Error codes
Every real error code AbaPay's rails can return, pulled straight from the route handlers — not a curated happy-path subset. If something failed, it's one of these.
HTTP status codes
| Status | Meaning | Where |
|---|---|---|
200 | Settled, or a JSON-RPC-framed result (MCP/A2A always return 200 at the transport level, even for a tool-level error — see the JSON-RPC table below). | REST, MCP, A2A |
402 | Payment Required — a genuine x402 challenge, or a signed authorization that failed verification (see x402 error codes below). | x402 / REST |
401 | No credential at all (missing api_key and no OAuth token) — carries a WWW-Authenticate header pointing at the OAuth flow. | MCP |
409 | This exact payment is already locked/being processed — don't retry, it's not a fresh failure. | x402 / REST |
429 | Rate limited — 60/min per-IP on the whole MCP/A2A surface, and separately per-credential on money-moving calls (pay_bill 10/min, schedule_bill 5/min, pay_bill_batch 5/min). Carries a Retry-After header. | MCP, A2A |
500 | Server-side failure unrelated to the caller's request (token not configured, vault misconfigured, or an unhandled exception). | x402 / REST |
x402 challenge / settlement errors
Carried in the 402 response body as errorCode, alongside a human-readable error string and a retryable flag — check retryable before deciding whether to sign a fresh authorization and try again.
| Code | Retryable | Meaning |
|---|---|---|
MALFORMED_AUTHORIZATION | No | The signed authorization was incomplete or its numbers unreadable — a client-side bug in how it was built, not a transient issue. |
WRONG_RECIPIENT | No | The authorization named a different payTo than this specific payment's challenge — stale or reused authorization. |
NOT_YET_VALID | No | validAfter is in the future relative to the server's clock — usually the caller's device clock is off. Fix the clock, then retry. |
AUTHORIZATION_EXPIRED | Yes | validBefore already passed. Sign a fresh authorization against a fresh challenge and retry. |
AMOUNT_MISMATCH | No | The signed value doesn't match this bill's required amount — the challenge and the signature disagree on price. |
Malformed X-PAYMENT header | No | The X-PAYMENT header wasn't valid base64-encoded JSON in the expected shape. |
Facilitator error (<http status>) | Yes | Celo's x402 facilitator itself returned a non-success status while settling. Not AbaPay's failure — safe to retry. |
Facilitator temporarily unavailable | Yes | The facilitator couldn't be reached at all. Retry with backoff. |
Settlement status (200 response body)
The status field on a settled x402/REST response — a 200 HTTP status doesn't always mean the money-to-bill leg finished cleanly.
| Status | Meaning |
|---|---|
SUCCESS | Bill vended, or reliably queued for background delivery. |
FAILED_VENDING | Payment settled on-chain, but the underlying bill purchase (VTpass) failed — enters the automatic on-chain refund flow. See the Custody chapter in the handbook. |
TIMEOUT | This exact payment was already being processed when the request landed — a duplicate submission, not a fresh failure. Don't resubmit. |
SYSTEM_CRASH | An unhandled exception during settlement. Treat as pending, not failed — check transaction_history / the receipt before assuming nothing happened. |
MCP / A2A JSON-RPC error codes
Standard JSON-RPC 2.0 codes (spec §8) plus AbaPay-specific ones. A tool-level error (e.g. a wrong PIN) comes back as normal result text, not one of these — these are transport/protocol-level failures.
| Code | Meaning |
|---|---|
-32700 | Parse error — the request body wasn't valid JSON. |
-32600 | Invalid Request — missing/malformed jsonrpc, method, or id. |
-32601 | Method not found. |
-32602 | Invalid params — a required field was missing or the wrong type. Check the tool's parameter table on the MCP or A2A page. |
-32603 | Internal error, unrelated to the request itself. |
-32001 | Unauthorized — no valid credential. Carries a WWW-Authenticate pointer to start OAuth. |
-32004 | Unsupported operation (A2A spec §8). |
Invalid or revoked API keys return the same plain-text message regardless of which tool was called: "Invalid or revoked API key. Create a new one in the AbaPay app under Agent Hub → MCP."