Errors and retries
The error envelope
Every error has the same shape:
json
{ "error": { "code": "not_found", "message": "no data for this object" } }Match on code, which is stable. message is for humans and may change.
| Status | code | Meaning |
|---|---|---|
400 | bad_request | Malformed JSON, an unknown field, or a failed validation. message says which. |
401 | unauthorized | Missing, invalid, expired or revoked credentials. See Authentication. |
402 | payment_required | The prepaid balance is empty. See Billing. |
403 | forbidden | The credential can't do this, e.g. a console-only action with an API key. |
404 | not_found | The object, signal, rule, endpoint or key doesn't exist. |
409 | conflict | The request conflicts with the current state, e.g. backfilling a disabled signal. |
422 | idempotency_key_reused | An Idempotency-Key was already used for a different object. |
429 | rate_limited | Too many requests. /v1 requests are limited per account (3,000 a minute by default), and so are concurrent wait: true analyses. Wait for Retry-After seconds. |
502 | internal_error, payment_provider_error | An upstream service (the analyzer, Stripe) failed. |
503 | analyzer_busy | The analyzer is throttling a wait: true request. The events were recorded; don't resend them. After Retry-After, request an analysis or read the answers later. |
503 | payments_not_configured, not_ready | A feature is unavailable on this deployment, or the service is starting. |
500 | internal_error | Something went wrong on our side. |
Retrying
- Safe to retry:
GET,PUTandDELETErequests, after a network error, a timeout, a429or a5xx. Back off exponentially with jitter. - Safe to retry with an idempotency key: event ingestion. Send an
Idempotency-Keyheader and retry with the same key; the events are recorded once. See Ingesting events. - Not safe to retry blindly: other
POSTrequests, and ingestion without anIdempotency-Key. A timeout doesn't tell you whether the events were recorded, and retrying may record them twice. - Never retry other
4xxerrors unchanged; fix the request.
The SDKs follow these rules: they retry idempotent requests twice by default, honor Retry-After, and never retry a POST.
Timeouts
Most requests answer in milliseconds. Direct moderation waits for the analyzer and can take seconds; give it a longer timeout. The server itself gives up on any request after 30 seconds.