Docs

API

Errors

Every non-2xx response is the same JSON shape with a code from one closed, append-only set. Branch on code, never on message.

The error envelope

Every error the API returns — including rejections from in front of the handler — is JSON of this shape, never HTML:

json
{
  "error": {
    "code": "not_entitled_tier",
    "message": "a human-readable explanation",
    "details": null
  }
}
  • code is machine-readable and comes from the closed set below.
  • message is for people. Its wording can change; do not parse it.
  • details is optional structured context and may be null.

Error codes

The set is closed and append-only: codes are never renamed or removed, and a new one is only added for a genuinely new failure mode. This table is generated from the API contract.

CodeHTTPWhat it means
unauthenticated401No credential, or one the API does not recognise. Send Authorization: Bearer itm_….
token_expired401The credential was valid and has expired. For a key: it was revoked or rotated.
invalid_ticketWSA WebSocket ticket that is malformed, expired or already used. Mint a new one per connection.
not_entitled_tier403Your plan does not include this data, or the account has no API access.
not_entitled_symbol403This symbol is not available to API keys (index symbols and options on them are app-only).
attestation_required403The account has not declared a market-data classification yet. Do it once in account settings.
rate_limited429Too many requests right now. The response carries Retry-After in seconds; wait that long, then retry.
quota_exceededWSA new stream subscription would pass your plan’s subscription or symbol cap. Unsubscribe from something first.
invalid_params400A parameter is missing, malformed or out of range. message says which.
not_found404No such symbol, contract, record or session.
range_capped—Reserved for range limits; not returned by any public operation today. Handle it like invalid_params.
partial_data—Reserved for incomplete answers; not returned today. Completeness is reported in meta on the endpoints where it varies.
internal5xxSomething failed on our side. Safe reads can be retried with backoff; include the request ID if you report it.

Retrying

  • Retry 429 rate_limited after the number of seconds in Retry-After.
  • Retry safe reads (GET) on 502, 503 and 504 with exponential backoff and a cap.
  • Do not blindly retry writes (POST, PUT, PATCH, DELETE). PUT operations in this API are idempotent upserts under an id you choose, so repeating one is safe; a POST may not be.
  • Never retry 401 or 403 without changing something first — the same request will fail the same way.

The SDKs follow exactly these rules: they retry GET on 429/502/503/504 with bounded waits (at most 30 seconds each) and never replay a write.

Reporting a problem

Include the x-request-id response header (the SDKs expose it as the result's request id and on the error). It identifies the exact request on our side.