Reference
Errors
Failures use one envelope. Branch on error.code. The HTTP status is the class. The message is for a person. request_id is safe to send to support. Do not send the token with it.
{ "ok": false, "error": { "code": "UNKNOWN_EXPIRY", "message": "Unknown expiry.", "details": [{"available": ["2026-10-19", "2026-10-20"]}], "request_id": "req_example_01" } }
error.details is present when the validator or the expiry check has a field to name. There is no stack trace. meta.rate_limit is added only when a rate-limit gate is the thing that answered.
Validation details
Every VALIDATION_ERROR names the field. The message is one sentence about the first problem. error.details lists every bad field, up to 20.
{ "ok": false, "error": { "code": "VALIDATION_ERROR", "message": "Invalid expiry: \"2026-13-01\". Expected YYYY-MM-DD or an alias (0, 1, w1-w4, M1-M3, ALL).", "details": [ { "field": "expiry", "problem": "format", "expected": "YYYY-MM-DD or an alias (0, 1, w1-w4, M1-M3, ALL)", "received": "2026-13-01" } ], "request_id": "req_example_01" } }
| Field | Meaning |
|---|---|
field | The request field. An array item has its index: symbols[3]. The whole body is body; the header is content-type. |
problem | One of unknown, missing, require_any, type, format, range, enum, duplicate, too_many, empty. The list is closed. |
expected | What the field takes, in the same words as the parameter table. Missing on body-level problems. |
received | What you sent, as text, at most 64 characters, cut with …, control characters removed. An object is "object", an array is "array". |
Body-level sentences: Duplicate field "symbol"., Body must be a JSON object., Body is not valid JSON at position N., Content-Type must be application/json., Unknown query parameter "x". Send parameters in the JSON body. On MCP the same details are in structuredContent.error and the text content is the message. Auth, rate-limit and unknown-path errors have no details.
What the client should do
| HTTP | Code | Do this |
|---|---|---|
422 | VALIDATION_ERROR | Fix the body. Unknown field, nested object, repeated key, bad JSON, bad alias, integer outside signed 64-bit, or a cursor that does not match. Do not retry the same body. |
422 | UNKNOWN_SYMBOL | The required symbol is not in the universe. Call list_symbols. Do not retry. |
422 | UNKNOWN_EXPIRY | You sent a symbol and an expiry that symbol does not have. Use a date from error.details. The same bad expiry with no symbol is an empty 200, not this error. |
422 | RESULT_TOO_LARGE | The uncompressed JSON would exceed 512 KiB. Narrow with symbol, or symbol and expiry, as the message says. Do not retry the wide call. |
404 | NOT_FOUND | That path is not a route. It looks the same as any other unknown path, and it is decided before auth. Stop. Do not hunt for another version prefix. |
401 | AUTH_REQUIRED | No bearer token. The response includes WWW-Authenticate: Bearer. Add the header. Do not retry in a loop. |
401 | INVALID_CREDENTIALS | The token is malformed or not recognized. Fix the secret. Failed auths from this address share a counter. |
429 | RATE_LIMIT_EXCEEDED | The ET-minute budget is spent. Sleep for Retry-After seconds, then continue. The window ends at the next America/New_York minute, not 60 seconds after your first call. |
429 | AUTH_RATE_LIMITED | Too many auth failures from this address. Wait Retry-After. Default budget is 60 per ET minute. |
429 | NOT_FOUND_RATE_LIMITED | Too many unknown paths from this address. Wait Retry-After. Default budget is 30 per ET minute. |
503 | DATA_WARMING | The datapoint is not built yet. Retry-After is 1. Wait, then retry the same read. |
503 | OVERLOADED | The process shed load, or every Redis slot is busy. Retry-After is 1. No usage is counted. Wait, then retry. |
503 | STATE_UNAVAILABLE | Shared state cannot be reached: the connection failed, timed out, or the process ran out of file descriptors. Retry-After is 1. Wait, then retry. |
413 | PAYLOAD_TOO_LARGE | A market JSON body is over 4 KiB at the app, an account JSON body is over 1024 bytes, or any body is over 64 KiB at the proxy. Shrink the body. A symbol list of 300 tickers still fits the 4 KiB cap if the tickers are short; a pasted chain will not. |
Other statuses
| HTTP | Code | When |
|---|---|---|
403 | ENDPOINT_NOT_ENABLED | The route is outside this token's explicit group list. A default PRO token can call every group, so this code is not returned for a catalog route. On MCP the HTTP status is still 403, and the body is a tool result with isError true and this code inside structuredContent. It is not a JSON-RPC error. Do not retry until the group is on the list. |
403 | API_USER_INACTIVE | The key exists and is not allowed to call. |
403 | API_USER_SUSPENDED | The key is suspended. |
403 | DISCORD_REQUIRED | Only when a Discord requirement is enabled for the account and no Discord user is linked. This is not a general requirement for PRO API or MCP access. |
429 | ACCOUNT_RATE_LIMITED | Too many /api/v1/account/* reads this ET minute. Default budget is 30, on top of the shared user budget. Wait Retry-After. meta.rate_limit.scope is account. The RateLimit-* headers still describe the shared budget. See Account. |
403 | IP_BLOCKED | This source address is blocked. |
405 | METHOD_NOT_ALLOWED | Allow names POST. OPTIONS is this, because there is no CORS. |
431 | HEADERS_TOO_LARGE | Headers over 16 KiB, rejected at the proxy. |
503 | AUTH_UNAVAILABLE | The auth store cannot be reached. No attempt is counted. |
503 | MAINTENANCE | Retry-After is the remaining window when one is known. |
503 | DATA_BUSY | This slice is already being built. Retry-After is 1. |
503 | DATA_NOT_READY / DATA_UNAVAILABLE | The generation cannot be served yet. Retry-After is 5. |
MCP
A tool’s domain error uses the same envelope inside structuredContent, with isError: true. It is not a JSON-RPC error. A disabled group is the same shape at HTTP 403, code ENDPOINT_NOT_ENABLED. JSON-RPC errors are a broken body, an unknown method, or an unknown tool. Auth and rate limits are HTTP responses before the body is read as JSON-RPC.
TanukiTrade API and MCP. Derived options analytics for your code and for agents. Not investment advice. tanukitrade.com