All errors follow the standard response envelope with status: "ERROR".
{
"status": "ERROR",
"request_id": "cm_abc123...",
"error": {
"code": "error_code",
"message": "Human-readable description."
}
}
Error codes
| HTTP Status | Code | Description |
|---|---|---|
| 400 | bad_request | Missing or invalid query parameters. |
| 400 | invalid_page_token | The page parameter is invalid or expired. Repeat the list request without page, then follow each next_url the API returns. |
| 401 | unauthorized | Missing or invalid API key. |
| 403 | forbidden | Your plan does not include this endpoint. |
| 403 | lookback_exceeded | A date or timestamp parameter falls outside your plan's historical lookback window (3 years for Free, 7 years for Developer). Upgrade your plan or adjust the date range. |
| 404 | not_found | The requested resource does not exist. |
| 429 | rate_limit_exceeded | You have exceeded your plan's request limit. |
Error-handling pattern
Treat the request_id as the primary debugging handle. It should be logged with the HTTP status, route, product, account-side job id, and sanitized key label. Do not log full API keys or bearer headers.
| Error family | Retry? | Client action |
|---|---|---|
bad_request | No | Fix the parameter, date format, ticker, or filter combination. |
unauthorized | No | Check that the bearer token is present and active. |
forbidden | No | Confirm the product key and plan entitlement. |
lookback_exceeded | No | Shorten the date range or upgrade to a longer lookback plan. |
rate_limit_exceeded | Later | Back off according to your worker policy and reduce burst concurrency. |
invalid_page_token | No | Restart from the list request and follow the new next_url. |
Production logging example
{
"route": "/v1/options/quotes/O:SPY260618C00500000/",
"status": 403,
"code": "lookback_exceeded",
"request_id": "cm_abc123",
"product": "options",
"job": "quote-backfill-2026-06"
}
That log is enough to reproduce the problem without exposing a credential. If the error appears only on one endpoint family, check the product key first; an Options API key and a Stocks API key are intentionally not interchangeable.
Client behavior by environment
Production clients should treat errors as workflow signals, not only as strings to display. A rejected options quote request can mean the symbol is wrong, the contract has expired, the page cursor is stale, the plan lacks quote access, or the requested timestamp is outside the historical window. Those causes need different handling in a research notebook, a dashboard, and a background ingestion job.
For user-facing applications, translate the error into the next action. A bad_request response should point to the invalid field when possible. A forbidden response should explain that the current product key or plan does not include the endpoint. A lookback_exceeded response should show the requested date range and the plan's available window. A rate_limit_exceeded response should avoid blaming the user and should retry later only when the operation is safe to repeat.
For batch jobs, persist failed request metadata so the job can resume deterministically. Store the route, query parameters, request time, account-side job id, and request_id. Do not discard the original query after retrying, because the retry may succeed for a different reason, such as a shorter date range or a new page cursor.
Debugging checklist
- Confirm the API key product: options endpoints require an Options API key and stock endpoints require a Stocks API key.
- Confirm the plan entitlement before investigating code-level bugs.
- Check date filters against the plan lookback window.
- Restart paginated jobs from the first request if
invalid_page_tokenappears. - Log
request_idwith every non-OKresponse so support can trace the exact request.
If the same request fails repeatedly with the same request_id pattern and a stable error code, fix the request. If failures are intermittent and dominated by 429, tune worker concurrency and add a backoff policy before increasing traffic.