Errors
When a request fails, the API returns an HTTP status code and a JSON body that explains what went wrong. A successful request always returns a 2xx status.
Error response format
Every error has the same shape:
{
"error": {
"message": "Invalid sportId parameter.",
"code": "INVALID_PARAMETER",
"details": "Invalid sportId: 99. Valid sportId's are: 10, 11, 12"
}
}| Field | Type | Description |
|---|---|---|
message | string | A short summary of the error. |
code | string | A machine-readable error code. See Error codes below. |
details | string | A longer explanation, usually with a hint on how to fix the request. |
Branch your error handling on code. We may reword messages at any time, but codes stay the same.
RATE_LIMITED errors carry two extra fields. See Rate limits.
HTTP status codes
| Status | Meaning |
|---|---|
400 | Bad Request: a parameter is missing or invalid. |
401 | Unauthorized: the API key is missing or invalid. |
402 | Payment Required: a payment for a subscription change failed. |
403 | Forbidden: your subscription doesn't include what you asked for. |
404 | Not Found: the endpoint or resource doesn't exist. |
429 | Too Many Requests: you hit your rate limit or your request quota. |
500 | Internal Server Error: something went wrong on our side. |
503 | Service Unavailable: the API is down for maintenance. |
Error codes
MISSING_API_KEY
Status: 401
The request has no API key.
Fix: Add your key as the apiKey query parameter, for example /v4/sports?apiKey=YOUR_API_KEY.
INVALID_API_KEY
Status: 401
The API key doesn't match any account.
Fix: Check that you copied the full key. If you refreshed your key recently, the old one no longer works. Use the new key from your account dashboard.
RESTRICTED_ACCESS
Status: 403
You're authenticated, but your subscription doesn't cover the request. Common causes:
message | Cause |
|---|---|
Subscription inactive | Your subscription has expired or been cancelled. |
Restricted sportId. / Restricted sport. | Your plan doesn't include this sport. |
Restricted tournament. | The tournament belongs to a sport your plan doesn't include. |
Restricted bookmaker(s). | Your plan doesn't include one or more of the requested bookmakers. |
No bookmakers available for the user. | Your plan has no bookmakers. |
No sports available for the user. | Your plan has no sports. |
No bookmakers with live access found. | The fixture is live, and none of your bookmakers include live odds. |
Restricted access to player props. | Your plan doesn't include player props for the requested bookmakers. |
Forbidden | Your IP address has been blocked. |
Fix: Check your plan on the account dashboard and upgrade or add the sports and bookmakers you need. If your IP address is blocked and you think that's a mistake, contact support.
With an inactive subscription you can still call /v4/account, so you can check your account status.
MISSING_PARAMETER
Status: 400
A required parameter is missing. The message names it, for example Missing fixtureId parameter.
Fix: Add the parameter named in message. The details field shows an example value.
MISSING_PARAMETERS
Status: 400
The request is missing a required combination of parameters. Refer to the documentation of the given endpoint to correct the sent parameters.
Fix: Add the parameters listed as required.
INVALID_PARAMETER
Status: 400
A parameter has a value the API can't accept. Common causes:
fixtureIddoesn't start withidorpn.sportIdisn't a known sport.detailslists the valid IDs.- A
tournamentIdsentry isn't an integer. - A bookmaker slug isn't recognised. Get the valid slugs from
/v4/bookmakers. - A
fromortovalue isn't a valid ISO 8601 timestamp. fromis afterto.- The date range is too wide: 10 days at most with only
sportId, and 2 days at most with no ID filter. statusIdisn't one of0(upcoming),1(live),2(finished) or3(cancelled).verbosityisn't an integer from 1 to 3.languageisn't a supported language code. Get the valid codes from/v4/languages./v4/odds-by-tournamentsgot more than one bookmaker./v4/odds-by-tournamentsgot more than 5 tournament IDs, or more than 3 for an exchange bookmaker./v4/historical-oddsgot an exchange bookmaker without exactly one bookmaker and oneoutcomeId.- An outcome ID or player ID isn't a number.
/v4/change-emailgot an email that is badly formatted or already in use.
Fix: Read details, which says which value is wrong and what's allowed.
MISSING_LANGUAGE
Status: 400
The endpoint needs a language, but you didn't send language and your account has no default language.
Fix: Add language (for example language=en), or set a default language on your account.
TOO_MANY_BOOKMAKERS
Status: 400
You asked /v4/historical-odds for more than 3 bookmakers.
Fix: Send 3 bookmakers or fewer, and split larger requests into several calls.
FIXTURE_NOT_FOUND
Status: 404
No fixture matches the fixtureId you sent, or no fixtures match your filters.
Fix: Check the fixture ID. Fixture IDs start with id or pn, for example id1200255561449509. If you used filters, try widening them.
NOT_FOUND
Status: 404
The endpoint doesn't exist, or the resource has no data yet. Common causes:
- The URL path is wrong. Check the spelling and the
/v4prefix. - No tournaments, participants or players exist for that
sportId. - The fixture has no scores or settlements yet. Try again later.
- No historical odds match your filters.
REQUEST_LIMIT_EXCEEDED
Status: 429
You've used all the requests in your plan for the current period. details shows your limit, for example You have exceeded your request limit of 100,000 requests.
Fix: Wait for your quota to reset at the start of the next period, or upgrade your plan. You can still call /v4/account to check your usage.
RATE_LIMITED
Status: 429
You called the same endpoint again too soon. See Rate limits.
Fix: Wait for the time given in retryMs, then retry.
PAYMENT_ERROR
Status: 402
A payment for a subscription change didn't go through.
Fix: Check your payment method in the billing portal and try again.
MAINTENANCE
Status: 503
The API is down for planned maintenance. details may say when it's expected back.
Fix: Retry later with a backoff.
INTERNAL_ERROR
Status: 500
Something went wrong on our side. Your request may have been valid.
Fix: Retry after a short wait. If the error keeps happening, contact support with the time of the request and the endpoint you called.
Rate limits
Each endpoint has a minimum wait between two calls from the same API key:
| Endpoint | Minimum interval |
|---|---|
/v4/historical-odds/v4/players | 5 seconds |
/v4/fixtures/v4/settlements | 2 seconds |
/v4/odds-by-tournaments/v4/account/v4/languages/v4/sports/v4/bookmakers/v4/markets/v4/tournaments/v4/participants/v4/scores | 1 seconds |
/v4/fixture/v4/odds | 0.5 seconds |
Each endpoint has its own limit, so calling /v4/odds doesn't count against /v4/fixtures. Some plans have higher limits.
A RATE_LIMITED response tells you how long to wait:
{
"error": {
"message": "You are being rate limited. Please wait before making more requests to this endpoint.",
"code": "RATE_LIMITED",
"details": "Please wait 0.42 seconds before making another request to /v4/odds.",
"retryAfter": "0.42 seconds",
"retryMs": 420
}
}| Field | Type | Description |
|---|---|---|
retryAfter | string | The wait time as readable text. |
retryMs | integer | The wait time in milliseconds. Use this in code. |
Rate limit or quota?
Both come back as 429. Check code to tell them apart:
RATE_LIMITEDmeans you're calling too fast. WaitretryMsand retry.REQUEST_LIMIT_EXCEEDEDmeans your quota for the period is used up. Retrying won't help until the quota resets.
Note
/v4/account doesn't count against your quota. /v4/historical-odds doesn't count against your quota either, but you can't call it once the quota is used up.
Handling errors
- Branch on
error.code, not on the HTTP status alone. Several codes share a status. - Don't retry
400,401,403or404errors unchanged. Fix the request first. - Retry
429 RATE_LIMITEDafterretryMs. - Retry
500and503with exponential backoff. - Log the full
errorobject. Itsdetailsfield usually says exactly what to fix.
