Error catalogue
The single error envelope and every stable error code.
Every error response uses a single envelope:
{ "error": { "code": "…", "message": "…" } }code is a stable, machine-readable identifier; message is a human-readable
description and may change. Branch on code (and the HTTP status), never on
message.
Codes
code | HTTP | When it happens |
|---|---|---|
unauthorized | 401 | Missing, malformed, unknown, expired, or revoked API key. |
forbidden | 403 | The key lacks the scope the endpoint requires (for example, a read-only key attempted a write). |
bad_request | 400 | Request body or query failed validation; or a cursor that does not match the requested sort/order. |
not_found | 404 | The resource does not exist, or is not in the key's team. |
conflict | 409 | A request with the same Idempotency-Key is still in flight; retry shortly. |
key_limit_reached | 409 | The team already holds the maximum number of active API keys. |
idempotency_key_conflict | 422 | An Idempotency-Key was reused with a different request body. |
rate_limited | 429 | A per-key or per-IP rate limit was exceeded. The response includes Retry-After and RateLimit-* headers. |
Notes
404, not403, for cross-team resources. An id that belongs to another team returns404, so the API never reveals whether an id exists elsewhere.- Validation failures are
400 bad_request. Themessagesummarizes the invalid field(s); do not parse it; treat it as human-facing.
For GraphQL, errors appear in the errors array with the same codes under
extensions.code. See the GraphQL guide.