NeuroAPI
GuidesErrors

Errors

Status codes, error format, and when to retry.

The public API uses standard HTTP status codes. Every error body is a JSON object with a detail key, but detail itself takes one of three shapes. Branch on the HTTP status first, then read detail.

Coded - 400, 402, 409, 429, and most 403s. code is stable and safe to branch on; message is prose and may be reworded.

{
  "detail": {
    "code": "mode_not_in_plan",
    "message": "Mode 'max' is not available on the 'starter' plan. Upgrade to access it."
  }
}

Plain - 401 and 503. These predate the coded shape.

{
  "detail": "Invalid API key"
}

Validation - a 422 caused by a malformed body. Here detail is a list, described under Validation below.

{
  "detail": [{ "type": "missing", "loc": ["body", "prompt"], "msg": "Field required" }]
}

detail is not always a string. String(err.detail).toLowerCase() breaks the first time it sees a 403 or a 429.

Every error response also carries an X-Request-Id header. Quote it when reporting issues.

Status codes

CodeMeaningRetry?
200Success-
400Malformed body or invalid field. Don't retry without fixing.No
401Missing or invalid X-API-Key.No
402No active subscription, or quota exhausted.No (fix billing first)
403Selected mode isn't available on your plan (code: mode_not_in_plan).No (pick a lower mode or upgrade)
404Endpoint or resource not found.No
409An earlier call with the same Idempotency-Key is still in flight.Yes, once it completes
422Validation error on the request body.No
429Rate limit exceeded. Honour Retry-After.Yes, after Retry-After
500Bug on our side. Please report with X-Request-Id.Maybe (idempotent calls)
503Agent capacity saturated.Yes, with backoff

Error codes

Most errors carry a machine-readable code inside detail.

codeStatusWhat happenedWhat to do
invalid_idempotency_key400Idempotency-Key isn't 1-255 printable ASCII characters.Fix the header value.
invalid_query_string400A query string was sent alongside Idempotency-Key.Move the parameters into the body.
streaming_unsupported_for_structured_output400output_schema was combined with stream=true.Set stream=false; structured output is non-streaming.
quota_exceeded402 / 429The plan's request quota is spent.Wait for X-Quota-Reset, or upgrade.
mode_not_in_plan403The requested mode isn't on your plan.Use a lower mode, or upgrade.
no_active_subscription403The key is valid but the account has no active plan.Subscribe, then retry.
mcp_origin_not_allowed403A browser Origin hit the MCP endpoint from an untrusted host.Call MCP server-side.
idempotent_request_in_flight409An earlier call with the same Idempotency-Key is still running.Retry once it finishes.
idempotency_key_mismatch422The same Idempotency-Key was reused with a different body.Use a fresh key for a different request.
invalid_output_schema422output_schema isn't a usable JSON Schema.Fix the schema.
rate_limited429The per-key rate limit was hit.Back off for Retry-After seconds.

401 and 503 carry no code - branch on the status for those.

Validation (422)

Anatomy of a 422

Each entry returns the field path and an explanation. Treat the loc array as the JSON pointer into your request body.

{
  "detail": [
    {
      "type": "missing",
      "loc": ["body", "prompt"],
      "msg": "Field required"
    }
  ]
}

When to retry

Retry 429 and 503 with exponential backoff. Cap retries (we recommend three) and surface the failure to the caller; the agent is non-idempotent in the sense that two calls produce two answers and two charges, so don't retry blindly on 500.

Send an Idempotency-Key to remove that caveat: with one, a retry replays the original response instead of running - and billing - a second time.

Report an issue

Send us:

  1. The X-Request-Id from the failing response.
  2. The HTTP status and body.
  3. The approximate timestamp (UTC).
  4. The mode and prompt shape (no need to share the full prompt content if it's sensitive - the request id is enough on our side).

On this page