Skip to main content
Every error — validation, authentication, business rule, or unexpected — returns the same shape. You never have to branch on the response format.
Branch on code, never on message. Messages are wording and may be reworded at any time; codes are part of the contract and only change with a version bump.

Status codes

Retry matrix

Retry the left column with backoff, reusing the same Idempotency-Key. The right column needs the request or your configuration to change first — a retry loop on a 422 is just a slower failure.

Every code

Authentication and authorisation

Idempotency

Payouts

Rates and quotes

Beneficiary lookup

Settlement and refunds

Webhooks

Platform

Not every code you will see is an API error code. DISPATCH_ERROR and similar values appear as failure_code on an outflow or a refund record — they describe why an attempt failed downstream, and never come back as the code of an HTTP error response.
PAYMENT_INSTRUCTION_NOT_FOUND is the one 404 that is routinely not an error. Instructions are generated asynchronously, so for a few seconds after creating a payout there genuinely is not one yet. Wait for payout.pending_payment rather than treating it as a failure.

Tracing a request

Send an X-Request-Id and it is echoed in the response and into every log line and error we record. Generate one per attempt and log it next to your own record.
If you do not send one, request_id is reported as unknown — which makes a support request considerably harder to answer.
Use a fresh X-Request-Id per attempt and a stable Idempotency-Key across attempts of the same operation. They serve opposite purposes: one identifies this HTTP call, the other identifies the business operation behind it.

Handling errors well

Log code and request_id on every failure. Those two fields are what turn a support conversation into a lookup.