Errors
Every API error uses one JSON envelope. The HTTP status tells you the class of failure; the
code tells you what to do. Do not branch on the human-readable message.
Code
requestId is also returned in X-Request-Id. Include it in a support request. Never
include the API secret, LPA text, QR data or customer records.
Status classes
| Status | Meaning | Retry? |
|---|---|---|
| 400 | Malformed request or unsupported value | Fix the request first. |
| 401 | Missing, invalid, expired or replayed credential | Fix authentication. Do not retry unchanged. |
| 402 | Wallet cannot cover the order | Fund the wallet or reduce the order. |
| 403 | Scope, allowlist, account or agent restriction | Fix authority. Do not retry unchanged. |
| 404 | Object absent or not owned by this partner | Confirm the id and environment. |
| 405 | Method not allowed on this path | Use the documented method. |
| 409 | Stock, price, quote, redemption or idempotency conflict | Re-read state before retrying. |
| 413 | Request body too large | Reduce the body. |
| 429 | Per-minute limit or daily quota exhausted | Wait Retry-After. |
| 500 | Unexpected server failure | Confirm no effect, then retry an idempotent mutation with the same key. |
| 501 | Capability deliberately gated | Do not retry. Use a supported path. |
| 503 | Dependency unavailable (FX, payment provider) | Retry later with backoff. |
Error codes
| HTTP | Code | Meaning | Safe action |
|---|---|---|---|
| 400 | validation_error | Missing or malformed input | Correct the body, query or header. |
| 401 | missing_signature | One or more signing headers absent | Send all four signing headers. |
| 401 | unauthorized | Unknown, revoked or wrong-environment key | Check the API ID and environment. |
| 401 | signature_invalid | HMAC mismatch | Recompute over the exact path and raw body. |
| 401 | request_expired | Timestamp outside five minutes | Sync the clock and use a fresh timestamp. |
| 401 | replayed | Nonce already used | Generate a fresh nonce. |
| 401 | key_expired | Key passed its expiry | Rotate or issue a new key. |
| 401 | agent_inactive | Agent suspended, revoked or expired | Ask the owner to reactivate or reissue. |
| 402 | insufficient_funds | Available wallet credit is below the total | Fund the wallet or reduce the order. |
| 402 | payment_required | Target payment envelope with a funding URL | Surface the funding URL to the principal. Planned. |
| 403 | forbidden | Key lacks the required scope, or the agent tried a principal-only action | Request the scope or use a principal key. |
| 403 | ip_not_allowed | Source IP is outside the key allowlist | Use an allowed egress address. |
| 403 | account_not_active | Account review is incomplete | Finish onboarding before ordering. |
| 404 | order_not_found | Purchase absent or not owned | Check the purchase id and environment. |
| 404 | quote_not_found | Quote absent, closed or not owned | Create a new quote. |
| 404 | agent_not_found | Agent absent or not owned | Check the agent id. |
| 404 | key_not_found | Key absent or not owned | Check the key id. |
| 404 | error_not_found | Error group absent | Check the error group id. |
| 405 | method_not_allowed | Wrong method | Use the documented method. |
| 409 | out_of_stock | No sellable stock for at least one offer | Refresh the catalogue or reduce quantity. |
| 409 | price_changed | Quote no longer matches the current price | Re-quote or retry the one-call order with a fresh expected total. |
| 409 | quote_expired | Quote lifetime ended | Create a new quote. |
| 409 | not_redeemable | Purchase not fulfilled or no credentials | Poll the purchase before redeeming. |
| 409 | idempotency_conflict | Key already used for a different or paid operation | Reuse the original request or use a new key for a new operation. |
| 409 | approval_required | Order exceeds an approval threshold | Stop and request human approval. No charge is made. |
| 413 | validation_error | Stripe receiver payload over 256 KB | Reduce the payload. |
| 429 | rate_limited | Per-minute or burst limit exceeded | Wait Retry-After, then retry with jitter. |
| 429 | quota_exceeded | Daily quota exhausted | Wait for the UTC reset or use another call class. |
| 500 | internal_error | Unexpected failure | Confirm no effect, then retry with the same idempotency key. |
| 501 | capability_unavailable | Feature is gated | Do not retry. Use a supported path. |
| 503 | fx_unavailable | EUR or GBP rate missing or stale | Retry later or use USD. |
| 503 | payment_pending | Stripe is not configured | Funding is unavailable. Do not retry. |
approval_required and payment_required are part of the target agent contract and are
not returned by every deployment yet. Handle them if you receive them, and handle the current
402 insufficient_funds shape as well.
Retry rules
Reads
Retry 429, 500 and 503 with exponential backoff and jitter. Use a fresh nonce
for every attempt. A read is safe to repeat.
Mutations
Order, redeem and funding calls are idempotent only when you reuse the same
Idempotency-Key and the same body. A new key creates a new logical operation.
| Situation | Action |
|---|---|
402 insufficient_funds | Do not retry. Fund the wallet. |
402 payment_required | Do not retry. Surface funding_url. |
409 price_changed | Re-quote or retry one-call with the returned total and a new decision. |
409 quote_expired | Create a new quote. |
409 idempotency_conflict | Resolve the original operation. Do not generate a new key to bypass it. |
429 | Wait Retry-After, then retry with the same key. |
500 | Poll the purchase or wallet first, then retry with the same key. |
503 payment_pending | Do not retry. Funding is not configured. |
Unknown outcomes
If a timeout or connection reset leaves the outcome unknown, do not create a second order. Call
GET /v1/orders/{purchaseId} if you have the id, or GET /v1/orders to find the
reference. Only create a new attempt after confirming the original did not exist.
What never appears in an error
- The API secret or any part of it.
- LPA strings or QR payloads.
- Upstream store, product or cost identifiers.
- Customer personal data.
- Stack traces or internal SQL.
Support
Send the X-Request-Id, UTC time, method, path, status and error code to
[email protected]. For a suspected credential leak, use
[email protected] and revoke the key first.