Skip to content
Open Markdown

Errors, pagination and limits ​

Error bodies ​

Two shapes exist. Branch on status first.

Application errors (auth, permissions, not found, conflicts, ...):

json
{ "error": "concurrent_limit" }

error is a machine code; details is optional and is omitted when undefined. It can be structured data or a string. Some operations can return both application and validation errors with HTTP 400; inspect the body as well as the status.

Request validation errors from zod validators on body, query, params and headers use a different shape, with status 400:

json
{
  "success": false,
  "error": {
    "name": "ZodError",
    "issues": [
      { "code": "too_small", "minimum": 8, "type": "string", "inclusive": true, "path": ["idempotency-key"], "message": "String must contain at least 8 character(s)" }
    ]
  }
}

Other cases:

StatusBody
401{"error":"missing_token" | "invalid_token" | "invalid_audience"}
403{"error":"forbidden","details":{"perm":"..."}}
404 (unknown route){"error":"not_found"}
429{"error":"rate_limited"}
500{"error":"internal"} (details are only in server logs; quote x-request-id)

Device-code endpoints under /v1/public/device return OAuth-style {"error":"..."} bodies instead.

Pagination ​

Several list endpoints (for example admin users and store lists) take:

QueryDefaultNotes
qnoneFree-text filter where supported.
page11-based.
per_page25Maximum 100.
sortendpoint-specificfield:asc or field:desc.
json
{ "data": [], "meta": { "page": 1, "per_page": 25, "total": 0 } }

List shapes differ by operation:

StyleExampleImportant difference
Page and totalStaff users/store listsmeta includes total.
Page without totalUser credit ledgermeta only has page/per_page.
Limit and offsetStorage browsingMetadata includes prefix/limit/offset.
Cursor and limitRuntime session listsFollow the operation's cursor envelope.
Bare arrayPublic productsNo data/meta wrapper.

Do not use a universal pagination parser. Check each operation in the reference.

Rate limits ​

Fixed-window limits, counted per user (or client IP when unauthenticated). Exceeding one returns 429 rate_limited.

EndpointLimitWindowKeyed by
POST /v1/public/device/code360 sIP
POST /v1/public/device/token3060 sIP (returns 400 slow_down)
POST /v1/me/device/approve560 suser
POST /v1/me/support group51 huser
Waitlist signup (/v1/public)560 sIP
Email unsubscribe (/v1/public)3060 sIP

Device polling also enforces its own interval (slow_down includes the required interval).

Maintenance mode ​

Operators can put the platform in degraded or lockdown mode. Clients then see:

http
HTTP/1.1 503 Service Unavailable
Retry-After: 30

{ "error": "panic_mode", "level": "lockdown", "reason": "..." }
  • degraded: new checkouts and POST /v1/me/sessions are refused; everything else works.
  • lockdown: all writes from public and /v1/me clients are refused.
  • Reads, POST /v1/me/sessions/stop, /health and staff routes stay available.

Retry after the Retry-After delay. This is distinct from 503 unavailable on session start, which means the runtime failed to create the session.

Built for developers. Ready for agents.