Errors
All errors share a single envelope:
{
"error": "human-readable message",
"code": "machine_code",
"request_id": "req_abc123"
}
request_id is always present. Quote it whenever you contact support.
HTTP status codes
| Status | Meaning | What to do |
|---|---|---|
| 200 | Success. | — |
| 400 | Malformed request — missing required path/query param, bad JSON. | Fix the request. The error message points at what's wrong. |
| 401 | API key missing, malformed or revoked. | Verify the key. See Authentication. |
| 403 | Key valid but lacks the required scope. | Re-issue with broader scopes or use a different key. |
| 404 | Resource not found. | Confirm the ID with listMatches / listLeagues. |
| 422 | Reserved for future use (validation that goes beyond malformed). | — |
| 429 | Rate limit exceeded. | Honour Retry-After. See Rate Limits. |
| 500 | Server error on our end. | Retry with backoff. If it persists, contact support. |
| 503 | Component unhealthy (only on /readyz). | Pause and retry. We're failing over. |
Error codes
The code field, when set, takes one of these values:
| Code | HTTP | Meaning |
|---|---|---|
invalid_api_key | 401 | Key absent / malformed / revoked. |
insufficient_scope | 403 | Key lacks the scope needed for this endpoint. |
not_found | 404 | Resource doesn't exist. |
rate_limited | 429 | See Rate Limits. |
internal_error | 500 | Generic server error. |
service_unavailable | 503 | Downstream component down (Postgres / Redis / NATS). |
Retry strategy
For idempotent (read-only) requests, retry on 429, 500, 503 with
exponential backoff and jitter:
import time, random, requests
def get_with_retry(url, headers, max_attempts=5):
delay = 0.5
for attempt in range(max_attempts):
r = requests.get(url, headers=headers, timeout=10)
if r.status_code < 500 and r.status_code != 429:
return r
retry_after = int(r.headers.get('Retry-After', 0))
wait = max(retry_after, delay) + random.random() * 0.25
time.sleep(wait)
delay = min(delay * 2, 30)
r.raise_for_status()
Permanent failures
These won't be solved by retrying — fix the request instead:
400— bad input.401/403— auth problem.404— wrong ID.
Reporting bugs
If you believe the API misbehaved, open a ticket from the support page with:
- The
request_idfrom the response. - The exact request (URL + headers, redacting the API key).
- The full response body and status code.
- The expected behavior.