Status codes

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 404

All 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

CodeNameWhen it is returned
200OKThe 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.
201CreatedA 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.
202AcceptedThe 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.
204No ContentThe 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

CodeNameWhen it is returnedHow to handle
400Bad RequestThe 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.
401UnauthorizedThe 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.
403ForbiddenThe 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.
404Not FoundThe 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.
405Method Not AllowedThe HTTP method is not supported on the path (for example PUT /v1/payees/{id}).Use the method documented for the endpoint.
409ConflictThe 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.
415Unsupported Media TypeThe Content-Type is not application/json.Send Content-Type: application/json.
422Unprocessable EntityThe 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.
429Too Many RequestsYou have exceeded the rate limit.Wait for the interval indicated by the Retry-After header, then retry with exponential backoff.
500Internal Server ErrorSomething 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.
503Service UnavailableThe 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."
  ]
}
FieldTypeDescription
titlestringThe HTTP reason phrase for the status, for example Not Found.
statusintegerThe HTTP status code, repeated in the body.
detailstring, optionalThe error message, present only when there is exactly one error.
errorsarray of stringsEvery 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

CodeSafe to retry?
400, 403, 404, 405, 415, 422No. The same request will fail again until something changes.
409No. The operation already exists. On a money-moving retry this is your answer: read existingPaymentId from the body.
401Yes, after refreshing the token and DPoP proof.
429Yes, after Retry-After.
500, 503, timeouts, connection errorsYes, with exponential backoff. Reuse the same idempotencyKey on money-moving requests.