Guide
Errors
The error envelope and every error code.
The envelope
Every non-2xx response is JSON with one error object. code is a closed enum for programs; message is for humans; param names the offending query parameter when there is one. The X-Request-Id header is set on errors too.
Shape
{ "error": { "code": "invalid_param", "message": "…", "param": "season" } }Error codes
| code | HTTP | When | What to do |
|---|---|---|---|
| invalid_param | 400 | Unknown parameter, bad value, bad/mismatched cursor, missing required filter. | Fix the request. Never retry as-is. |
| unauthorized | 401 | Missing, malformed or unknown key. | Check the Authorization header. |
| forbidden | 403 | Revoked key, ended trial, past-due or canceled subscription. | Resolve at /api/manage. |
| not_found | 404 | Unknown game_id, or a game that is not final yet; unknown route. | Check the id against /v1/games. |
| rate_limited | 429 | Per-minute limit exceeded. | Sleep Retry-After seconds, retry. |
| quota_exceeded | 429 | Monthly quota exhausted. | Wait for X-Quota-Reset or upgrade. |
| internal | 500 | Our fault. | Retry once with backoff; if it persists, send us the request id. |
Unknown query parameters are rejected, not ignored. This is deliberate: a typo like
seasn=2024 would otherwise silently return every season.Examples
400 — unknown parameter
{
"error": {
"code": "invalid_param",
"message": "unknown parameter: seasn",
"param": "seasn"
}
}400 — bad value
{
"error": {
"code": "invalid_param",
"message": "sport: must be one of: mlb, nfl, ncaaf, nba, nhl",
"param": "sport"
}
}400 — /v1/odds needs a filter
{
"error": {
"code": "invalid_param",
"message": "provide at least one of season, from/to, team, or game_id",
"param": "season"
}
}404
{
"error": {
"code": "not_found",
"message": "game not found"
}
}