FOOTBALL API QUICK START
Quick startThree steps from no key to your first answer: get a key, make a call, read what comes back.
GET A KEY
Sign in with Google at footballapi.org/key. Your complimentary key appears at once and is shown only then, so keep it somewhere safe. It starts fa_live_ and reads this season's Premier League, 50 calls a day.
MAKE THE FIRST CALL
Every call is a GET to https://api.footballapi.org/v1 with your key in the X-API-Key header. Start with yesterday's results:
curl "https://api.footballapi.org/v1/results/yesterday?competition=premier-league" \ -H "X-API-Key: your key"
import requests
r = requests.get(
"https://api.footballapi.org/v1/results/yesterday?competition=premier-league",
headers={"X-API-Key": "your key"},
)
print(r.json()["data"])const res = await fetch("https://api.footballapi.org/v1/results/yesterday?competition=premier-league", {
headers: { "X-API-Key": "your key" },
});
const { data } = await res.json();
console.log(data);$ch = curl_init("https://api.footballapi.org/v1/results/yesterday?competition=premier-league");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["X-API-Key: your key"],
]);
$data = json_decode(curl_exec($ch), true)["data"];
print_r($data);READ THE ANSWER
Every answer is JSON with two parts. data holds the rows, or one object for a single match or table. meta holds the count, the paging and a request_id to quote if you write to support. On the complimentary key, meta.your_key_reads says what the key reads.
{ "data": [ { "match_id": "mt_95kf4jw9a", "competition": "premier-league", "country_name": "England", "competition_name": "Premier League", "season_start_year": 2026, "kickoff_utc": "2026-10-19T19:00:00Z", "kickoff_date": "2026-10-19", "kickoff_local_date": "2026-10-19", "kickoff_local_time": "19:00", "match_status": "finished", "home_club_id": "cl_4x2bczxvv", "home_club_name": "Tottenham", "away_club_id": "cl_frt0n2e46", "away_club_name": "Coventry", "home_goals": 3, "away_goals": 1, "full_time_result": "home", "half_time_home_goals": 1, "half_time_away_goals": 0, "half_time_result": "home", "stoppage_minutes": null, "is_kickoff_rescheduled": false, "elapsed_minutes": null, "home_league_position": 20, "away_league_position": 16, "away_travel_km": 135, "ground_name": "Tottenham Hotspur Stadium", "city_name": "London", "latitude": 51.604444444444, "longitude": -0.066388888888889, "location_precision": "ground", "daylight_minutes": 630, "sun_elevation_deg": -19.3, "public_holiday": null, "kickoff_temperature_c": null, "kickoff_rain_mm": null, "kickoff_wind_ms": null, "attendance": 60913, "referee_name": "Andrew Madley", "regular_time_home_goals": 3, "regular_time_away_goals": 1, "regular_time_result": "home", "extra_time_home_goals": null, "extra_time_away_goals": null, "shootout_home_goals": null, "shootout_away_goals": null, "club_figures": { "home": { "xg": 0.9, "xg_estimate": 1.66, "shots": 16, "shots_on_target": 5, "corners": 4, "fouls": 15, "yellow_cards": 1, "red_cards": 0, "possession_pct": 66 }, "away": { "xg": 0.83, "xg_estimate": 1.34, "shots": 12, "shots_on_target": 1, "corners": 4, "fouls": 14, "yellow_cards": 3, "red_cards": 0, "possession_pct": 34 } } } ], "meta": { "count": 2, "page": 1, "per_page": 2, "total": 14446, "total_pages": 7223, "next_page": 2, "prev_page": null, "next_cursor": "uAIfpUPNnzUavfl_M-pg_XaOxXFDwItzDe9-0s_bm5TCAvcK_roiyZ88DdhFqRM1ovRYfw", "request_id": "req_dc5191a88e65250a" } }
Matches, clubs and grounds carry our own ids, mt_, cl_ and gd_ and 9 characters. They never change, so you can store them and pass them back to any endpoint. Times are UTC, written out with a Z.