Errors

What each status means, what the body carries, and which ones to retry.

All error responses are JSON objects with at least an error string. Machine-readable fields (code, capability, resource, retry_after_seconds) are included when applicable.

Status catalog

HTTPMeaningTypical codeRetry?
400Client validation failure—No (fix request)
401Missing, malformed, unknown, or revoked token—No (fix credentials)
403Valid token but org lacks api_accessupgrade_requiredNo until plan upgrade
403Valid token without the scope this route needsinsufficient_scopeNo (mint a token with the scope)
404No such record in this workspacenot_foundNo
409Token's minting admin is no longer an adminapi_actor_unavailableNo (mint a new token)
409Idempotency-Key reused for a different requestidempotency_key_reusedNo (use a new key)
409Deliverable is signed off, so nothing on it can changedeliverable_signed_offNo
405Wrong HTTP method—No
413Inline image over the 10 MB decoded cappayload_too_largeNo (send a smaller image)
422Business rule / plan limit on createupgrade_requiredNo until upgrade or free capacity
422Project's included revision rounds are used uprevision_over_budgetNo until an override or upgrade
422Deliverable or client is onboarding sample datasample_data_never_emailedNo
422Client has no email address on fileclient_email_missingNo (add an address)
429Rate limit exceededrate_limit_exceededYes after window
500Unexpected server error—Cautious retry
502Upstream storage failure on image uploadstorage_unavailableRetry with backoff, same key
502Review email could not be sentemail_send_failedRetry with the same key

Canonical bodies

401 Unauthorized

{ "error": "Invalid or missing API token" }

403 Forbidden (capability)

{
  "error": "API access is a paid feature",
  "code": "upgrade_required",
  "capability": "api_access"
}

400 Bad Request (examples)

{ "error": "title is required (1-200 chars)" }
{ "error": "client_id is required" }
{ "error": "client_id not found in this workspace" }
{ "error": "Provide embed_url or image_base64" }
{ "error": "embed_url must be an https URL" }

422 Unprocessable Entity (deliverable cap)

{
  "error": "Deliverable limit reached for your plan. Upgrade to create more.",
  "code": "upgrade_required",
  "resource": "deliverables"
}

(Exact error prose may vary; rely on code + resource for branching.)

429 Too Many Requests

{
  "error": "Rate limit exceeded. Please wait a few minutes and try again.",
  "code": "rate_limit_exceeded",
  "retry_after_seconds": 60
}

405 Method Not Allowed

{ "error": "Method not allowed" }

Client handling guidance

  1. Parse JSON even on error responses.
  2. Branch on code before parsing human-readable error text.
  3. For upgrade_required + capability: api_access, send users to Settings → Billing / Pricing. Every paid tier carries api_access since migration 20261112000600, so this now means "you are on a free or cancelled plan", not "you need Agency". Tiers differ by rate ceiling, not by access.
  4. For insufficient_scope, the token is valid but was minted without the scope in required_scope. Scopes cannot be added to an existing token — mint a new one.
  5. For api_actor_unavailable (409), the admin who created the token is no longer an admin of the workspace, so writes cannot be attributed. Mint a new token. A credential must not outlive the authority it was granted under.
  6. For upgrade_required + resource: deliverables, send users to upgrade or archive unused deliverables.
  7. For idempotency_key_reused (409), the key was already spent on a different request. The first result is deliberately not returned, because answering with it would report success for work the caller never asked for. Generate a fresh key per logical operation.
  8. For deliverable_signed_off (409), stop offering edits. A signed-off deliverable refuses every modification, not just a state change — create a new deliverable if the work has genuinely moved on.
  9. For revision_over_budget (422), the project's included revision rounds are spent. This is a commercial conversation, not a retry: surface it as "this revision is outside the agreed rounds" and let the user record an override in the app or bill for it.
  10. For payload_too_large (413), re-export smaller — a lower scale factor or JPEG instead of PNG. The cap is on the decoded bytes, so base64 inflation is not the problem.
  11. For storage_unavailable (502), nothing was created and any partial object was removed. Retry with the same Idempotency-Key.
  12. For email_send_failed (502), nothing was sent and the idempotency claim was released. Retry with the same key; the API will not have double-emailed the client.
  13. For sample_data_never_emailed / client_email_missing (422), these are data problems with a clear user action — they are never fixed by retrying.
  14. For 429, wait at least retry_after_seconds with jitter before retrying. Read the value; it is measured, not a fixed 60.
  15. Never retry 401 / 403 / 400 blindly in a tight loop.

A 200 that still needs reading

POST /api-v1/deliverables/{id}/send can return ok: true with a non-null

status_warning. That means the client was emailed but the deliverable's status

could not be advanced. Do not treat it as a failure and do not re-send: surface the

warning and move on.

RPC errors (Settings UI)

When minting tokens or registering webhooks via Supabase RPC:

Exception messageHintMeaning
API access is a paid featureupgrade_required:api_accessPlan lacks capability
Only organization admins can create API tokens—Caller is not admin
Only organization admins can add webhooks—Caller is not admin

These map to the frontend helper isCapabilityUpgradeError(..., 'api_access').

More reference

  • Authentication — How tokens are minted, stored, presented and revoked.
  • Endpoints — Every request and response shape, with worked examples.
  • Outbound webhooks — Signed HTTPS POSTs when work is signed off, a change order moves, or an invoice is paid — plus how to verify one and how to survive a duplicate.
  • Rate limits — Per organization, per minute, and published rather than discovered as a random failure.
  • Compatibility and versioning — What may change without notice, what may not, and how you are told.
  • API changelog — Every change, dated, including the ones that were corrections.

OpenAPI specification · API access is on every paid plan · Start your 14-day trial