The free key reads yesterday again: our one-month trial of today on the free key has finished. Read the changelog

Historical data

What is in the archive, and how to read the coverage figures.

Scope

1,693,122 matches across 1,381 competitions in 171 countries, over ten seasons. Every plan reaches every competition. Plans differ by how far back you can read and whether the prices come with it, never by coverage; the free key reads yesterday, as one whole day.

What a row carries

Beyond the scoreline: both clubs’ league position at kickoff, how far the away side travelled, the ground with its coordinates and city, the half-time score, added time (stoppage_minutes, 1 to 15: a figure sent as the match minute, 98 for 90+8, is read as 8, and any other figure above 15 is left out as not added time), and whether the kickoff was moved. Then the exchange market recorded at kickoff.

Coverage is published, not implied

Not every field exists on every match, and we would rather you had the number than found out later. Every competition and every season carries a coverage block giving the fill rate field by field: for the rows you are actually asking about, rather than an average over everything.

That is the figure to build against. A field can be near complete in one competition and absent from another, so a single archive-wide percentage would be the wrong number in both directions. Read the coverage on what you are querying and you will know exactly what you are getting.

Every field is in the schema already. A field that is empty on a match comes back as null rather than being missing from the response, so nothing on your side has to change as coverage grows.

Ids do not move

A match_id or team_id you store today resolves to the same thing next year. Ids come from the source rather than being generated at import, so a rebuild maps everything back to the same numbers. That is a promise, not an implementation detail: it is in the terms.

Freshness

The archive rebuilds nightly. Every response carries data_as_of, so you always know how old the answer is rather than assuming.