ZZanoraDocs

Core concepts

The error envelope, what each error code means, whether any money moved, and what to do next. The page to keep open while you integrate.

The envelope

Every error from the gateway has the same shape:

JSON
{ "error": { "code": "POLICY_DENIED", "message": "denied by rule: price > 20", "details": { "matchedRule": "price > 20" } } }

Handle errors by code. The message is written for a person and can change between releases. An unexpected server error returns only "internal error" and an errorId. Quote the errorId when you ask for help.

Refusals while buying

These are the platform answering a purchase, not faults. In every row except the last, no money moved.

CodeHTTPMeansDo this
POLICY_DENIED403a workspace rule, the daily budget, or a missing allow rule said nodon't retry. Pick another capability, or change the policy
APPROVAL_REQUIRED403a rule needs a person; the response has an approvalIdstop and report the id. A person approves in the console, then retry once
APPROVAL_DENIEDa person refused this spend (MCP tools)don't retry, and don't ask again
PRICE_ABOVE_CLIENT_LIMITthe price is above your own maxPriceMinor. Your client refused before signingraise your ceiling, or pick something cheaper
INSUFFICIENT_FUNDS402the wallet's available balance is below the pricestop, and fund the wallet
WALLET_FROZEN403the wallet is frozenunfreeze it (POST /v1/wallets/:id/unfreeze)
WALLET_PROVIDER_PAUSED429three seller failures in a row (5xx, thrown handler, MCP isError or timeout) paused them for this wallet. 4xx responses don't countwait, or lift the pause
CHALLENGE_EXPIRED410the signed price quote expired before paymentcall again. The SDKs do this for you
REPLAY_DETECTED409this payment proof was already usednothing: the first use counted. Don't resend proofs
CANCELLEDyou aborted before the payment proof was sentretry freely. Nothing was charged, and the SDK can only promise that for this code
a failed receipt200you paid, the seller's handler failed, and you were refundedthe refund is a new ledger entry. Consider rating the seller

Cancelling after payment

Once the payment proof has been sent, cancelling no longer stops the purchase. The seller is already running, and dropping the connection would only throw away an answer you paid for. The call completes and appears in your purchase history.

Errors while integrating

CodeHTTPUsually
VALIDATION_FAILED400an amount sent as a number instead of a string, a missing required field, or an unknown enum value. The message names the field
UNAUTHORIZED401a missing, expired, revoked or mistyped key. Run GET /v1/whoami
FORBIDDEN403the key is missing a scope (the message names it), or the record isn't yours
NOT_FOUND, CAPABILITY_NOT_FOUND, PROVIDER_NOT_FOUND, WALLET_NOT_FOUND404a wrong id, or one owned by another tenant
NOT_SUPPORTED501this deployment has no rail for that request, e.g. card top-ups without a card processor. Ask GET /v1/rail/providers first
INSECURE_TRANSPORT403the request reached the gateway over plain HTTP. Use https://
RATE_LIMITED429too many requests for this key. Wait for the retry-after header

Errors about money moving in or out

CodeHTTPMeans
DEPOSIT_HELD409a USDC deposit arrived while USDC was outside ±0.5% of $1. It's held, not credited at a guessed rate, and is retried automatically
DESTINATION_COOLING_DOWN409the payout destination changed less than 24 hours ago. Payouts resume on their own after that
SANCTIONED_ADDRESS403sanctions screening blocked the payout destination
TREASURY_UNAVAILABLE503a pricing or screening service is down, so the payout is paused rather than guessed. Retry later
COVERAGE_SHORTFALL503payouts are paused while the platform reconciles its holdings. Retry later
DUPLICATE_EXTERNAL_REF409this deposit was already credited. Duplicates are ignored