Soccer API guide
Build with soccer data
A practical guide to soccer identifiers, seasons, match events, timestamps, absences, freshness, and tournament structure. It applies across domestic leagues, club competitions, and national-team tournaments; where those formats differ, the guide says so explicitly.
Coverage and useful first calls
Soccer coverage is dataset-specific. A competition may have fixtures, scores, standings, clubs, and odds without also having a complete expected-goals or absence feed. Check the competition page and the live coverage map before promising a capability in your product.
Start with GET /v1/matches?sport=football&league=<league-key> or GET /v1/standings?sport=football&league=<league-key>. Use the league-code reference rather than guessing a competition key.
Canonical club, player, and match identifiers
Discover entities through list responses, then keep the returned canonical IDs for later detail calls. Do not join on display names: accents, abbreviations, transfers, nicknames, and two people with the same name all make text identity unsafe.
- Resolve the competition with its league key.
- Read matches, standings, teams, or players for that competition.
- Persist the returned IDs and use them in event, statistic, or head-to-head calls.
- Update the same record when later responses carry corrected values.
Season labels and historical data
Preserve the season or edition label returned by the API. Many European domestic seasons cross two calendar years, MLS follows a calendar-year rhythm, and tournaments may be organized around an edition rather than a continuous league season. Kickoff year alone is not a reliable season key.
Historical depth can differ between fixtures, standings, events, odds, and player statistics. Read the available season values for the route you are using instead of applying one global start year to every dataset. Plan access and source coverage are separate constraints: a plan can expose all available history without creating seasons a source does not hold.
Match events and soccer play-by-play
The soccer event timeline is the play-by-play surface for a match. The measured event taxonomy includes goals, cards, substitutions, and VAR-style incidents with match timing and available player or team context. It is a key-event feed, not a claim that every pass or possession is present.
Obtain the canonical match ID from the schedule or match list, then request that match’s events. Preserve event ordering and the supplied clock fields; do not reconstruct the timeline by sorting descriptions. A competition with no published event rows should show an unavailable state rather than events borrowed from another match.
Freshness and post-match corrections
There is no honest page-wide refresh interval. Live scores and in-match statistics can move quickly, while schedules, rosters, absences, settled history, and model outputs use different writer cadences. Use the response’s source or update metadata when it is present, and choose a polling interval for that dataset and match state.
Completed results and player rows can still be corrected after the final whistle. Re-fetch records that matter to settlement or auditability, and upsert by canonical ID so a correction replaces the same match, event, player, or club record rather than creating a duplicate.
Respect the plan headers and the rate-limit guidance. On a 429, back off rather than retrying at the same cadence.
UTC timestamps and match statuses
Match kickoff timestamps are UTC. Store the original timestamp for comparisons and convert it only at your presentation boundary. Keep the served season or tournament edition beside it; a local date is not a safe replacement for competition identity.
Read match status rather than inferring state from a score, kickoff time, or an empty field. Scheduled, live, finished, postponed, suspended, and cancelled matches require different product behavior. Preserve unfamiliar future status values and wait for a terminal status before irreversible settlement or final notifications.
Injuries, suspensions, and absences
Soccer availability records are absences, not one universal weekly injury designation. A record can describe an injury, suspension, or another stated reason, so preserve the source reason instead of converting every absence into an injury.
Absence coverage is competition-specific and has its own source date. A competition page with no dedicated absence feed is making a deliberate non-claim: do not infer availability from a missing lineup, and do not copy absences from another domestic league or tournament.
Tournament editions, phases, and cycles
A tournament can progress through qualifying, a league or group phase, and knockout rounds. National-team competitions can also span a multi-year cycle. Keep the served competition, edition, phase, round, and match status where available rather than forcing every tournament into a domestic table or deriving its edition from kickoff year.
A standings response may represent a group or league phase while later rounds are better represented by fixtures or a bracket. Model your UI around the phase supplied by the data, not around an assumption that every competition has one season-long table.
Clubs versus national teams
Domestic leagues, MLS, and the UEFA Champions League use clubs. AFCON, the CONCACAF Gold Cup, Copa America, the European Championship, and the UEFA Nations League use national teams. Both are participants in matches, but they do not share the same roster lifecycle, competition calendar, or transfer semantics.
Use the canonical participant ID returned for the competition. Do not assume a club crest, club-season roster, or domestic-league table exists for a national-team tournament simply because another soccer page can display one.