Getting started
Errors
Errors return a real HTTP status and { error: { code, message } }. Branch on error.code, never on the message text.
HTTP/1.1 404 { "error": { "code": "not_found", "message": "resource not found" } }
| Status | Code | Meaning |
|---|---|---|
| 400 | bad_request | invalid id, unknown sport, missing or invalid date, season, round or query, invalid type or page (the message names the allowed values) |
| 401 | unauthorized | missing, invalid or revoked API key |
| 403 | ws_not_available | stream ticket requested on a plan without WebSocket access |
| 403 | origin_not_allowed | a widget key used from a site its list does not include (or without an Origin header — widget keys are for browsers) |
| 403 | ip_not_allowed | the call came from an address outside your account’s IP allowlist (Business; set in the dashboard — an empty list allows every address); not counted against the quota |
| 403 | endpoint_not_in_plan | the endpoint is outside your key’s plan: the premium endpoints (win probability, AI commentary, match and player analytics — marked Pro + Business) on Free and Starter |
| 403 | history_not_in_plan | the fixture, race, day or season is older than your plan’s history (Free 7 days, Starter 30 days, Pro 12 months, Business no limit); historyFrom in the error is the first day you can read |
| 404 | not_found | no such resource (an id we never issued, an unknown ranking type, a session or season of another race or series, or a route that does not exist) |
| 404 | no_data | the ids are ours but the source has no such data: standings, team / player season statistics, the player-statistics explorer, a league’s or series’ seasons (since 2026-10-23; not_found before) |
| 404 | not_supported | win probability or AI commentary of a fixture that is not football; the player-statistics explorer of a league that is not football |
| 429 | rate_limited | per-minute rate exceeded — wait Retry-After seconds |
| 429 | quota_exceeded | request quota used up — per UTC month on Starter, Pro and Business (resets 00:00 UTC on the 1st), per UTC day on Free (resets 00:00 UTC); the message names the period and the reset time, Retry-After gives the seconds until the reset |
| 500 | internal_error | our fault; safe to retry (the message is always generic) |
| 503 | upstream_unavailable | data temporarily unavailable; retry after the Retry-After seconds (503 since 2026-10-27 — it was 502, which Cloudflare replaced with its own page, so the JSON never arrived) |