error.code the specific condition, error.message a human-readable
explanation, and error.details structured context where it exists:
Match on
error.code, not message; messages are for humans and may be
reworded. The two flat Sandbox
probes are the only endpoints that don’t use this envelope.Money movement (
/fund, /mint, /transfer, /redeem) is asynchronous.
The HTTP codes below cover what can be checked in the request (input,
wallet, caps, public balances, configuration). Anything that goes wrong while
the background worker executes the operation does not produce an HTTP error at
all: the transaction becomes status: "FAILED" with error and errorCode
set. That catalog is in
Asynchronous failures below.400 Bad request
401 Unauthenticated
402 Payment required
403 Forbidden
404 Not found
409 Conflict
410 Gone
415 Unsupported media type
429 Too many requests
500 Internal error
502 Upstream failure
Two kinds of endpoint can return502: read endpoints that talk to the
confidential-rail relayer inline, and the two Aro Mail
calls that broadcast a transaction inline (POST /transfer/letter and
POST /transfer/letter/claim). The queued money-movement endpoints (/fund,
/mint, /transfer, /redeem) never do: on-chain and relayer problems during
execution become status: "FAILED" on the transaction (see the next section),
and transient ones are retried by the worker without surfacing.
For
escrow_unsettled and claim_unsettled, error.details carries { letterId, txHash } so a client can follow the letter with GET /transfer/letter/{id} instead of creating or claiming it again. Both mean the transaction was broadcast; only the bookkeeping is pending and reconciliation finishes it.503 Configuration
A503 naming an environment variable means the deployment is missing
required configuration. Platform-side; report the message text to your admin.
On money-movement endpoints these are checked before anything is queued,
so a 503 means no transaction row was created.
Asynchronous failures (transaction.errorCode)
Money-movement requests return 201 with a QUEUED transaction; a background
worker then executes it. When execution cannot proceed, the worker marks the
transaction FAILED and sets two fields:
error is human-readable and may be reworded; errorCode is the stable key.
Both are null on every non-FAILED transaction.
FAILED always means nothing moved on-chain for that row. A transaction
is failed only when a pre-flight check rejected it before anything was
broadcast, or when the on-chain call reverted (a revert moves no funds). A
broadcast transaction whose outcome is still unknown stays PENDING (or
SETTLING for a redeem payout) and keeps being tracked; it is never failed
underneath you.
Codes that no longer exist:
approval_timeout, operator_approval_timeout,
redeem_settlement_pending, and redeem_settlement_failed. A redeem payout
that cannot be sent yet keeps the row in SETTLING and is retried.