Errors & rate limits

Error shape

Every non-2xx response is JSON of the form:

{
  "error": {
    "code": "insufficient_scope",
    "message": "This endpoint requires the `generation:run` scope.",
    "required_scope": "generation:run",
    "granted_scopes": ["books:read"]
  }
}

Common codes

HTTPerror.codeMeaning
400invalid_requestThe body or query failed schema validation.
400invalid_stateThe book/chapter exists but isn’t in a state that supports the action (e.g. publishing a book with empty chapters).
401unauthenticatedMissing or malformed Authorization header.
401invalid_tokenToken is unknown, expired, or revoked.
403insufficient_scopeThe token is valid but missing the scope the endpoint requires — mint a new key with the listed scope.
404not_foundThe book or chapter doesn’t exist (or isn’t owned by you).
502generation_failed, narration_failedThe downstream provider (Anthropic, ElevenLabs) failed. Safe to retry.
503feature_disabledThe Anthra instance doesn’t have the required upstream key configured (e.g. ELEVENLABS_API_KEY for narration).

Rate limits

Anthra applies per-account quotas to expensive operations (chapter generation, narration). When you hit a limit, you’ll receive an HTTP 429 with retry-after set to the number of seconds to back off. The 429 body uses the same error shape.

Generation jobs are also bounded by maxDuration = 300s on Vercel Functions — chapter writes that legitimately need longer should be re-issued (the partial content is already saved before the timeout).

Idempotency

Mutating endpoints are not idempotent today. Use a unique key per request (e.g. POST /v1/books always creates a new book). If you need at-most-once semantics, deduplicate on the client before retrying.