Errors
Every refusal tells you what to do about it.
The shape
Errors use the same envelope as everything else. error.code is stable and safe
to branch on; error.message is for humans and may be reworded.
{
"error": {
"code": "plan_required",
"message": "Half-time prices need the Archive plan.",
"your_plan": "free",
"needs_plan": "archive",
"upgrade_url": "/pricing?from=odds"
},
"meta": { "request_id": "01J9QW3C7M4KX2VB" }
}The codes
400 invalid_parameter: a filter was the wrong type or outside its range.
The message names the parameter.
401 missing_key / 401 unknown_key: no X-API-Key
header, or one we do not recognise. A rotated key gives this.
403 plan_required: a valid key on a plan that does not reach this
endpoint. Always names the plan needed.
403 outside_plan_window, a free key asking for a match or a date older than its
window. The error states the window and names the plan that carries older matches.
404 not_found: no such match, club or competition.
429 rate_limited: see rate limits.
500 server_error: ours, not yours. Quote the request_id.
request_id
Every response carries one, success or failure. Quote it in a support thread and we can find the exact call you made rather than asking you to describe it.
What to retry
Retry 429 after retry-after, and 500 with a backoff.
Never retry 400, 401, 403 or 404:
the answer will not change.