DownloadsDocsWikiWhyFeaturesPricing

Errors & Limits

Every error is a flat JSON object with an error_code and a human-readable message. Nothing is ever silently dropped — a rejected field or exhausted limit always comes back as one of the bodies below.

401 — missing or invalid key

{
  "error_code": "UNAUTHORIZED",
  "message": "Invalid or revoked API key",
  "retryable": false
}

402 — insufficient credits

Returned when the account balance can't cover the request.

{
  "code": "INSUFFICIENT_CREDITS",
  "message": "You've run out of credits. Purchase more to continue using cloud models.",
  "available_microcredits": 0,
  "required_microcredits": 5250,
  "available_credits_display": "0.00",
  "required_credits_display": "5.25",
  "purchase_url": "https://verdictide.com/account/billing/credits?..."
}

403 — forbidden

Two distinct cases share this status code:

A test-environment key on a live endpoint — there is no test environment at launch:

{
  "error_code": "test_key_not_allowed",
  "message": "Test-environment API keys are not accepted on /v1/chat/completions.",
  "retryable": false
}

A key missing the required scope:

{
  "error_code": "insufficient_scope",
  "message": "This API key does not have the 'llm:chat' scope.",
  "retryable": false
}

429 — rate limited

{
  "error_code": "rate_limit_exceeded",
  "message": "Per-key rate limit exceeded: 60 requests/minute.",
  "retryable": true
}

Carries a Retry-After header (seconds until the current window resets).

400 — unsupported parameter

Returned for a rejected field per the compatibility matrix — the response names the field.

{
  "error_code": "unsupported_parameter",
  "message": "Parameter 'seed' is not supported.",
  "retryable": false,
  "param": "seed"
}

x-ratelimit-* headers

Sent on every response from a key that has a configured limit. An unlimited key emits none of these — there is no ceiling to report.

HeaderMeaning
x-ratelimit-limit-requestsThe configured ceiling for the primary window (per-minute if rpm is set, otherwise per-day).
x-ratelimit-remaining-requestsRequests left in the current primary window.
x-ratelimit-reset-requestsTime until the primary window resets, formatted like 21s or 1m0s.
x-ratelimit-limit-requests-day / -remaining-requests-day / -reset-requests-dayThe daily ceiling, only emitted when both a per-minute and a per-day limit are configured on the same key.
Retry-AfterSeconds to wait before retrying, sent only on a 429.

Rate limiting is per-instance

At launch, rpm/rpd limits are enforced per Gateway instance, approximately— not with a single shared counter. With N instances behind the load balancer, the effective ceiling for a key is up to N× its configured value. This is a documented launch posture, not a bug; a shared atomic counter is the upgrade path once the API tier carries real traffic.

Key revocation

A revoked or rotated key stops authenticating within 60 seconds or less, everywhere — each Gateway instance caches key lookups for up to 60 seconds before re-checking.

Key expiration

Every key can be given an expiration when it's created: 30, 90, or 365 days, or never. The console defaults new keys to 90 days. An expired key fails the same way a revoked one does.

Scopes

A key needs the llm:chat scope to call /v1/chat/completions. A key missing it gets the 403 insufficient_scope body above rather than a silent failure.

Learn More