Errors
Every error the API returns carries one envelope, whatever the route:
{
"error": {
"code": "not_found",
"message": "escrow esc_1234 not found",
"docsUrl": "https://quitanza.com/docs/errors.html#not_found"
}
}
The code is stable and machine-matchable; the message is for humans and may change; docsUrl points at the section below that explains the code. Match on the code, never on the message.
The codes
bad_request (HTTP 400)
The request body is malformed: missing required fields, invalid JSON, or values of the wrong shape. Fix the request; retrying unchanged will fail the same way.
unauthorized (HTTP 401)
The deployment requires Authorization: Bearer <api key> on /v1 routes and the header is missing or wrong.
forbidden (HTTP 403)
The operation is admin-only and this caller cannot perform it: the key is not the root key, or the deployment is an open sandbox with no API key configured. Issuer rotation and key management answer to the root key alone.
mandate_violation (HTTP 403)
The escrow would exceed the mandate the payer acts under: per-escrow cap, cumulative cap, asset allowlist, counterparty allowlist, or expiry. The mandate's usage is inspectable at GET /v1/mandates/{id}.
unauthorized_ruling (HTTP 403)
A dispute ruling lacked the required signatures: both parties (co-signature) or the named arbiter. Also returned for malformed split shares: shares that do not sum to 10000 basis points, are not integers, or appear on a non-split ruling. The platform never rules.
not_found (HTTP 404)
No such resource: an unknown id, or a route that does not exist.
invalid_state (HTTP 409)
The escrow cannot make that transition from its current state, e.g. delivering before funding, or disputing a settled matter. Fetch the escrow to see where it stands.
rate_limited (HTTP 429)
Too many requests in the current window. Back off and retry; idempotency keys make retries safe on create and fund.
payload_too_large (HTTP 413)
The request body exceeds the route's cap: 32 KB on the public POST /v1/verify (a quitanza is a few kilobytes), 1 MB elsewhere. Send the document itself, not an archive of them.
unprocessable (HTTP 422)
The request was well-formed but the operation could not proceed, e.g. a dispute opened by a key that is not a party.
custody_failed (HTTP 502)
Custody could not settle: the chain was unreachable or the transaction did not confirm. Nothing is lost: the settlement is journaled, the escrow carries custody.status: "settle-failed", a custody.failed event fired, and POST /v1/escrows/{id}/custody/retry resumes it. A quitanza is never issued without a confirmed settle.
x402 payment errors (HTTP 402)
The x402 handshake refuses a payment with the same envelope and one of these codes: malformed_header, version_mismatch, scheme_mismatch, wrong_resource, wrong_payee, wrong_asset, bad_signature. Each names exactly what disagreed between the offer and the signed payment authorization.
Retry guidance
| Code | Retry? |
|---|---|
bad_request, unprocessable, x402 codes |
No. Fix the request first |
unauthorized, forbidden |
No. Fix credentials or use a capable deployment |
mandate_violation, unauthorized_ruling |
No. Authority is missing, not luck |
invalid_state |
No. Re-read the escrow state |
not_found |
No, unless you created the resource a moment ago |
rate_limited |
Yes, after backing off |
payload_too_large |
No. Shrink the body |
custody_failed |
Yes, via the custody retry route |