Skip to content
Scores and results

Football scores and results API for score centres

The scores feed is the workhorse behind a match-day score centre: one request, no parameters, a snapshot of current match states and results across the competitions your account can see. This page explains what the snapshot is good for, how it differs from the live and recent-results feeds, and how to build a score centre that stays accurate without overspending.

Primary endpoint

GET/api/v1/football/scores

No query parameters.

Access: All plans; Starter limited to your five saved leagues. Header: X-API-Key.

Illustration of a grid of blank score tiles grouped under competition headers, with no team names or real scores.
A score centre groups supplied match states by competition; the tiles are deliberately blank.
01

The everyday score snapshot

If you could only call one football endpoint on a match day, it would probably be this one. The scores feed takes no parameters and returns scores and results for the current window across the competitions your account is entitled to. It covers matches not yet started, in progress and finished, so a single response can populate the whole of a score centre: fixtures still to come at the top of the page, games in play in the middle, full-time results below.

It sits between two narrower feeds. The live feed returns only matches the source currently reports as in play, and is cached for about fifteen seconds. Recent results returns finished matches for a chosen day in the past week and is cached for about five minutes. The scores feed, cached for about thirty seconds, is the general-purpose view in the middle, and for many products it is the only score feed they need.

02

Snapshot, envelope and source structure

Each response is a snapshot. The data object contains the source structure as supplied, and the meta object records which feed answered, when it was fetched in UTC, the cache time and the feed's qualification. We have not published a normalised schema for scores, and we do not rename source attributes. Fields that came from the source as attributes keep their at-sign prefix, and every identifier is a string.

That design has a practical consequence for your code. Write a small mapping layer that reads the attributes you need from a real response, and keep it in one place. When the source adds an attribute, your mapping keeps working and you can choose to use the new value. When an attribute you rely on is missing from a particular match, the mapping should return nothing for it rather than throwing, because missingness is normal across a wide range of competitions.

The meta timezone note applies too. fetchedAt is UTC. Match dates and times inside data are as supplied and not necessarily UTC, so do not label them as such until you have confirmed the convention for the competitions you show.

Score centre data flowFlow: one server request to scores, group matches by competition as supplied, compare with the previous snapshot by match ID, publish to readers from your own cache.01GET /scoresno parameters02Groupby competition03Diff by IDstring keys04Publishyour cache
Score centre data flow. One request feeds the whole page; the comparison step is where changes become visible.
03

Grouping matches the way readers scan

Readers look for their competition first and their team second. A score centre that lists every match in one long sequence sorted by time is hard to use on a busy Saturday. Group by competition as the source structure suggests, and order the groups in a way that makes sense for your audience: domestic leagues first for a national publisher, followed teams first for a personalised app.

Inside each group, order by supplied kick-off time and keep finished matches visible until the end of the day. Readers who arrive late want to see what they missed, and removing a result the moment it is final makes the page feel as if something broke.

  • Group by the competition the source associates with each match.
  • Order groups for your audience, not alphabetically by default.
  • Within a group, order by supplied time; keep finished matches until the day ends.
  • Show the time your server last refreshed the snapshot.
04

A minimal score centre poller

The Python example polls the scores feed on a thirty-second rhythm, matching the cache, and writes the envelope to your own store only when the body changes. Your web pages read that store. Readers never call the API, the key never leaves your server, and a page with ten thousand visitors costs the same number of requests as a page with ten.

Note the slower retry after an error. A 429 response includes a Retry-After header; honour it. A 502 or 504 response means the upstream request failed or timed out, and the right reaction is a calm retry with backoff rather than a burst of parallel attempts.

Python: poll scores at the cache intervalpython
import os, time, json, requests

URL = "https://footballapi.net/api/v1/football/scores"
H = {"X-API-Key": os.environ["FOOTBALLAPI_KEY"]}
last = None

while True:
    r = requests.get(URL, headers=H, timeout=20)
    if r.status_code == 429:
        time.sleep(int(r.headers.get("Retry-After", "60")))
        continue
    if not r.ok:
        time.sleep(60)
        continue
    if r.text != last:
        last = r.text
        save_snapshot(r.json())  # your store; data and meta intact
    time.sleep(30)
05

Respecting match states

A score is only meaningful alongside its match state. A two-one scoreline means one thing at half-time and another at full time, and something else again if the match was abandoned. Display the state the source supplies next to every score, and never infer one. In particular, do not treat a match as finished because its scheduled duration has passed. Stoppage time, delays and suspensions all extend matches beyond the clock.

Corrections happen. A goal can be credited and then removed, or a result amended after review. Because each request is a fresh snapshot, your page will pick up the correction on the next refresh, provided you replace stored values with new ones rather than only ever appending changes. Design notifications cautiously for the same reason: if you alert readers to a goal, be prepared for the next snapshot to disagree.

06

Quiet days and empty responses

International breaks, mid-season pauses and the summer all produce days with few or no matches in the competitions you follow. A response with little in it is not an error. Your page should look deliberate when that happens: say there are no matches today in your followed competitions and point to the upcoming feed's next match day, rather than showing an empty frame with a spinner.

Equally, an unexpected empty response on a busy day is worth investigating. Check the HTTP status, the meta qualification value and your account entitlement before assuming the source has nothing. A Starter account, for instance, only sees its five saved leagues, so a match in a sixth league is correctly absent.

07

Plan scope and match-day cost

Scores is filtered by league on Starter. At EUR 29 a month you receive only your five saved leagues, filtered on our side before the response reaches you. Growth at EUR 99 and Pro at EUR 249 receive the available package competitions. Coverage still varies by competition and date on every plan, and the feed qualification is sample received: a response has returned, while final freshness, coverage and licensing checks are pending.

Polling every thirty seconds for a full day is 2,880 requests, comfortably inside the Starter inclusion of 5,000 successful requests per UTC day. Most products poll that often only around match windows and much less otherwise. Extra successful requests beyond the inclusion cost EUR 0.002 each on the monthly EUR invoice; failed and denied requests are not billed.

08

When one feed is not enough

As a score centre grows, it usually adds detail pages. A reader taps a match and expects statistics, line-ups and a timeline. The scores feed is the entry point for that journey but not the destination. The match detail service on Growth and Pro returns a focused record for one match using its static identifier and league, and the competition match statistics feed returns statistics for many matches at once. Plan your data model so that the identifiers you take from scores can be used to reach those services without lookups by name.

We also run a separate scores-new service that groups matches by competition. Both are published; evaluate each against your product before deciding which to build on.

Questions developers ask

Does the scores feed take any parameters?
No. One request returns the current window across the competitions your account can see.
How is scores different from live?
Live returns only matches in play and is cached for about fifteen seconds. Scores covers not started, in progress and finished matches, cached for about thirty seconds.
How often should I poll?
Around the thirty-second cache interval during match windows, and much less often otherwise.
Why is a match missing on my Starter account?
Starter responses are filtered to your five saved leagues. Matches in other competitions are correctly absent.
Are scores ever corrected?
Yes, the source can amend scores and results. Replace stored values with each new snapshot so corrections appear.
Is this a streaming feed?
No. It is REST. Each request returns a snapshot; streaming services are separate and need their own activation.

Check the plan before you write the integration.

Starter EUR 29, Growth EUR 99, Pro EUR 249 per month. No free trial. No VAT currently charged.