GUIDE

World Cup 2026 Fixtures API: All 104 Matches in JSON

Complete World Cup 2026 fixtures via REST API: 104 matches, kickoff times in UTC, host cities, stadiums, and Python + JavaScript code examples.

6 min read

The 2026 FIFA World Cup features the largest schedule in the tournament's history: 104 matches across 12 groups, 7 knockout stages, and 16 host cities in three countries. That is a lot of data to keep synchronised in your app.

This guide shows you exactly how to pull the full fixture list via REST API, what's in each fixture object, and how to handle the new 48-team format quirks (Round of 32, placeholder slots, third-place qualification).

The 2026 World Cup fixture structure at a glance

Knowing the schema saves you confused calls later:

  • 72 group-stage matches — 12 groups × 6 matches each (each team plays 3 group games)
  • 16 Round of 32 matches — the new round introduced for the 48-team format
  • 8 Round of 16 matches
  • 4 quarter-finals
  • 2 semi-finals
  • 1 third-place playoff
  • 1 Final — MetLife Stadium, July 19, 2026

Total: 104 matches between June 11 and July 19, 2026.

One endpoint, full schedule

You don't need 7 endpoints to fetch the schedule. One filtered call to /football/matches returns the lot:

curl 'https://api.thestatsapi.com/api/football/matches?competition_id={COMPETITION_ID}&season=2026&per_page=104' \
  -H 'Authorization: Bearer YOUR_API_KEY'

The competition_id={COMPETITION_ID} placeholder scopes the response to the 2026 FIFA World Cup — look up the actual ID via GET /football/competitions?search=world%20cup. season=2026 is technically redundant for the next World Cup, but it future-proofs your code when the 2030 edition arrives.

What's in a fixture object

Each fixture has roughly this shape:

{
  "id": "mt_010249745",
  "match_number": 1,
  "competition_id": "{COMPETITION_ID}",
  "season": 2026,
  "stage": "group-stage",
  "group": "A",
  "kickoff_utc": "2026-06-11T19:00:00Z",
  "status": "scheduled",
  "home": { "id": "tm_mex", "name": "Mexico", "slug": "mexico" },
  "away": { "id": "tm_cmr", "name": "Cameroon", "slug": "cameroon" },
  "venue": {
    "stadium": "Estadio Azteca",
    "city": "Mexico City",
    "country": "MX",
    "capacity": 87523
  }
}

A few important fields worth highlighting:

  • match_number — FIFA's official match numbering (1-104). Useful for displaying "Match 1" on a match-centre page.
  • kickoff_utc — always in UTC. Convert client-side using Intl.DateTimeFormat for user-local times.
  • home / away — for knockout fixtures where the qualified team isn't known yet, this returns a positional placeholder like { "type": "placeholder", "label": "Winner Group A" }.
  • stage — one of group-stage, round-of-32, round-of-16, quarter-finals, semi-finals, third-place, final.

Filtering down to what you actually need

The 104-match payload is small enough to fetch whole, but you'll usually want a slice:

const COMPETITION_ID = 'YOUR_COMPETITION_ID'; // look up via GET /football/competitions?search=world%20cup

// Just Group A matches
const groupA = await fetch(`${BASE}/football/matches?competition_id=${COMPETITION_ID}&group=A`, { headers });

// Just knockout matches
const knockouts = await fetch(`${BASE}/football/matches?competition_id=${COMPETITION_ID}&stage=round-of-32`, { headers });

// Just Argentina's matches
const argentina = await fetch(`${BASE}/football/matches?competition_id=${COMPETITION_ID}&team=argentina`, { headers });

// Just matches at Estadio Azteca
const azteca = await fetch(`${BASE}/football/matches?competition_id=${COMPETITION_ID}&venue_id=mexico-city`, { headers });

// Just matches on opening day
const day1 = await fetch(`${BASE}/football/matches?competition_id=${COMPETITION_ID}&date=2026-06-11`, { headers });

Each filter is a query parameter. Combine as needed.

Handling Round of 32 placeholders

The Round of 32 is new for the 48-team format. Eight third-placed teams advance alongside the 12 group winners and 12 runners-up. Until the group stage finishes, the API returns positional placeholders:

{
  "home": { "type": "placeholder", "label": "Winner Group A" },
  "away": { "type": "placeholder", "label": "3rd Place B/E/F" }
}

Once the group stage resolves, the same fixture object updates with the real teams:

{
  "home": { "type": "team", "id": "tm_mex", "name": "Mexico" },
  "away": { "type": "team", "id": "tm_jpn", "name": "Japan" }
}

In your UI: render the placeholder label until type === "team", then swap in the team component. A simple ternary handles it.

Converting kickoff times to user-local

A common mistake is to display UTC times to fans who want to see "8pm local". JavaScript's built-in Intl.DateTimeFormat does all the heavy lifting:

function formatKickoff(utcString) {
  const date = new Date(utcString);
  const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
  return date.toLocaleString(undefined, {
    weekday: 'short',
    month: 'short',
    day: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
    timeZoneName: 'short',
  });
}

formatKickoff("2026-06-11T19:00:00Z");
// "Thu, Jun 11, 03:00 PM EDT" (or whatever the user's timezone is)

We also ship a free Match Kickoff Time Converter tool that does this without any API call — useful as a public utility on a match page.

Python: build a quick fixtures table

import requests
import pandas as pd

url = "https://api.thestatsapi.com/api/football/matches"
params = {"competition_id": "{COMPETITION_ID}", "season": 2026, "per_page": 104}
headers = {"Authorization": "Bearer YOUR_API_KEY"}

fixtures = requests.get(url, params=params, headers=headers).json()["data"]

df = pd.DataFrame([{
    "match": f["match_number"],
    "date": f["kickoff_utc"][:10],
    "stage": f["stage"],
    "group": f.get("group"),
    "home": f["home"].get("name") or f["home"].get("label"),
    "away": f["away"].get("name") or f["away"].get("label"),
    "venue": f["venue"]["stadium"],
} for f in fixtures])

print(df.head(10))

You now have a 104-row DataFrame ready for analysis, model training, or CSV export.

Caching strategy

Fixtures change rarely — venue switches, scheduling adjustments, that's about it. A 5-minute cache (Cache-Control: max-age=300) at your edge is usually fine for pre-tournament. During the tournament, drop the cache to 30-60 seconds when matches are live so live scores from the same endpoint stay fresh.

What about cancellations or schedule changes

The 2022 World Cup had no cancellations, but the API returns status: "postponed" and an updated kickoff_utc if anything moves. Surface the status field in your UI and you handle the edge case gracefully.

Free alternatives

If you're just experimenting, football-data.org includes World Cup fixtures on its free tier. The format is a bit older (their fixtures endpoint paginates more aggressively) and you'll miss out on the venue metadata and Round of 32 placeholders, but it's enough for a hobby project.

For full coverage including the new Round of 32 handling and live-friendly rate limits, TheStatsAPI's $50/month Starter plan is the cleanest option.

Frequently Asked Questions

How many matches are in the 2026 World Cup?

104 matches total: 72 in the group stage (12 groups × 6) and 32 in the knockouts (16 R32, 8 R16, 4 QF, 2 SF, 1 third-place playoff, 1 Final).

What is the FIFA World Cup 2026 competition ID?

In TheStatsAPI, look up the 2026 FIFA World Cup competition_id via GET /football/competitions?search=world%20cup — we use {COMPETITION_ID} as a placeholder above. Other APIs use different IDs — check their /competitions endpoint.

How do I get just group-stage fixtures?

Add stage=group-stage to your matches query. Or filter by date range June 11–28, 2026.

Are knockout fixtures available before the group stage finishes?

Yes — pre-seeded with positional placeholders ("Winner Group A", "3rd Place A/B/F"). The API automatically replaces them with the qualified team once each group resolves.

How do I convert UTC kickoff times to local time?

Use JavaScript's Intl.DateTimeFormat with no explicit timezone — it defaults to the user's browser timezone. Our free Match Kickoff Time Converter does this in the browser with no API needed.

Does the World Cup API include venue and stadium info?

Yes. Each fixture returns venue.stadium, venue.city, venue.country, and venue.capacity. Useful for venue-specific landing pages and visualising travel logistics across the 16 host cities.

Can I subscribe to fixture updates via webhook?

Yes, on the Growth and Scale plans. Configure a webhook URL and receive POSTed events when fixtures are updated, postponed, or rescheduled — useful for ticker apps and notification systems.

Start building today

Ready to Power Your Sports App?

Start your 7-day free trial. All endpoints included on every plan.

Cancel anytime
7-day free trial
Setup in 5 minutes