Error codes

The standard error envelope and stable machine-readable error codes.

Every error uses the same envelope, with a stable machine-readable code:

{
  "error": {
    "code": "insufficient_scope",
    "message": "This request requires the 'clips:read' scope.",
    "details": { "required_scope": "clips:read" }
  },
  "request_id": "req_..."
}

Branch on error.code, never on the HTTP status alone and never on message -
messages are written for humans and will change. Log request_id and include it
when contacting support; it identifies the exact request in our logs.

details is optional and its contents vary by code. For validation_error it
usually names the offending field.

Codes

HTTPcodeMeaning
400validation_errorInvalid request body or parameters
401missing_api_keyNo API key was provided
401invalid_api_keyKey not recognized or malformed
401key_revokedKey or its app has been revoked or disabled
401key_expiredKey has passed its expiry
401invalid_signatureHMAC request signature failed (signed mode)
403insufficient_scopeKey lacks the scope this operation requires
403ip_not_allowedSource IP is not in the app's allowlist
404not_foundResource does not exist, or is not in your organization
409idempotency_conflictAn Idempotency-Key was reused with a different body
429rate_limitedPer-key rate limit exceeded. See Retry-After
500internal_errorUnexpected server error
501not_implementedReserved. No current endpoint returns this

Codes worth handling explicitly

not_found hides authorization. A resource that exists but belongs to
another organization returns 404, not 403. This is deliberate - it prevents
probing for ids - so do not read 404 as proof that something never existed.

insufficient_scope is not retryable. The key's scopes are fixed at issue
time and are intersected with its parent app's scopes, so a key can lack a scope
that the app itself has. Fix it by issuing a new key, not by retrying.

idempotency_conflict means the bodies differed. Reusing a key with the
same body is the supported path and replays the original response with
Idempotent-Replayed: true. You only get 409 when the key matches but the
body does not. Generate a fresh key per logical operation - never reuse one
across different requests.

validation_error is not always 400. External storage endpoints return it
with 403 when the organization has no external storage configured, and
upstream failures can surface it with other 4xx statuses. Handle the code, and
treat the status as advisory.

Which errors can any endpoint return

Assume every operation can return 401, 403 and 429, regardless of what it
does - these come from authentication, scope checking and rate limiting, all of
which run before the handler. Every POST that accepts Idempotency-Key can
additionally return 409.

Retrying

CodeRetry?
rate_limitedYes, after Retry-After seconds
internal_errorYes, with exponential backoff
idempotency_conflictNo - fix the key or the body
insufficient_scope, ip_not_allowedNo - a configuration change is needed
validation_error, not_foundNo - the request itself is wrong
key_revoked, key_expired, invalid_api_keyNo - issue a new key

When retrying anything that writes, send an Idempotency-Key so a retry after a
timeout cannot duplicate the work. See
Rate limiting for backoff guidance.


Did this page help you?