Error codes
Every error returns {"success": 0, "error": {…}} with the HTTP status that matches. The code is stable and safe to branch on; message is written for a human reading a log. param names the offending input where one applies, request_id is worth quoting if you write in, and doc_url points at the entry on this page.
{
"success": 0,
"error": {
"type": "invalid_request",
"code": "invalid_time_window",
"message": "The window may span at most 24 hours.",
"param": "end_time",
"doc_url": "https://5dollarfootballapi.com/docs/errors#invalid_time_window",
"request_id": "req_0xyuw9pv3baf"
}
}
Jump to a code
Authentication
HTTP 401missing_api_key
type: authentication_error
No key reached us.
- Usually because
- The header was absent, spelled differently, or dropped by a proxy or a spreadsheet add-on that cannot send headers.
- What to do
- Send
Authorization: Bearer fb_live_…, orX-API-Key: fb_live_…if the client makes that easier. Tools that cannot set headers at all — Google Sheets' IMPORTDATA, for one — cannot call this API; use Apps Script instead.
invalid_api_key
type: authentication_error
A key arrived but does not match a live key.
- Usually because
- Revoked, mistyped, or a key from a different account. Keys are shown once at creation and only their hash is stored, so a truncated copy fails here rather than at creation.
- What to do
- Check the prefix against the one in your dashboard. If it does not match, issue a new key — we cannot recover the old one.
expired_api_key
type: authentication_error
The key was valid and has passed its end date.
- Usually because
- Trial and evaluation keys are issued with an end date; the account behind them is unaffected. Keys without one never expire.
- What to do
- The message names the date it ended. Create a key from your dashboard, or reply to the email the trial key came in and we will sort you out.
Plan limits
HTTP 403insufficient_plan
type: permission_error
The key is valid; this resource is outside its plan.
- Usually because
- A competition your plan does not cover, include=odds on a fixture list below Pro, odds history below Ultra, a bookmaker other than Bet365 below Ultra, or a date older than your plan's history window.
- What to do
- The message names which of those it was. We return this rather than an empty list on purpose — an empty array is indistinguishable from "no matches that day", and silently returning nothing is how an import ends up with holes nobody notices.
Request parameters
HTTP 400invalid_time
type: invalid_request
`start_time` or `end_time` is not a unix timestamp.
- Usually because
- An ISO date string, milliseconds instead of seconds, or a formatted date from a spreadsheet cell.
- What to do
- Send whole seconds since the epoch, UTC. Milliseconds are the common one — divide by 1000.
invalid_time_window
type: invalid_request
The window is backwards, or spans more than 24 hours.
- Usually because
- `end_time` at or before `start_time`, or a range wider than a day on `/v1/fixtures`.
- What to do
/v1/fixturesanswers a bounded window — at most 24 hours — so that it can never turn into a range scan. For a longer stretch, walk it a day at a time: call again withstart_timemoved forward 86400 seconds. The window is[start_time, end_time), so consecutive days share no fixture and nothing is counted twice.end_timeis optional and defaults tostart_time+ 24h, so paging usually means changing one number.
invalid_status
type: invalid_request
Unrecognised `status`.
- Usually because
- A value outside the four we accept.
- What to do
- Use
all,scheduled,liveorfinished.liveignores the time window and returns everything in play right now.
invalid_order
type: invalid_request
Unrecognised `order` on a fixture list.
- Usually because
- A value other than `asc` or `desc` — often a sort field name, or a direction spelled out.
- What to do
- Use
desc(the default, newest kickoff first) orasc. Only/v1/leagues/{id}/fixturesand/v1/teams/{id}/fixturestake it; the order is always by kickoff, never by another field.
invalid_include
type: invalid_request
Unrecognised `include`.
- Usually because
- A typo, or a name from another provider's API.
- What to do
- Use any comma-separated mix of
odds,eventsandstats. Adding an include capsper_pageat 50 to bound the payload.
invalid_market
type: invalid_request
Unrecognised `market` on an odds endpoint.
- Usually because
- A market this bookmaker does not carry, or a name from elsewhere.
- What to do
- Bet365 carries
1x2,asian,goalline,corner, their_halfvariants, pluscorner_asian,cards,cards_asianandbtts. Every other bookmaker carries1x2,asian,goallineandcorner.
invalid_bookmaker
type: invalid_request
Unrecognised bookmaker slug.
- Usually because
- A display name rather than the slug, or a book we do not carry.
- What to do
- Call
GET /v1/bookmakersfor the current list of slugs.bookmakertakes exactly one.
invalid_bookmakers
type: invalid_request
One or more slugs in a `bookmakers` list are unrecognised.
- Usually because
- A typo in a comma-separated list; the message names the offender.
- What to do
- Check the list against
GET /v1/bookmakers.bookmakers(plural) takes several, comma-separated.
invalid_type
type: invalid_request
Unrecognised `type` on standings.
- Usually because
- A value outside the three tables we build.
- What to do
- Use
total(the points table, the default),cornerorcard.
invalid_esports
type: invalid_request
`esports` is not a boolean.
- Usually because
- Something other than true/false.
- What to do
- Send
trueorfalse. It defaults to false, which is real football; true returns esoccer instead, never both.
invalid_lang
type: invalid_request
Unrecognised `lang` code.
- Usually because
- A locale we do not translate into, or a full locale where a short code is expected.
- What to do
- The message lists every supported code. Omit
lang, or passen, for English. A name with no translation falls back to English on that row rather than coming back empty, so a response is never partly blank.
invalid_country
type: invalid_request
Unrecognised `country` code on /v1/leagues.
- Usually because
- A code that is not one /v1/countries lists — a country name, a three-letter code, or a confederation acronym such as UEFA.
- What to do
- Pass the
codefrom /v1/countries: ISO 3166-1 alpha-2 (DE, BR), GB-ENG / GB-SCT / GB-WLS / GB-NIR for the home nations, or a region code (EUROPE, ASIA, AFRICA, AMERICAS, OCEANIA, WORLD) for continental and international competitions. Case does not matter.
missing_parameter
type: invalid_request
A required parameter is absent.
- Usually because
- Usually `league` on `/v1/standings`, or `market` on the odds history endpoint.
- What to do
- The message names it. Required parameters are marked in the endpoint reference.
unknown_parameter
type: invalid_request
A parameter we do not support was sent.
- Usually because
- Habits from another API — `date`, `from`, `to`, `team` and `live` are the usual ones.
- What to do
- The message suggests the equivalent. We reject unknown parameters rather than ignoring them: a filter that is silently dropped returns a full result set that looks exactly like a filtered one, and that quietly corrupts whatever you are building.
Moved
HTTP 301league_moved
type: moved
That league id was retired when two duplicate rows were merged; the survivor is in `error.canonical_id` and in the `Location` header.
- Usually because
- The feed occasionally opens a second row for a competition (a rename, a split season). We merge them, moving every fixture to the surviving id, so the retired id no longer owns anything.
- What to do
- Most HTTP clients follow the 301 automatically and you get the canonical league's data with its real id in the payload. Update the id you store; the redirect is permanent and costs a request each time.
Not found
HTTP 404fixture_not_found
type: invalid_request
No fixture with that id.
- Usually because
- An id from another provider, or one outside our coverage.
- What to do
- Fixture ids come from
/v1/fixturesand are ours — ids from other football APIs will not resolve here.
league_not_found
type: invalid_request
No league with that id.
- Usually because
- Same as above, or a guessed id.
- What to do
- Look ids up with
GET /v1/leagues, or in the league coverage reference.
team_not_found
type: invalid_request
No team with that id.
- Usually because
- An id from elsewhere, or a team outside our coverage.
- What to do
- Team ids appear on every fixture row under
teams.home.idandteams.away.id.
season_not_found
type: invalid_request
That league has no such season.
- Usually because
- A season the feed does not define for this competition — coverage varies by league, and not every one has a season record.
- What to do
GET /v1/leagues/{id}lists the seasons that exist, newest first. Omitseasonto get the newest with fixtures.
standings_not_available
type: invalid_request
That competition has no league table.
- Usually because
- Cups, play-offs and some smaller competitions have no table to build — and where the feed's data is incomplete enough that a computed table could be wrong, we decline rather than publish a table that looks authoritative and is not.
- What to do
- Nothing to change in the request. Fixtures, results, statistics and odds for the competition are unaffected; only the table is missing.
GET /v1/leagues/{id}reports whether a competition has standings at all.
resource_not_found
type: invalid_request
The addressed resource does not exist.
- Usually because
- The generic 404, used where a more specific code does not apply.
- What to do
- Check the path and the id against the endpoint reference.
Rate limits
HTTP 429too_many_requests
type: rate_limit_error
The window's allowance is spent.
- Usually because
- More calls than the plan permits inside one window — 60 an hour on Free, 10 a minute on Pro, 40 a minute on Ultra.
- What to do
- Read
Retry-Afteron the 429 and wait that many seconds; every successful response also carriesX-RateLimit-RemainingandX-RateLimit-Reset, so a client can slow down before it hits this rather than after. Finished matches never change, so caching what you already pulled removes most repeat traffic.
Server
HTTP 500internal_error
type: api_error
The failure is ours, not yours.
- Usually because
- A bug or an upstream problem. Nothing about the request needs changing.
- What to do
- Retry with a short backoff. If it persists, send us the
request_idfrom the response — it points straight at the log line.
Still stuck?
Send the request_id
from the response to support.
It points at the exact log line, which is faster than describing what happened.