Errors
Statuses
| Status | Meaning |
|---|---|
| 200 | Success |
| 400 | Invalid request, charged nothing. Bounds, enums, dates and offsets are validated BEFORE any index work, so this never means a partially-served query. `credit_budget_exceeded`: the call's worst case is more than `max_credits`. |
| 401 | Missing or invalid API key. `code` is `unauthorized`. |
| 402 | Account suspended (subscription canceled or payment failed). `code` is `suspended`. |
| 429 | Refused before running, and charged nothing. `credit_rate_limited`: this minute's credits are spent. `message_rate_limited`: too many free calls or refused requests this minute. `insufficient_credits`: the key stops at its monthly allocation and does not have this call's worst case left. `retry-after` says how long to wait. |
| 503 | The index could not be read for this request. This is NOT an empty result set and NOT a statement that nothing matched — retry rather than caching it as a negative. `coverage` says which part was unreadable. |
The id endpoints add 404 (its meaning against 503 is
worth reading). Plus the ones any HTTP service can return:
| Status | Means | Retry? |
|---|---|---|
408 | The request exceeded the server's own time budget. | Yes, but narrow it first — see below. |
413 | Request body too large. Only reachable on the MCP endpoint. | No. |
Error bodies
Every 4xx and 5xx carries the same JSON body, 401, 402 and
429 included. Switch on code; detail is for a person, and on a
503 it says in so many words that the response is not evidence of absence.
| Field | Type | Description |
|---|---|---|
| code | `invalid_parameter` · `unknown_parameter` · `unknown_signal` · `not_found` · `unauthorized` · `suspended` · `insufficient_credits` · `credit_rate_limited` · `message_rate_limited` · `credit_budget_exceeded` · `upstream_unavailable` · `internal` · `watch_limit` · `unsupported` | Stable machine-readable reason; switch on this. The same codes appear in MCP tool errors. |
| credits | CreditRange | On a credit refusal: what the refused call could cost. |
| credits_limit | integer | On `insufficient_credits`: credits included this month. |
| credits_needed | integer | On `credit_rate_limited`: the credits that must be free this minute for the call to run. |
| credits_per_minute | integer | On `credit_rate_limited`: credits allowed per minute. |
| credits_per_minute_remaining | integer | On `credit_rate_limited`: credits left this minute. |
| credits_remaining | integer | On `insufficient_credits`: credits left this month, less calls in flight. |
| credits_used | integer | On `insufficient_credits`: credits used this month. |
| detail | string | What a caller should do about it. On a 503 this states explicitly that the response is not evidence of absence; on an unknown parameter it names the one you probably meant. |
| error | string | Short human-readable label, e.g. `invalid request`. |
| max_credits | integer | On `credit_budget_exceeded`: the budget you passed. |
| messages_per_minute | integer | On `message_rate_limited`: free calls and refused requests allowed per minute. |
| retry_after_secs | integer | On a 429: how long to wait before retrying. For `insufficient_credits`, when the monthly allocation renews. |
code | Status |
|---|---|
invalid_parameter | 400 |
unknown_parameter | 400 |
unknown_signal | 400 |
not_found | 404 |
unauthorized | 401 |
suspended | 402 |
insufficient_credits | 429 |
credit_rate_limited | 429 |
message_rate_limited | 429 |
credit_budget_exceeded | 400 |
upstream_unavailable | 503 |
internal | 500 |
watch_limit | 400 |
unsupported | MCP only |
The same codes appear in MCP tool errors and, for the 400 family, in
error.data.code on a JSON-RPC error — one table handles both surfaces.
400: a mistake in the request
Not retryable and never partial: bounds, enums, dates, offsets and parameter names are validated before any index work. Three codes, and each says what to change.
{
"error": "invalid request",
"code": "unknown_parameter",
"detail": "Unknown parameter 'organiztion'. Did you mean 'organization'?"
} -
unknown_parameter— a query parameter the endpoint does not take. The hint names the closest one it does. -
unknown_signal— a name insignalorsignalsthat is not one of the published signals. -
invalid_parameter— a value outside its range or enum: alimitover 100, aviewthat is neitherfullnorcompact, afacetsfield that cannot be counted,signal_minwithoutsignal, a malformed date.
watch_limit is a 400 too, on POST /watches when the account already keeps
as many watches as its plan allows. Retrying will not help until one is
deleted or the plan changes. unsupported never arrives over REST: it is the tool error a watch tool
returns on an MCP server with no watch store, such as the local stdio server.
credit_budget_exceeded is a 400 as well: the call's worst case costs more than the
max_credits you passed. Nothing ran and nothing was charged; the body's credits says what it
could cost. Credits and overage.
Until September 2026 unknown parameters were ignored. organiztion=asml searched everything, and the
typo looked like a wide result set rather than a mistake; an unknown signal name matched nothing, which looked
like no coverage. Both now fail, with the name you meant.
Retrying
A 429 is never charged. Switch on code: the three want different waits.
429, credit_rate_limited or message_rate_limited
Transient. This minute's credits, or free messages, are spent. retry-after is when the call would fit —
usually a second or two, because the bucket refills continuously. Do not exponentially back off from there to a
minute; you will be idle on an allowance you had paid for. Rate limits and backoff has a
correct client.
429, insufficient_credits
Not transient. The key stops at its monthly allocation, and this call's worst case costs more than the credits left,
so retrying will not help until the month resets — retry-after says how many seconds that is, and it may
be days. A cheaper call may still fit: the body carries the call's credits and your
credits_remaining.
503
Every shard covering your time range failed to answer. Deliberately not reported as zero results: an agent
that reads "no matches" when the fleet is degraded concludes the story does not exist. Retry with backoff, and
narrow the range — a tighter from/to asks fewer shards and is likelier to succeed.
408
A relevance query over a wide time range has to visit every shard overlapping it. A call stopped at the time budget is charged nothing. If you are hitting this, the fix is almost always a narrower window rather than a longer client timeout — see Time windows.
A wide query that reached most but not all of the index returns 200 with the results it did get, and
says so:
What is not an error
- Zero results.
200with an emptyresultsarray andcoverage: complete. Usually an exact filter value the index does not hold — resolve the name with/entities, which returns the spellings it does hold, or check it against a facet. - Fewer results than expected. Check
from_clamped: your plan may have narrowed the window. Archive depth. Then checkpartialandcoverage: the index may not have been fully read.
On MCP
The same conditions and the same codes, but some are reported as tool errors rather than as statuses,
because an HTTP error on a tool call reads to a client as a server that has gone away, and the 400
family is a JSON-RPC -32602 with the code in error.data. MCP
errors has the mapping and the exact payloads.