Football (soccer) results API Football results, already shaped.

1M+ soccer matches since 2011 — fixtures with half-time and full-time scores across 3,742 competitions in 158 countries, each one the same clean JSON object. A plain REST API, and a free key to start.

  • 1,000 free requests a day
  • Every endpoint, results since 2011
  • Updated several times a day
  • Best-effort, no SLA, stated plainly
The match
data[0].scoreobject

halftime and fulltime, as integers or null. Never an empty string.

Hover or tap the scoreboard. Each field is one key.

The object
GET /matches?competition=england-england-premier&status=finished&per_page=2 200 OK
{
"data": [
{
"id": 3821517,
"kickoff": "2026-11-01T16:30:00+00:00",
"status": "finished",
"competition": {
"id": "england-england-premier",
"name": "England Premier", "country": "England"
},
"home_team": { "id": "liverpool", "name": "Liverpool" },
"away_team": { "id": "arsenal", "name": "Arsenal" },
"score": {
"halftime": { "home": 0, "away": 1 },
"fulltime": { "home": 0, "away": 1 }
}
},
"… 1 more"
],
"meta": {
"api": "archive", "version": "v1",
"generated_at": "2026-11-02T09:56:02+00:00", "page": 1,
"per_page": 2, "total": 5786, "last_page": 2893
}
}
In the archive
  • England League 28,616 matches
  • England League 18,557 matches
  • Italy Serie D7,577 matches
  • USA MLS6,545 matches
  • Italy Serie B6,498 matches
  • Brazil 26,072 matches
  • Brazil 16,053 matches
  • Germany 35,919 matches
  • France 25,659 matches
  • Netherlands 25,631 matches
  • Spain Segunda Division5,621 matches
  • France 15,587 matches
  • Portugal 25,581 matches
  • Argentina 25,397 matches
  • Colombia 15,307 matches
  • Spain Tercera Division RFEF5,290 matches
  • Japan 2 League5,200 matches
  • Japan J League5,143 matches
1,090,118
Matches since 20111,052,020 with a full-time score
3,742
Competitions
158
Countries
30,998
Teams

Read from GET /stats · refreshed every 6 hours · last sync 22 min ago

01What you get

Results you can build on, without cleaning them first.

One archive, one schema, one key. What follows is what it does for you — and, just as plainly, what it does not.

01

History back to 2011

1,090,118 matches from 2011 to this week, the finished ones carrying half-time and full-time scores. Backfill a stats page or a model in one pass instead of scraping season by season.

Grouped by calendar yearUpdated this week
02

Coverage past the top flights

Lower tiers, cups, youth and women's football as well as the leagues everyone covers. Check how deep a competition goes before you build on it.

Matches per country, top 5 of 158
  • England86,664
  • Spain57,830
  • Germany52,277
  • Italy41,246
  • Brazil37,961
Check a competition
03

One consistent schema

The same match object from every endpoint that returns one. Match ids never change, scores are integers or null — never an empty string standing in for a number.

finished
"fulltime": { "home": 3, "away": 1 }
scheduled
"fulltime": { "home": null, "away": null }
04

Kickoffs in UTC

Every kickoff is ISO-8601 in UTC, and date filters are UTC days. No guessing which timezone a feed meant.

2026-11-01Date T16:30:00Time +00:00UTC, always
05

A plain REST API

GET and JSON. One header carries your key, page and per_page walk a list, and the docs have curl, JavaScript and Python to paste.

  • GET/matches
  • GET/competitions/{id}/matches
  • GET/teams/{id}/matches
  • GET/stats
06

Honest about its limits

Updated several times a day and run best-effort, with no SLA dressed up as one. The docs say where coverage is thin.

Best-effort · several updates a day · no SLA

In the archive

  • Fixtures and results
  • Half-time and full-time scores
  • Competitions and teams
  • Kickoffs in UTC, since 2011

Not in the archive

  • Prices of any kind
  • Predictions
  • Lineups and player names
  • Player statistics or xG
02Your first call

One header, one GET.

Four steps from sign-up to JSON. Call from your server — a key in browser code is a key anyone can read.

  1. 01Create a free account
  2. 02Confirm your email
  3. 03Make a key in the console
  4. 04Send it asX-API-Key
# Finished England Premier matches, 2 per page
curl -G "https://admin.thefootballsignal.com/football-scores/v1/matches" \
-d competition=england-england-premier \
-d status=finished \
-d per_page=2 \
-H "X-API-Key: $GOALSCHEMA_KEY"
# Quota left today, from the response headers
curl -s -o /dev/null -D - \
"https://admin.thefootballsignal.com/football-scores/v1/stats" \
-H "X-API-Key: $GOALSCHEMA_KEY" | grep -i x-quota
// Node 18+: finished England Premier matches, 2 per page
const url = new URL(
"https://admin.thefootballsignal.com/football-scores/v1/matches"
);
url.search = new URLSearchParams({
competition: "england-england-premier",
status: "finished",
per_page: "2",
});
const res = await fetch(url, {
headers: { "X-API-Key": process.env.GOALSCHEMA_KEY },
});
const { data, meta } = await res.json();
# pip install requests
import os, requests
r = requests.get(
"https://admin.thefootballsignal.com/football-scores/v1/matches",
params={"competition": "england-england-premier",
"status": "finished",
"per_page": 2},
headers={"X-API-Key": os.environ["GOALSCHEMA_KEY"]},
)
matches = r.json()["data"]

On every keyed response

X-Quota-Remaining
Requests left today
X-RateLimit-Remaining
Requests left this minute
X-Plan
explorer, developer or business
Retry-After
Sent only with a 429
200 OK 5,786 matches · page 1 of 2,893 Cache-Control: private, max-age=60
03Pricing

Free to start. Paid when it's in production.

Every plan reaches the whole archive. Plans differ in how many requests you can make, and in support.

Free

$0
free key, with an account
Requests a day1,000
  • 60 requests a minute
  • The full archive: every endpoint, results since 2011
  • Community support
Get a free key

Developer

Self-serve
$29
per month
Requests a day25,000
  • 300 requests a minute
  • The full archive
  • Email support
Get Developer

Business

Custom
agreed by email
Requests a dayAgreed
  • The full archive
  • Daily and per-minute limits sized to your traffic
  • Priority email support
Email us
Payments by Polar, merchant of record. Sales tax and VAT handled Cancel anytime from the console At the limit: a 429 with Retry-After Compare plans
04Questions

Questions, answered plainly.

Anything else goes to contact@goalschema.com. The docs cover authentication, errors and where coverage is thin.

Football results: fixtures with half-time and full-time scores, plus the competitions and teams they belong to, from 2011 onward, compiled from third-party sources. No prices, lineups or player statistics.

Finished matches usually appear within a few hours of full time. Updates run several times a day, on a best-effort basis.

Yes. You can display it in your own products, commercial ones included. You can't resell, mirror or republish it as a dataset, feed or API.

No, on any plan. The service is best-effort, with no promised uptime.

You get a 429 with Retry-After, and an error code that says whether you hit the per-minute limit or the daily quota. The day resets at 00:00 UTC. Caching on your side means you'll rarely reach it.

Developer is self-serve: create a free account, confirm your email, then upgrade from Billing in the console. Polar, the merchant of record, takes payment and handles sales tax or VAT. Cancel anytime; the plan runs to the end of the paid month.

Free key, with an account

Kick off with a free key.

The full archive and every endpoint, 1,000 requests a day. Upgrade when it's in production.