Errors

Errors

API errors use standard HTTP status codes. Application-level failures also carry a stable errorCode string so you can branch on the cause programmatically instead of parsing messages.

Response format

A failed request returns the matching HTTP status (400, 401, 404) with this body:

{
  "message": "Session expired",
  "errorCode": "SESSION_EXPIRED",
  "error": "Bad Request"
}

Branch on errorCode, not message. Messages are human-readable and may be reworded; errorCode values are stable.

Session

errorCodeHTTPWhen
SESSION_NOT_FOUND404The sid doesn't exist.
SESSION_EXPIRED400The session passed its TTL. Create a new session.
SESSION_NOT_OPEN400The session was cancelled and can no longer be used.

Withdrawals

A withdrawal is approved by your approval webhook (WITHDRAW_REQUEST). To decline one, return an error with a numeric code — it maps to the errorCode the widget surfaces to the user, all as HTTP 400:

Your numeric codeerrorCodeMeaning
1WITHDRAW_DECLINEDGeneric decline (also the default if no code is given).
2INSUFFICIENT_BALANCEUser lacks the balance for this amount.
3WITHDRAW_UNAVAILABLEWithdrawals temporarily unavailable.
4USER_NOT_ELIGIBLEUser not permitted to withdraw.
5DAILY_LIMIT_EXCEEDEDUser hit their daily limit.
6WITHDRAW_AMOUNT_TOO_LOWBelow your minimum.
7WITHDRAW_AMOUNT_TOO_HIGHAbove your maximum.
8ACCOUNT_VERIFICATION_REQUIREDUser must complete verification first.
9WITHDRAW_SUSPENDEDWithdrawals suspended for this user.

The API also returns one withdrawal error on its own, as HTTP 400:

errorCodeWhen
WITHDRAW_IN_PROGRESSA withdrawal for this session is already PENDING/PROCESSING. Wait for it to finish.

Headless withdrawals

Errors specific to the headless (widgetless) flow. Scope is EVM / ERC-20 only — non-EVM/native/Tron inputs and unsupported chains/tokens are rejected at intent creation or execute.

errorCodeHTTPWhen
HEADLESS_NOT_ENABLED403Headless is not enabled for your operator. (Deliberately generic — it does not reveal whether an intent exists.)
OPERATOR_REFERENCE_REQUIRED400POST /session/withdraw with executionMode:"HEADLESS" omitted a non-empty operatorReference.
HEADLESS_INVALID_RECIPIENT400Intent creation received the zero address. A malformed or non-EVM address instead fails request validation with HTTP 400 and no stable errorCode.
HEADLESS_UNSUPPORTED_CHAIN400 / 409400 at intent creation for an unsupported, inactive, or Tron chain; 409 at execute if the locked chain is no longer supported.
HEADLESS_UNSUPPORTED_TOKEN400 / 409400 at intent creation for a native, inactive, or unregistered token; 409 at execute if the locked token is no longer supported.
OPERATOR_REFERENCE_CONFLICT409You reused an operatorReference with a different immutable payload. The same reference + same payload is idempotent and returns the original intent.
HEADLESS_INTENT_NOT_EXECUTABLE409Execute was called after the intent expired or was cancelled, or for a non-CREATED intent that has no existing reservation. A replay of an already-reserved intent returns its existing result instead.
INSUFFICIENT_LIQUIDITY409The shared Bankroll balance minus active reservations cannot fund this payout.
HEADLESS_CANCEL_NOT_ALLOWED409Cancel was attempted after broadcast uncertainty began, after a tx hash exists, or on a terminal intent. It can also mean concurrent resolution; read status and retry only if the intent is still cancellable.
HEADLESS_RETRY_NOT_ALLOWED409Admin retry was called on a request that is not safely retryable (not WAITING_FOR_GAS / FAILED(retryable), terminal, or a tx hash already exists).
HEADLESS_RETRY_IN_PROGRESS409A settlement worker already holds this request's job — a retry cannot pull it forward.
PRICE_UNAVAILABLE503Execute could not resolve a fresh price; no reservation or job was created.
BALANCE_UNAVAILABLE503Execute could not read Bankroll capacity; no reservation or job was created.

The execute call fails closed rather than guessing when it cannot price or read availability — it returns HTTP 503 and reserves/queues nothing. Retry a 503 only once price/capacity is available again. Create and execute are idempotent only for the same immutable intent: reuse the same operatorReference and payload for create, and the same sessionRef for execute. Treat 409 as a state/configuration signal rather than blindly retrying it; inspect status or correct the underlying input first. HEADLESS_RETRY_* is the dashboard-admin recovery plane, not an operator-key endpoint.

Transaction limits

errorCodeHTTPWhen
AMOUNT_BELOW_MINIMUM400Amount under the configured minimum for the operation.
AMOUNT_ABOVE_MAXIMUM400Amount over the configured maximum for the operation.

Authentication

HTTPWhen
401Missing or invalid Authorization: Bearer <OPERATOR_SECRET_KEY> on an operator endpoint.