The Client API uses conventional HTTP status codes to indicate the outcome of a request. Codes in the 2xx range indicate success, codes in the 4xx range indicate a problem with the request that you can correct, and codes in the 5xx range indicate a problem on our side.
Ownership and 404All resources are scoped to your client. A resource that belongs to another client is never visible to you and returns
404, exactly as if it did not exist.
Success codes
| Code | Name | When it is returned |
|---|---|---|
200 | OK | The request succeeded. Returned by reads, and by POST /v1/outbound-payments, POST /v1/internal-payments and POST /v1/fx/trades when an identical retry replays the original resource. |
201 | Created | A resource was created. What comes back differs per endpoint. Full resource and a Location header: POST /v1/payees, POST /v1/account-name-verifications. Id only, with a Location header: POST /v1/fx/trades. Id only, no Location: POST /v1/outbound-payments, POST /v1/internal-payments. Full resource, no Location (a quote has no URL of its own): POST /v1/fx/quotes. |
202 | Accepted | The request was accepted and is being processed asynchronously. Returned by the sandbox-only POST /v1/simulations/inbound-payments; the credit appears in your transactions shortly after. |
204 | No Content | The request succeeded and there is nothing to return. Returned by DELETE /v1/payees/{id}, POST /v1/outbound-payments/{id}/cancel and the sandbox-only POST /v1/simulations/fx-trades/{id}/reject. |
Error codes
| Code | Name | When it is returned | How to handle |
|---|---|---|---|
400 | Bad Request | The request is malformed or a parameter is invalid: unparseable JSON, a missing required field, a value outside its allowed range (for example pageSize above 200), or a badly formatted id. It also covers field-level rules, for example accountNameVerificationId supplied for a payee that is not a GB sort-code payee, or a value longer than the maximum allowed on POST /v1/account-name-verifications (accountHolderName 140, sortCode 50, accountNumber 50). | Fix the request. Do not retry unchanged. |
401 | Unauthorized | The access token is missing, invalid or expired, or the DPoP proof is missing or does not match the request. | Fetch a new access token, rebuild the DPoP proof for the exact method and URL, and retry. |
403 | Forbidden | The token is valid but lacks a scope granting the operation (detail starts with insufficient_scope and names the scope(s) to request), or your client is not active. | Request the missing scope through your account manager, then fetch a new token. Do not retry with the same token. |
404 | Not Found | The resource does not exist, has been deleted, or belongs to another client. Also returned by sandbox-only endpoints outside the sandbox. Note that an unsigned POST to a path that does not exist under /v1 is rejected by request-signature verification first ( 400 Request signature verification failed: missing_content_digest), not with 404. If you see that error on a request you did not expect to sign, check the path. | Check the id. If you received the id from us, the resource may have been deleted. |
405 | Method Not Allowed | The HTTP method is not supported on the path (for example PUT /v1/payees/{id}). | Use the method documented for the endpoint. |
409 | Conflict | The request conflicts with existing state: a reused idempotencyKey (the body's existingPaymentId identifies the payment already created under it), a byte-identical duplicate payment under a new key, a payee with the same account and bank details, or an FX internalReference reused with different details. | On a money-moving retry this is the expected duplicate signal. See the Idempotency page. Otherwise use the existing resource. |
415 | Unsupported Media Type | The Content-Type is not application/json. | Send Content-Type: application/json. |
422 | Unprocessable Entity | The request is well formed but a business rule rejects it: an expired or already-executed quote, a payment that is no longer cancellable, a rail unsupported for the payee or account, a valueDate outside the earliest-available/max-future window, a chargeType on a non-Swift rail, or an incomplete ultimate debtor set. Insufficient balance is a 422 on POST /v1/internal-payments only. An outbound payment short of funds is accepted and parks at AwaitingFunds. | Read detail/errors in the response, correct the underlying condition, and retry. Retrying unchanged will fail again. |
429 | Too Many Requests | You have exceeded the rate limit. | Wait for the interval indicated by the Retry-After header, then retry with exponential backoff. |
500 | Internal Server Error | Something failed on our side. The request may or may not have been processed. POST /v1/payees returns it when the payee was created but could not be read back. | Retry with backoff. For money-moving requests, always retry with the same idempotencyKey so a duplicate cannot be created. |
503 | Service Unavailable | The service is temporarily unavailable, for example during maintenance. GET /v1/payees/{id} also returns it when the payee has a Confirmation of Payee result but the account name verification service cannot be reached. | Retry with backoff, honouring Retry-After when present. |
Error response format
All error responses share one problem document format, with Content-Type: application/problem+json:
{
"title": "Unprocessable Entity",
"status": 422,
"errors": [
"Insufficient balance on the selected account."
]
}| Field | Type | Description |
|---|---|---|
title | string | The HTTP reason phrase for the status, for example Not Found. |
status | integer | The HTTP status code, repeated in the body. |
detail | string, optional | The error message, present only when there is exactly one error. |
errors | array of strings | Every error message; always present, with at least one entry. |
The 409 bodies of POST /v1/outbound-payments and POST /v1/internal-payments carry these fields plus existingPaymentId / existingInternalPaymentId (see the Idempotency page). A 400 for a body that cannot be read names the field, for example Missing required properties: accountType. or amount has an invalid value.
Which codes to retry
| Code | Safe to retry? |
|---|---|
400, 403, 404, 405, 415, 422 | No. The same request will fail again until something changes. |
409 | No. The operation already exists. On a money-moving retry this is your answer: read existingPaymentId from the body. |
401 | Yes, after refreshing the token and DPoP proof. |
429 | Yes, after Retry-After. |
500, 503, timeouts, connection errors | Yes, with exponential backoff. Reuse the same idempotencyKey on money-moving requests. |