Shape
Every error response is a single JSON object:error is stable — safe to switch on in your code. reason is advisory — surface it in logs / alerts, don’t parse it.
Status codes
| Status | error | When |
|---|---|---|
| 400 | invalid_json | Body isn’t valid JSON. |
| 400 | invalid_body | Body is valid JSON but didn’t match the endpoint’s schema. reason explains which field. |
| 401 | unauthenticated | Missing or malformed Authorization: Bearer ... header. |
| 401 | invalid_key | Key is revoked, unknown, or doesn’t exist in our records. |
| 403 | forbidden | Key is valid but lacks the required scope. reason says which scope. |
| 404 | not_found | The requested entity exists for no org you have access to. |
| 429 | rate_limited | See Rate limits. Includes retry_after_seconds. |
| 5xx | various | Server-side bug or outage. Retry with backoff. |
Retry guidance
- Never retry 4xx. They’re client errors — fix and resend.
- Retry 429 with the
Retry-Aftervalue. Fixed windows don’t roll over; faster retries are pointless. - Retry 5xx with exponential backoff. Cap at 3-5 attempts per request. If 5xx persists, alert on it — don’t silently swallow.
Idempotency on writes
The only write endpoint —POST /v1/deals/events — is idempotent on dedup_key. You can safely retry without creating duplicate events. See Ingest a deal event for details.