Skip to content

Errors ​

A failed request answers a non-2xx status with a JSON body. Route handlers answer the flat envelope:

json
{ "status": 422, "code": "VALIDATION_ERROR", "message": "Invalid document payload", "fields": { "rootAtoms": "Not bound to this document type: 1234…" } }

The token authenticator and the two raw design-token exports (.css, .tokens.json) answer the same fields nested under error:

json
{ "error": { "status": 401, "code": "INVALID_API_TOKEN", "message": "Invalid, expired, or revoked API token" } }

Branch on code; message is localized prose. Some codes carry extra fields, noted below. A 429 also sets a Retry-After header (seconds).

Codes ​

CodeStatusMeaningWhat to do
API_TOKEN_REQUIRED401No Authorization: Bearer atk_… or X-API-Key headerSend the token
INVALID_API_TOKEN401The token is unknown, revoked or expired, or belongs to another organization than the URL'sRegenerate or create a token; check org_id
TOKEN_ORG_MISMATCH403The token does not belong to the URL's organizationUse the right org_id
TOKEN_PROJECT_MISMATCH403The token is narrowed to one project and the URL names anotherUse the token's project, or an organization-wide token
TOKEN_SCOPE_READ_ONLY403A write with a read token; carries requiredPlanCreate a read + write token
FEATURE_DISABLED403The organization's plan has no API writes; carries feature and requiredPlanUpgrade in Studio → Settings → Billing
ACCOUNT_CLOSED403The organization has been closedDo not retry
DELIVERY_BLOCKED403Content delivery for the organization is blocked by the platformDo not retry; the organization's owner can contact support from Studio
BILLING_TERMINATED402The subscription was terminated for non-paymentAn owner settles the invoice in Studio → Settings → Billing
NOT_FOUND404Unknown org id, project slug or resource — or a resource that is not published, to a caller without draft accessCheck the slug; use ?status=draft with a read_write token to see drafts
VALIDATION_ERROR422The write payload was refused; fields names each problem (an unknown atom uuid, a missing title, a bad parent term, a refused upload URL)Fix the named fields; nothing was written
SLUG_CONFLICT409The requested slug is taken within the typeOmit slug to derive a unique one, or choose another
VERSION_LOCKED409An editor has the document or term open; holder.name and expiresAt say who and until when; nothing was writtenRetry after the lock lapses
LIMIT_EXCEEDED403An upload would exceed the plan's storage capFree space in Studio → Media, or upgrade
UNSUPPORTED_MEDIA_TYPE415The upload is not an accepted image typeSend a JPEG, PNG, GIF, WebP, AVIF or SVG
EMPTY_FILE · UPLOAD_FAILED400The upload carried no usable file; errors lists per-file failuresCheck the multipart body
RATE_LIMITED429A rate limit was hit; Retry-After says how longWait; do not retry in a loop
PLATFORM_READ_ONLY503Writes are paused platform-wide; reads still workWait Retry-After, retry the write once
PLATFORM_MAINTENANCE503The platform is down for maintenanceWait Retry-After, then retry
QUERY_FAILED500The read or write could not complete — never an empty 200Retry; if it persists, contact support with the time and route

Not found is deliberate ​

The API never distinguishes "does not exist" from "not published" to a caller without draft access — doing so would let a read token discover draft work. It also checks the credential before resolving the URL, so an anonymous caller cannot tell a real project slug from an invented one.

Writes are all-or-nothing ​

Every write validates the whole payload before touching anything: a 422, a 409 VERSION_LOCKED or a 409 SLUG_CONFLICT means nothing was written. A create whose content commit fails rolls the new row back, so a retry never lands on title-2.

Documentation for Hypervalent Studio