02 · CONCEPTS
Errors
Every non-2xx response has exactly one shape. Codes tell your agent what to do next — most of them are not “try again.”
Error envelope
{
"error": {
"code": "insufficient_credits",
"message": "available credits below the maximum cost of this call",
"request_id": "…", // when a request was created
"details": { } // code-specific context
}
}1
Codes & the retry matrix
| Code | HTTP | Retry? | What to do |
|---|---|---|---|
| unauthorized | 401 | no | Missing or revoked key. Create one in the console. |
| forbidden | 403 | no | Key lacks the required scope, or the workspace needs review for external actions. |
| confirmation_required | 403 | after approval | A human must approve this action in the console. Get a fresh preview, have them approve, retry with the token. |
| insufficient_credits | 402 | after top-up | Top up in the console. Quote tokens survive this — no need to re-quote. |
| rate_limited | 429 | yes, backoff | 300 requests/min per key. Back off and retry. |
| idempotency_conflict | 409 | no | Same Idempotency-Key, different parameters. Use a new key for a new request. |
| invalid_request | 400 | no | Schema/validation failure — the message says which field. |
| suppressed_recipient | 422 | no | Recipient is suppressed. This is permanent and by design. |
| not_found | 404 | no | Wrong id, or it belongs to another workspace. |
| operation_unknown_state | 409 | poll, don't retry | External outcome is ambiguous and being reconciled. Poll the request/operation; never blind-retry a purchase or launch. |
| provider_unavailable | 503 | yes, later | Every route exhausted. Nothing was charged. Retry with the same Idempotency-Key. |
| internal | 500 | yes, later | Our fault. The request_id helps support trace it. |
🔁 Retrying safely: reuse the same Idempotency-Key and you can never be double-charged — a completed request replays its original result; an in-flight one returns 202 in_progress.