Errors
The error envelope
Every non-2xx response has the same shape. Branch on error.code, never on the message. error.details depends on the code; for refusals of an API key it carries a reason.
The requestId is also in the X-Request-Id header of every response, successful or not. Quote it when you contact support.
403 Forbidden
{ "error": { "code": "forbidden", "message": "This key is missing the codes:write scope", "details": { "reason": "missing_scope", "scope": "codes:write" }, "requestId": "req_7Hq2mK9xT4" }}Error codes
400validation_failedThe body or query failed validation. details is a list of { path, message } issues.400bad_requestThe request is well formed but can't be done; details.reason says why.401unauthorizedThe key is missing, malformed, revoked or expired.403forbiddenThe key may not do this: a missing scope, a folder or IP restriction, or a route for the app only. See details.reason.404not_foundNo such object in this workspace, or the key can't see it.409conflictA slug or hostname is taken, or a request with the same Idempotency-Key is still running.422idempotency_conflictThe Idempotency-Key was used before with a different body.410goneThe object existed and was deleted or released.413payload_too_largeThe body or upload is over the size limit.429rate_limitedOver the workspace's per-minute or burst budget. Wait Retry-After seconds.403plan_limit_reachedA plan limit (codes, bulk rows, jobs…) is reached. details names the limit and the usage.403feature_not_in_planThe workspace's plan doesn't include this (for example webhooks on Free).422unsafe_destinationThe destination failed the Google Web Risk and blocklist check.500internalSomething failed on our side. Retry with backoff; quote the requestId if it persists.503unavailableTemporarily unavailable. Retry with backoff.API key refusals
details.reason of the refusals that are specific to API keys.
403 forbiddenmissing_scopeThe key lacks the route's scope (details.scope), or its creator's role no longer allows it.403 forbiddensession_requiredThe route is for the app only (billing, members, key management…); keys can't call it.403 forbiddenapi_key_folder_restrictedThe key is limited to some folders (details.folderIds) and the request targets another.403 forbiddenip_not_allowedThe caller's address is outside the key's IP allowlist.400 bad_requesttest_mode_unavailablesk_test_ keys can't be created: there is no test mode yet. Use a separate workspace for tests.400 bad_requesttoo_many_api_keysThe workspace already has 50 live keys (details.limit). Revoke one first.403 forbiddenscope_not_grantableYour role can't grant these scopes (details.scopes), e.g. webhooks:write as an editor.What to retry
Retry 429 after Retry-After seconds, and 500 or 503 with exponential backoff. Every other 4xx needs a change to the request first. POST requests are safe to retry when you send the same Idempotency-Key.