# Errors & recovery

Handle failures, pagination, credit limits, and safe retries.

Updated: 2026-10-02

## Consistent errors

```json
{ "error": { "code": "version_conflict", "message": "The website changed or another run is active. Read the current state before retrying." } }
```

- 400 invalid_request: correct inputs; URL identifiers must match any identifiers in the body.
- 401 invalid_token: missing, invalid, expired, revoked key, or removed membership.
- 403 permission_denied: missing scope, current role restrictions, or site-bound key restrictions.
- 404 not_found: resource is outside the key's boundary or no longer exists.
- 402 plan_required: add available credits or an eligible plan.
- 409 version_conflict: reload current state and reconcile before editing/restoring.
- 413 payload_too_large / 415 unsupported_media_type: use bounded JSON bodies and application/json.
- 422 build_required / resources_inactive: build or activate resources before publishing.
- 429 rate_limited: respect Retry-After; default 60 seconds.
- 503 unavailable: back off and retry the same requestId for create/edit.

## Recover safely

Create and edit use requestId for recovery. Save it before sending the request and retain identical inputs on retries. Restoring creates a new draft and is protected by expectedVersion; do not blindly repeat it after a timeout. Read current revisions first. Publishing and tracking updates may be retried with the same target, but audit metadata can contain repeated entries.

## Pagination

List methods return nextCursor or null. Sites use UUID after cursors; revisions use integer before versions; audit events use numeric-string after cursors. limit ranges from 1 to 100 and defaults to 30. A full final page can return a cursor followed by an empty page. Audit events are ordered by event ID.