Skip to main content
This page lists the errors the Embedded API returns, what each one means, and how to recover from it.

The error shape

Every error uses the same body:
There is no stable machine-readable error code yet. Branch on statusCode and, where you must distinguish two errors sharing a status, match on message. Treat message as unstable: log it, show it to your own operators, but do not parse it in a way that a wording change would break.

Validation errors return an array

When a request body fails validation, message is an array with one entry per invalid field:
Handle both shapes:

Errors by status

400 — Bad Request

401 — Unauthorized

403 — Forbidden

404 — Not Found

409 — Conflict

500 — Internal Server Error

A 500 here is usually an upstream error passed through unchanged rather than a fault in the proxy. The two you are most likely to meet both come from signature validation:
These are validation faults reported with a 500. Returning 400 for a malformed signature is tracked as platform work; until it lands, treat a 500 carrying one of the messages above as a client-side bug and fix the request rather than retrying it.

Failures that return success

The dangerous errors are the ones that do not look like errors. Each of these returns 2xx.

Employment data is dropped when the occupation does not resolve

You send an occupation as free text. The API matches it to an occupation code, and silently omits your employment data when no match is found. The call returns success. Nothing in the response says the data was dropped. Matching works as follows:
  1. The API searches occupations using your occupation string as the search term.
  2. It looks for an active occupation whose display name equals your string exactly, ignoring case and surrounding whitespace, or one of whose aliases does.
  3. If there is no exact match but the search returned exactly one active result, that one is used.
  4. Otherwise no code is resolved, and employment is not sent upstream.
So a title that returns several near-matches and matches none of them exactly — Financial Administrator is the recorded example — resolves to nothing and is discarded.
Do not send occupation as free text in production. Resolve the code yourself and send occupationCode, which is never silently dropped.
Pick the entry you want from the response and submit its code:
Then confirm it stuck, rather than trusting the 2xx:
If employment is absent or its occupationCode is null, the write did not land.

Card status transitions

The current status does not allow it means the card is not in a state that permits what you asked for. Retrying the same call cannot succeed — one recorded case retried four times over sixteen hours against an unchanged state. Through the Embedded API you can set exactly two statuses — BLOCKED to freeze and ACTIVE to unfreeze:
A card also carries issuer-set statuses you can only read, such as pending on a card that has never been activated. Attempting a transition the issuer does not permit from the card’s current state produces this error. Read the current status before you try a transition:
The full status list, the reason there is no published transition matrix, and the ACTIVE-does-not-mean-activate trap are covered in Card statuses.

A 404 does not always mean missing

requested item could not be found is an upstream message that covers two different situations, and the distinction matters when you are polling. The clearest case is the proposal signing payload. GET …/proposals/{proposalId}/sign-payload returns 404 until the proposal reaches PENDING_SIGNATURES. The proposal exists; it is simply not ready to be signed. So a 404 from sign-payload after you have just approved a proposal means wait and try again, not the proposal is gone. Confirm with GET …/proposals/{proposalId}: if that returns the proposal, keep polling sign-payload.

Retries and duplicates

There are no idempotency keys on the Embedded API today. When a request times out and you did not read a response, you cannot assume it failed. Create-user is the case that matters most, because a blind retry is what turns one intended user into two. It is protected by a uniqueness check on email, phone number, and employee identifier, so a retry of a create that already succeeded returns 409 naming the field that collided — not a second user. Treat that 409 as success from a previous attempt, not as a failure:
Wallet creation has no equivalent uniqueness guard, so a blind retry there can produce a second wallet. Before you retry a wallet create that timed out, list the account’s wallets and check whether the first attempt landed.
Retry only when that shows no wallet for the currency you were creating.
Idempotency keys on user and wallet creation are tracked as platform work. When they ship, this section will describe them and the read-before-retry workaround above becomes unnecessary.

Last reviewed: 7 August 2026.