Error format
Every API error returns a stable code plus a human-readable message:retry_after_seconds above) — there is never a nested details object. Branch on the error code, not the message text; messages can change.
Casing convention: routes authenticated with a session or organization key return UPPER_SNAKE codes (UNAUTHORIZED, PLAN_LIMIT_REACHED). Routes authenticated with an agent API key return lower_snake codes (unauthorized, agent_disabled, scope_denied).
Request validation failures are the one exception to the shape above — they return Fastify’s standard
400 body, where the machine code lives in code:Common error codes
Organization API key codes
Codes involved in the organization-key lifecycle. Most are returned on routes authenticated with areinx_org_live_… key; the mint-time codes are returned to a human dashboard
session creating or rotating a key, since key management has no machine scope at all. See
Authentication for scopes and bindings.
Rate limits
Limits are applied per organization and scale with plan tier:
Several tighter limits are enforced on top of that org-wide ceiling:
Authenticated responses carry usage headers:
Daily creation quota (organization keys)
Distinct from rate limiting: a per-key counter covering agent, project, and team creation (default 100/day) that resets at 00:00 UTC, not on a rolling window. Exhaustion returns429 CREATE_QUOTA_EXHAUSTED with no retry-after header and no retry_after_seconds —
there is no short window to wait out, and backing off will not clear it before the reset.
Retrying the same idempotency key + payload within the same UTC day is never re-charged
(complete or not); only a cross-midnight resume of an incomplete create costs another unit.
Rotating the key does not reset the count.
Handling 429s
- First check the code — two
429s are daily lockouts, not throttles.CREATE_QUOTA_EXHAUSTED(organization keys, resource creation) andCOPILOT_BUDGET_EXCEEDED(POST /v1/copilotkit, the org’s daily assistant-usage ceiling) both carry no delay and clear only at 00:00 UTC — retrying either on a backoff loop just burns the day. Every other429(incl.COPILOT_BUSY, a genuine short throttle) is a short throttle. - For a throttle, wait at least
retry_after_seconds(or theretry-afterheader) before retrying — don’t hammer. When neither is present — the upstream-provider relay case in the 429 matrix carries no delay field at all — fall back to client-side exponential backoff (start ~1s, grow it). Retrying immediately just re-hits the upstream limit. - For write requests, retry with the same idempotency key: the retry is deduplicated and will never double-spend. See the payment workflow for how idempotency keys behave.
- If you’re consistently hitting limits at legitimate volume, contact support about your plan’s limits.