Error codes
Contract §7. Section numbers are contract-wide and never change; the contract overview maps every section to its page.
Conventions — authentication, the response envelope, idempotency, retry safety, pagination, rate limits — are defined in the Partner Integration Guide and apply to every endpoint here.
These are the codes this contract adds on top of the platform codes in
guide §7. error.code on the wire is the name in the first
column — never the composed E_CPX_… form.
Retry safety is decided by the code, never by the status class. There are two retryable
409s in this list and several 502s that must never be retried; a client that branches on
5xx or on 409 will get one of them wrong. Where a row says do not retry, that is not
caution — it is a call that costs money or creates a duplicate resource if repeated.
Dispute codes live with the endpoints that raise them, in §8 — that section was appended after this one and is deliberately not folded in here, because renumbering a published contract breaks every reference a partner has already written down.
Clients, KYB and UBOs
| Code | HTTP | What it means, and what you do |
|---|---|---|
CLIENT_NOT_FOUND | 404 | No such client for your account — a foreign or mistyped id is indistinguishable from a nonexistent one. Also answers a client_id on a list route that names no client of yours. |
CLIENT_NOT_APPROVED | 409 | The client is not APPROVED yet — e.g. creating a cardholder under a pending one. Poll the client's status; do not retry on a timer alone. |
EXTERNAL_REF_TAKEN | 409 | That externalRef already belongs to one of your clients. Pick another. |
CLIENT_KIND_UNSUPPORTED | 501 | kind: INDIVIDUAL before its announced availability. |
APPLICATION_REJECTED | 422 | The issuer refused the client application. |
INVALID_DOCUMENT_TYPE | 422 | The type is not in the enum for that upload target. |
DOCUMENT_QUALITY_REJECTED · DOCUMENT_REJECTED · DOCUMENT_INCOMPLETE | 422 | Actionable issuer document rejections. The raw issuer tags are in error.params.tags — surface them, they say what to re-upload. |
DOCUMENT_TOO_LARGE | 413 | The upload exceeds 20 MB. |
UBO_NOT_FOUND | 404 | No such UBO under that client. |
UBO_REJECTED | 422 | The issuer refused the UBO. |
UBO_SIDE_NOT_ALLOWED | 422 | side was sent with a PASSPORT upload, which has one side. |
Cardholders and cards
| Code | HTTP | What it means, and what you do |
|---|---|---|
CARDHOLDER_NOT_FOUND · CARD_NOT_FOUND | 404 | Same uniform 404 as clients: no such resource for your account. |
CARDHOLDER_NOT_APPROVED | 409 | Issuing a card for a cardholder whose KYC is not APPROVED. Rolling out — until it lands, the same condition answers 422 CARD_REJECTED. |
CARDHOLDER_REJECTED · CARD_REJECTED | 422 | The issuer refused the create. Check the submitted details. |
SHIPPING_NOT_APPLICABLE | 422 | shipping was sent on a VIRTUAL card, which delivers nothing. |
REPLACE_NOT_APPLICABLE | 422 | replace was attempted on a PHYSICAL card. Cancel it and issue a new one. |
CARD_TERMINAL | 409 | Freeze, unfreeze, limit, replace or reveal on a CANCELED card. Not retryable — this is one of the 409s that never clears. |
OPERATION_IN_FLIGHT | 409 | Another attempt on this key, or on this card's replace scope, is already live. Ordinarily wait and retry with the same key — but after a 502 on replace it is permanent, see §3. |
CARD_UNRECORDED | 502 | The issuer created the card and the service could not record it. Do not retry — a retry creates a second card with a second PAN, billable and invisible to you. The card is in no list and resolves from no id; contact support with the request id. The opposite remedy to PROVIDER_AMBIGUOUS. |
Transactions
| Code | HTTP | What it means, and what you do |
|---|---|---|
TRANSACTION_NOT_FOUND | 404 | No such transaction, or one belonging to another partner. |
FILTER_NOT_APPLICABLE | 422 | card_id was combined with a type that carries no card. |
Card secrets and PIN
| Code | HTTP | What it means, and what you do |
|---|---|---|
SESSION_INVALID | 422 | Malformed or expired sessionId on a secrets endpoint. Open a new session. |
REVEAL_RATE_LIMITED | 429 | The per-card reveal ceiling. Retry after the window. |
PIN_WRITE_UNCONFIRMED | 502 | A PIN write whose outcome is unknown. Read it back rather than rewriting blindly. |
Funding
| Code | HTTP | What it means, and what you do |
|---|---|---|
FUNDING_NOT_READY | 409 | The funding contract is still provisioning. Retry later — and contact support if it persists for hours, because some causes need service-side action. |
FUNDING_AMBIGUOUS | 409 | More than one funding contract is registered. Contact support; do not guess. |
FUNDING_UPSTREAM_UNAVAILABLE | 502 | The funding read failed upstream. Retry with backoff. |
FUNDING_READ_FAILED | 502 | The issuer answered something the read cannot honestly relay. |
FUNDING_RATE_LIMITED | 429 | The funding-read budget is exhausted. Retry after the window. |
Withdrawal authorization
| Code | HTTP | What it means, and what you do |
|---|---|---|
WITHDRAWAL_ADMIN_INVALID | 422 | The admin you sent is not an admin of this client's collateral contract. Your fault, and the fix is the wallet, not the amount — read GET /clients/:id/collateral-contract for the current list. The service checks this before calling the issuer, deliberately: a wrong wallet would otherwise hold your client's one-at-a-time authorization slot for its full lifetime. |
WITHDRAWAL_TOKEN_UNSUPPORTED | 422 | The token is not one this client's contract holds collateral in. Take it from GET /clients/:id/collateral-contract. |
WITHDRAWAL_AMOUNT_INVALID | 422 | amount has more fraction digits than the token's decimals can represent. The token is fine, the amount is not. It is never rounded — this value is what the issuer signs. |
SPENDING_POWER_INSUFFICIENT | 422 | The contract holds less of that token than you asked for; lower the amount. This is the collateral balance, not the USD spendingPower on the funding read — different quantities. |
WITHDRAWAL_AUTH_CONFLICT | 409 | A different authorization is already active for this client. Not retry-safe as-is — wait for the live one to expire, then request again. An identical repeat never reaches this code (it returns the same authorization), so meeting it means something in your request changed. |
WITHDRAWAL_AUTH_NOT_READY | 409 | The issuer will not sign yet. Measured cause: a short cool-down that runs after the previous authorization expires — about 40 seconds — so a client requesting one authorization straight after another meets this routinely. Nothing of yours is in the way; retry shortly. |
WITHDRAWAL_RATE_LIMITED | 429 | Retry after the window. |
WITHDRAWAL_UPSTREAM_UNAVAILABLE | 502 | The issuer timed out or was unavailable. Nothing was signed, so this is safe to retry with backoff. |
WITHDRAWAL_FAILED | 502 | The issuer answered something the authorization cannot honestly relay. Do not retry blindly — contact support with the request id. |
Webhooks and events
| Code | HTTP | What it means, and what you do |
|---|---|---|
INVALID_CURSOR | 400 | ?since= was not a non-negative integer. It is not an evt_… id. |
EVENT_NOT_FOUND | 404 | No such event, or one belonging to another partner. |
RESEND_NOT_POSSIBLE | 400 | A resend is already queued, or the event cannot be attributed. |
EVENT_NOT_READABLE | 409 | Temporary, on the service's side. The event exists and is not lost; its stored payload cannot be opened right now. Retry with backoff — one of only two retryable 409s (see guide §7). Deliberately not a 404, which would say it is gone. |
ENDPOINT_URL_REJECTED | 400 | Not HTTPS, or not a publicly routable host. |
ENDPOINT_LIMIT_REACHED | 409 | You already have an active endpoint. |
ENDPOINT_URL_ALREADY_REGISTERED | 409 | You already have a non-deleted endpoint on that URL — possibly a PAUSED one. |
ENDPOINT_NOT_FOUND | 404 | No such endpoint. |
ENDPOINT_STATE_INVALID | 400 | A lifecycle transition that does not exist. |
Issuer relay — any endpoint
| Code | HTTP | What it means, and what you do |
|---|---|---|
PROVIDER_UNAVAILABLE | 502 | The issuer is unreachable, or refused before acting. Retry with backoff. |
PROVIDER_RATE_LIMITED | 429 | The issuer rate-limited the call. Retry after a short wait. |