FIFA World Cup API
Welcome to the BALLDONTLIE FIFA World Cup API, your source for World Cup data across the 2018, 2022, and 2026 tournaments — teams, stadiums, players, rosters, matches, standings, lineups, events, per-match player and team stats, shot maps, attack momentum, and betting odds. An API key is required. You can obtain an API key by creating a free account on our website. Read the authentication section to learn how to use the API key.
Endpoints that filter by season accept a seasons[] query parameter (allowed values: 2018, 2022, 2026). When omitted, queries default to the current edition (2026) so existing integrations continue to work without changes.
Take a look at our other APIs.
Join us on discord.
AI-Powered Integration
Using the OpenAPI Specification with AI
Our complete OpenAPI specification allows AI assistants to automatically understand and interact with our API. Simply share the spec URL with your AI assistant and describe what you want to build—the AI will handle the technical implementation.
Getting Started with AI:
- Copy this URL:
https://www.balldontlie.io/openapi/fifa.yml - Share it with your preferred AI assistant (ChatGPT, the agent, Gemini, etc.)
- Tell the AI what you want to build (e.g., "Create a dashboard showing FIFA World Cup matches")
- The AI will read the OpenAPI spec and write the code for you
Example prompts to try:
- "Using the OpenAPI spec at https://www.balldontlie.io/openapi/fifa.yml, show me how to get FIFA World Cup team information"
- "Read the BALLDONTLIE OpenAPI spec and create a Python script that fetches FIFA World Cup matches"
- "Help me understand the available FIFA World Cup endpoints from this OpenAPI spec: https://www.balldontlie.io/openapi/fifa.yml"
This makes it incredibly easy for non-technical users, analysts, and researchers to leverage our FIFA World Cup data without needing to learn programming from scratch.
Google Sheets Integration
Our Google Sheets integration lets you access all the same data available through our API using simple spreadsheet formulas. Perfect for fantasy sports tracking, betting analysis, and sports research.
Quick Start:
- Get your API key from app.balldontlie.io
- Copy our Google Sheets script
- Paste it into your Google Sheet (Extensions > Apps Script)
- Start using functions in your cells
Example functions:
=BDL_FIFA_TEAMS()- Get all teams=BDL_FIFA_PLAYERS("search")- Search for players=BDL_FIFA_MATCHES("2026-01-27")- Get matches by date=BDL_FIFA_STANDINGS(2025)- Get standings
For full setup instructions and the complete list of 150+ functions, see our Google Sheets Integration Guide.
Account Tiers
There are three different account tiers which provide you access to different types of data. Visit our website to create an account for free.
Paid tiers do not apply across sports. The tier you purchase for the FIFA World Cup will not automatically be applied to other sports. You can purchase the ALL-ACCESS ($299.99/mo) tier to get access to every endpoint for every sport.
Read the table below to see the breakdown.
| Endpoint | Free | ALL-STAR | GOAT |
|---|---|---|---|
| Teams | Yes | Yes | Yes |
| Stadiums | Yes | Yes | Yes |
| Group Standings | No | Yes | Yes |
| Matches | No | No | Yes |
| Odds | No | No | Yes |
| Futures | No | No | Yes |
| Players | No | No | Yes |
| Rosters | No | No | Yes |
| Match Lineups | No | No | Yes |
| Match Events | No | No | Yes |
| Player Match Stats | No | No | Yes |
| Team Match Stats | No | No | Yes |
| Match Shots | No | No | Yes |
| Match Momentum | No | No | Yes |
| Match Best Players | No | No | Yes |
| Match Avg Positions | No | No | Yes |
| Match Team Form | No | No | Yes |
The feature breakdown per tier is shown in the table below.
| Tier | Requests / Min | $USD / mo. |
|---|---|---|
| GOAT | 600 | 39.99 |
| ALL-STAR | 60 | 9.99 |
| Free | 5 | 0 |
48-hour free trial
Every paid sport offers a 48-hour trial of the GOAT tier (all endpoints, 5 req/min during the trial). ALL-ACCESS is also available as a 48-hour trial with the same 5 req/min trial limit. A payment method is required at signup; there is no charge until the trial ends, and you can cancel anytime from your dashboard. One trial per sport per account. Existing ALL-STAR subscribers may trial the GOAT upgrade for their sports.
Authentication
To authorize, use this code:
curl "api_endpoint_here" -H "Authorization: YOUR_API_KEY"
const response = await fetch(
"https://api.balldontlie.io/fifa/worldcup/v1/teams",
{
headers: {
Authorization: "YOUR_API_KEY",
},
}
);
const data = await response.json();
console.log(data);
import requests
response = requests.get(
'https://api.balldontlie.io/fifa/worldcup/v1/teams',
headers={'Authorization': 'YOUR_API_KEY'}
)
if response.status_code == 200:
data = response.json()
print(data)
else:
print(f'Error: {response.status_code}')
Make sure to replace
YOUR_API_KEYwith your API key.
BALLDONTLIE uses API keys to allow access to the API. You can obtain an API key by creating a free account at our website
We expect the API key to be included in all API requests to the server in a header that looks like the following:
Authorization: YOUR_API_KEY
Errors
The API uses the following error codes:
| Error Code | Meaning |
|---|---|
| 401 | Unauthorized - You either need an API key or your account tier does not have access to the endpoint. |
| 400 | Bad Request -- The request is invalid. The request parameters are probably incorrect. |
| 404 | Not Found -- The specified resource could not be found. |
| 406 | Not Acceptable -- You requested a format that isn't json. |
| 429 | Too Many Requests -- You're rate limited. |
| 500 | Internal Server Error -- We had a problem with our server. Try again later. |
| 503 | Service Unavailable -- We're temporarily offline for maintenance. Please try again later. |
Teams
Get All Teams
curl "https://api.balldontlie.io/fifa/worldcup/v1/teams" \
-H "Authorization: YOUR_API_KEY"
const response = await fetch(
"https://api.balldontlie.io/fifa/worldcup/v1/teams",
{
headers: {
Authorization: "YOUR_API_KEY",
},
}
);
const data = await response.json();
console.log(data);
import requests
response = requests.get(
'https://api.balldontlie.io/fifa/worldcup/v1/teams',
headers={'Authorization': 'YOUR_API_KEY'}
)
if response.status_code == 200:
teams = response.json()['data']
for team in teams:
print(f"{team['name']} ({team['abbreviation']})")
The above command returns JSON structured like this:
{
"data": [
{
"id": 13,
"name": "Algeria",
"abbreviation": "ALG",
"country_code": "ALG",
"confederation": "CAF"
},
{
"id": 1,
"name": "Argentina",
"abbreviation": "ARG",
"country_code": "ARG",
"confederation": "CONMEBOL"
},
{
"id": 25,
"name": "Australia",
"abbreviation": "AUS",
"country_code": "AUS",
"confederation": "AFC"
}
...
]
}
This endpoint retrieves all participating nations for the requested World Cup edition(s). Defaults to 2026 when seasons[] is omitted.
HTTP Request
GET https://api.balldontlie.io/fifa/worldcup/v1/teams
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| seasons[] | int[] | Optional. World Cup years to include. Allowed: 2018, 2022, 2026. Default: [2026]. |
Response Fields
| Field | Type | Description |
|---|---|---|
| id | int | Team ID |
| name | string | Full country name |
| abbreviation | string | Three-letter country code (e.g., USA, BRA, GER) |
| country_code | string | ISO country code |
| confederation | string | FIFA confederation (UEFA, CONMEBOL, CONCACAF, CAF, AFC, OFC) |
Stadiums
Get All Stadiums
curl "https://api.balldontlie.io/fifa/worldcup/v1/stadiums" \
-H "Authorization: YOUR_API_KEY"
const response = await fetch(
"https://api.balldontlie.io/fifa/worldcup/v1/stadiums",
{
headers: {
Authorization: "YOUR_API_KEY",
},
}
);
const data = await response.json();
console.log(data);
import requests
response = requests.get(
'https://api.balldontlie.io/fifa/worldcup/v1/stadiums',
headers={'Authorization': 'YOUR_API_KEY'}
)
if response.status_code == 200:
stadiums = response.json()['data']
for stadium in stadiums:
print(f"{stadium['name']} - {stadium['city']}")
The above command returns JSON structured like this:
{
"data": [
{
"id": 13,
"name": "Atlanta Stadium",
"city": "Atlanta",
"country": "USA",
"capacity": 71000,
"latitude": 33.7553,
"longitude": -84.4006
},
{
"id": 8,
"name": "BC Place Vancouver",
"city": "Vancouver",
"country": "CAN",
"capacity": 54500,
"latitude": 49.2767,
"longitude": -123.1119
}
...
]
}
This endpoint retrieves the host stadiums used by the requested World Cup edition(s). Defaults to 2026 when seasons[] is omitted.
HTTP Request
GET https://api.balldontlie.io/fifa/worldcup/v1/stadiums
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| seasons[] | int[] | Optional. World Cup years to include. Allowed: 2018, 2022, 2026. Default: [2026]. |
Response Fields
| Field | Type | Description |
|---|---|---|
| id | int | Stadium ID |
| name | string | Stadium name |
| city | string | Host city |
| country | string | Country code |
| capacity | int | Seating capacity (nullable) |
| latitude | float | Geographic latitude (nullable) |
| longitude | float | Geographic longitude (nullable) |
Group Standings
Get Group Standings
curl "https://api.balldontlie.io/fifa/worldcup/v1/group_standings" \
-H "Authorization: YOUR_API_KEY"
const response = await fetch(
"https://api.balldontlie.io/fifa/worldcup/v1/group_standings",
{
headers: {
Authorization: "YOUR_API_KEY",
},
}
);
const data = await response.json();
console.log(data);
import requests
response = requests.get(
'https://api.balldontlie.io/fifa/worldcup/v1/group_standings',
headers={'Authorization': 'YOUR_API_KEY'}
)
if response.status_code == 200:
standings = response.json()['data']
for standing in standings:
print(f"{standing['group']['name']}: {standing['team']['name']} - {standing['points']} pts")
The above command returns JSON structured like this:
{
"data": [
{
"season": { "id": 1, "year": 2026 },
"team": {
"id": 8,
"name": "Mexico",
"abbreviation": "MEX",
"country_code": "MEX",
"confederation": "CONCACAF"
},
"group": {
"id": 1,
"name": "Group A"
},
"position": 1,
"played": 0,
"won": 0,
"drawn": 0,
"lost": 0,
"goals_for": 0,
"goals_against": 0,
"goal_difference": 0,
"points": 0
}
...
]
}
This endpoint retrieves group stage standings for the requested World Cup edition(s). Defaults to 2026 when seasons[] is omitted.
HTTP Request
GET https://api.balldontlie.io/fifa/worldcup/v1/group_standings
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| seasons[] | int[] | Optional. World Cup years to include. Allowed: 2018, 2022, 2026. Default: [2026]. |
Response Fields
| Field | Type | Description |
|---|---|---|
| season | object | Season { id, year } |
| team | object | Team object |
| group | object | Group object (id, name) |
| position | int | Position within the group |
| played | int | Games played |
| won | int | Games won |
| drawn | int | Games drawn |
| lost | int | Games lost |
| goals_for | int | Goals scored |
| goals_against | int | Goals conceded |
| goal_difference | int | Goal difference |
| points | int | Total points |
Matches
Get All Matches
curl "https://api.balldontlie.io/fifa/worldcup/v1/matches" \
-H "Authorization: YOUR_API_KEY"
const response = await fetch(
"https://api.balldontlie.io/fifa/worldcup/v1/matches",
{
headers: {
Authorization: "YOUR_API_KEY",
},
}
);
const data = await response.json();
console.log(data);
import requests
response = requests.get(
'https://api.balldontlie.io/fifa/worldcup/v1/matches',
headers={'Authorization': 'YOUR_API_KEY'}
)
if response.status_code == 200:
matches = response.json()['data']
for match in matches:
home = match['home_team']['name'] if match['home_team'] else 'TBD'
away = match['away_team']['name'] if match['away_team'] else 'TBD'
print(f"{home} vs {away}")
The above command returns JSON structured like this:
{
"data": [
{
"id": 1030,
"match_number": 1,
"datetime": "2022-11-20T16:00:00.000Z",
"status": "completed",
"season": { "id": 2, "year": 2022 },
"stage": { "id": 24, "name": "Group Stage", "order": 1 },
"group": { "id": 1, "name": "Group A" },
"stadium": {
"id": 476,
"name": "Al Bayt Stadium",
"city": "Al Khor",
"country": "QAT",
"capacity": 60000,
"latitude": 51.31667,
"longitude": 25.76667
},
"home_team": {
"id": 7,
"name": "Qatar",
"abbreviation": "QAT",
"country_code": "QAT",
"confederation": "AFC"
},
"away_team": {
"id": 20,
"name": "Ecuador",
"abbreviation": "ECU",
"country_code": "ECU",
"confederation": "CONMEBOL"
},
"home_team_source": null,
"away_team_source": null,
"home_score": 0,
"away_score": 2,
"home_score_penalties": null,
"away_score_penalties": null,
"first_half_home_score": 0,
"first_half_away_score": 2,
"second_half_home_score": 0,
"second_half_away_score": 0,
"extra_time_home_score": null,
"extra_time_away_score": null,
"has_extra_time": false,
"has_penalty_shootout": false,
"round_number": 1,
"round_name": null,
"home_formation": "5-3-2",
"away_formation": "4-4-2",
"referee": {
"id": 168,
"name": "Daniele Orsato",
"country_code": "ITA",
"country_name": "Italy"
},
"home_manager": {
"id": 369,
"name": "Félix Sánchez",
"short_name": "F. Sánchez"
},
"away_manager": {
"id": 372,
"name": "Gustavo Alfaro",
"short_name": "G. Alfaro"
}
},
{
"id": 73,
"match_number": 73,
"datetime": "2026-06-28T15:00:00.000Z",
"status": "scheduled",
"stage": {
"id": 6,
"name": "Round of 32",
"order": 2
},
"group": null,
"stadium": {
"id": 4,
"name": "Los Angeles Stadium",
"city": "Los Angeles",
"country": "USA"
},
"home_team": null,
"away_team": null,
"home_team_source": {
"type": "group_2nd",
"source_match_id": null,
"source_match_number": null,
"source_group_id": 1,
"source_group_name": "Group A",
"placeholder": "2A",
"description": "2nd place in Group Group A"
},
"away_team_source": {
"type": "group_2nd",
"source_match_id": null,
"source_match_number": null,
"source_group_id": 2,
"source_group_name": "Group B",
"placeholder": "2B",
"description": "2nd place in Group Group B"
},
"home_score": null,
"away_score": null,
"home_score_penalties": null,
"away_score_penalties": null
},
...
]
}
This endpoint retrieves matches for the requested World Cup edition(s) — group stage and knockout rounds. Defaults to 2026 when seasons[] is omitted. Results are paginated by cursor.
HTTP Request
GET https://api.balldontlie.io/fifa/worldcup/v1/matches
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| seasons[] | int[] | Optional. Allowed: 2018, 2022, 2026. Default: [2026]. |
| match_ids[] | int[] | Optional. Filter to specific match IDs. |
| team_ids[] | int[] | Optional. Filter to matches where one of these team IDs played. |
| per_page | int | Optional. Page size, max 100. Default 25. |
| cursor | int | Optional. Cursor for the next page. |
Response Fields
| Field | Type | Description |
|---|---|---|
| id | int | Match ID |
| match_number | int | Official match number |
| datetime | string | Match date and time in UTC |
| status | string | Match status (scheduled, in_progress, completed, postponed, cancelled) |
| season | object | Season { id, year } |
| stage | object | Stage object (id, name, order) |
| group | object | Group object (null for knockout matches) |
| stadium | object | Stadium object |
| home_team | object | Home team (null if TBD in knockout stage) |
| away_team | object | Away team (null if TBD in knockout stage) |
| home_team_source | object | Source info when home team is TBD |
| away_team_source | object | Source info when away team is TBD |
| home_score | int | Home team score (null if not started) |
| away_score | int | Away team score (null if not started) |
| home_score_penalties | int | Home team penalty shootout score (null if no shootout) |
| away_score_penalties | int | Away team penalty shootout score (null if no shootout) |
| first_half_home_score | int | First-half home score (nullable) |
| first_half_away_score | int | First-half away score (nullable) |
| second_half_home_score | int | Second-half home score (nullable) |
| second_half_away_score | int | Second-half away score (nullable) |
| extra_time_home_score | int | Extra-time home score (nullable; null unless has_extra_time) |
| extra_time_away_score | int | Extra-time away score (nullable) |
| has_extra_time | boolean | Whether extra time was played |
| has_penalty_shootout | boolean | Whether a penalty shootout was played |
| round_number | int | Round number within the tournament (nullable) |
| round_name | string | Round name, e.g. "Round of 16" (nullable) |
| home_formation | string | Home team formation, e.g. "4-3-3" (nullable until lineups confirmed) |
| away_formation | string | Away team formation (nullable) |
| referee | object | Referee { id, name, country_code, country_name } (nullable) |
| home_manager | object | Home manager { id, name, short_name } (nullable) |
| away_manager | object | Away manager (nullable) |
Team Source Object
For knockout matches where teams are not yet determined, the home_team_source or away_team_source provides information about how the team will be determined:
| Field | Type | Description |
|---|---|---|
| type | string | Source type (group_1st, group_2nd, winner, loser, etc.) |
| source_match_id | int | ID of the match that determines this team |
| source_match_number | int | Match number that determines this team |
| source_group_id | int | ID of the group (for group placement sources) |
| source_group_name | string | Group name (e.g., "A", "B") |
| placeholder | string | Placeholder text |
| description | string | Human-readable description (e.g., "Winner of Match 49") |
Understanding Knockout Match Data
The 2026 World Cup includes 104 matches total; the 2018 and 2022 editions had 64 each. Before the knockout rounds begin, many matches will have home_team and/or away_team set to null because the participating teams have not yet been determined. You can construct the knockout bracket in addition to the group stages with this data.
How to interpret the data:
Check if teams are determined: If
home_teamoraway_teamisnull, the team has not yet qualified for that match.Use the source object: When a team is
null, look at the correspondinghome_team_sourceoraway_team_sourceobject to understand how the team will be determined.Source types explained:
group_1st- Winner of a group (checksource_group_namefor which group)group_2nd- Runner-up of a group (checksource_group_namefor which group)group_3rd- Third place finisher from a groupwinner- Winner of a previous match (checksource_match_idorsource_match_number)loser- Loser of a previous match (used for third-place playoff)
- Display placeholder text: Use the
descriptionfield for a human-readable label (e.g., "Winner of Group A" or "Winner of Match 49").
Odds
Get Betting Odds
curl "https://api.balldontlie.io/fifa/worldcup/v1/odds" \
-H "Authorization: YOUR_API_KEY"
const response = await fetch(
"https://api.balldontlie.io/fifa/worldcup/v1/odds",
{
headers: {
Authorization: "YOUR_API_KEY",
},
}
);
const data = await response.json();
console.log(data);
import requests
response = requests.get(
'https://api.balldontlie.io/fifa/worldcup/v1/odds',
headers={'Authorization': 'YOUR_API_KEY'}
)
if response.status_code == 200:
odds = response.json()['data']
for odd in odds:
print(f"Match {odd['match_id']}: Home {odd['moneyline_home_odds']}, Draw {odd['moneyline_draw_odds']}, Away {odd['moneyline_away_odds']}")
The above command returns JSON structured like this:
{
"data": [
{
"id": 37515873,
"match_id": 10,
"vendor": "draftkings",
"moneyline_home_odds": -115,
"moneyline_away_odds": 320,
"moneyline_draw_odds": 250,
"updated_at": "2025-12-18T20:39:00.295Z"
},
{
"id": 37515874,
"match_id": 11,
"vendor": "draftkings",
"moneyline_home_odds": 230,
"moneyline_away_odds": 130,
"moneyline_draw_odds": 210,
"updated_at": "2025-12-18T20:39:00.295Z"
}
...
]
}
This endpoint retrieves moneyline betting odds for World Cup matches. Defaults to 2026 when seasons[] is omitted. Results are paginated by cursor.
Available Vendors:
| Vendor | Description |
|---|---|
| draftkings | DraftKings |
| fanduel | FanDuel |
HTTP Request
GET https://api.balldontlie.io/fifa/worldcup/v1/odds
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| seasons[] | int[] | Optional. Allowed: 2018, 2022, 2026. Default: [2026]. |
| match_ids[] | int[] | Optional. Filter to specific match IDs. |
| per_page | int | Optional. Page size, max 100. Default 25. |
| cursor | int | Optional. Cursor for the next page. |
Response Fields
| Field | Type | Description |
|---|---|---|
| id | int | Odds ID |
| match_id | int | Match ID |
| vendor | string | Sportsbook vendor |
| moneyline_home_odds | int | Home team moneyline odds |
| moneyline_away_odds | int | Away team moneyline odds |
| moneyline_draw_odds | number | Draw moneyline odds |
| updated_at | string | Last update timestamp |
Futures
Get Futures Odds
curl "https://api.balldontlie.io/fifa/worldcup/v1/odds/futures" \
-H "Authorization: YOUR_API_KEY"
const response = await fetch(
"https://api.balldontlie.io/fifa/worldcup/v1/odds/futures",
{
headers: {
Authorization: "YOUR_API_KEY",
},
}
);
const data = await response.json();
console.log(data);
import requests
response = requests.get(
'https://api.balldontlie.io/fifa/worldcup/v1/odds/futures',
headers={'Authorization': 'YOUR_API_KEY'}
)
if response.status_code == 200:
futures = response.json()['data']
for future in futures:
print(f"{future['subject']['name']}: {future['american_odds']} ({future['market_name']})")
The above command returns JSON structured like this:
{
"data": [
{
"id": 1297,
"market_type": "finish_bottom",
"market_name": "Group G",
"subject": {
"id": 41,
"name": "New Zealand",
"abbreviation": "NZL",
"country_code": "NZL",
"confederation": "OFC"
},
"vendor": "draftkings",
"american_odds": -185,
"decimal_odds": 1.5405,
"updated_at": "2025-12-18T15:12:26.494Z"
},
{
"id": 1283,
"market_type": "finish_bottom",
"market_name": "Group C",
"subject": {
"id": 44,
"name": "Scotland",
"abbreviation": "SCO",
"country_code": "SCO",
"confederation": "UEFA"
},
"vendor": "draftkings",
"american_odds": 500,
"decimal_odds": 6,
"updated_at": "2025-12-18T15:12:26.494Z"
}
...
]
}
This endpoint retrieves futures betting odds for the FIFA World Cup (e.g., tournament winner odds). Defaults to 2026 when seasons[] is omitted.
Available Vendors:
| Vendor | Description |
|---|---|
| draftkings | DraftKings |
| fanduel | FanDuel |
HTTP Request
GET https://api.balldontlie.io/fifa/worldcup/v1/odds/futures
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| seasons[] | int[] | Optional. Allowed: 2018, 2022, 2026. Default: [2026]. |
Response Fields
| Field | Type | Description |
|---|---|---|
| id | int | Futures odds ID |
| market_type | string | Type of futures market |
| market_name | string | Name of the futures market |
| subject | object | Team object the odds are for |
| vendor | string | Sportsbook vendor |
| american_odds | int | American odds format |
| decimal_odds | number | Decimal odds format |
| updated_at | string | Last update timestamp |
Market Types
| Market Type | Description |
|---|---|
| outright | Tournament winner |
| group_winner | Win their group |
| qualify_from_group | Advance from group stage |
| finish_bottom | Finish last in their group |
| win_all_group_games | Win all three group stage matches |
| to_reach_quarters | Advance to the quarterfinals |
| to_reach_semis | Advance to the semifinals |
| to_reach_final | Advance to the final |
| stage_of_elimination | Stage at which a team will be eliminated |
Players
Get Players
curl "https://api.balldontlie.io/fifa/worldcup/v1/players?search=pulisic" \
-H "Authorization: YOUR_API_KEY"
The above command returns JSON structured like this:
{
"data": [
{
"id": 142,
"name": "Christian Pulisic",
"short_name": "C. Pulisic",
"position": "M",
"date_of_birth": "1998-09-18T00:00:00.000Z",
"country_code": "USA",
"country_name": "United States",
"height_cm": 172,
"jersey_number": "10"
}
],
"meta": { "next_cursor": 142, "per_page": 25 }
}
Lists biographical data for every player who has appeared in a FIFA World Cup squad. By default returns all players across every ingested edition; pass seasons[] and/or team_ids[] to filter.
HTTP Request
GET https://api.balldontlie.io/fifa/worldcup/v1/players
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| seasons[] | int[] | Optional. Allowed: 2018, 2022, 2026. When omitted, returns players across all editions. |
| team_ids[] | int[] | Optional. Filter to players who appeared on these team IDs. |
| search | string | Optional. Case-insensitive substring match on player name. |
| per_page | int | Optional. Page size, max 100. Default 25. |
| cursor | int | Optional. Cursor for the next page. |
Response Fields
| Field | Type | Description |
|---|---|---|
| id | int | Player ID |
| name | string | Full name |
| short_name | string | Short / display form (nullable) |
| position | string | Primary position code (nullable) |
| date_of_birth | string | ISO date (nullable) |
| country_code | string | Three-letter country code (nullable) |
| country_name | string | Country name (nullable) |
| height_cm | int | Height in centimeters (nullable) |
| jersey_number | string | Last known jersey number (nullable) |
Rosters
Get Tournament Rosters
curl "https://api.balldontlie.io/fifa/worldcup/v1/rosters?team_ids[]=12" \
-H "Authorization: YOUR_API_KEY"
The above command returns JSON structured like this:
{
"data": [
{
"season": { "id": 1, "year": 2026 },
"team_id": 12,
"player": {
"id": 142,
"name": "Christian Pulisic",
"short_name": "C. Pulisic",
"position": "M",
"date_of_birth": "1998-09-18T00:00:00.000Z",
"country_code": "USA",
"country_name": "United States",
"height_cm": 172,
"jersey_number": "10"
},
"position": "M",
"appearances": 4,
"starts": 4,
"minutes_played": 360,
"goals": 2,
"assists": 1,
"yellow_cards": 1,
"red_cards": 0,
"avg_rating": 7.6
}
],
"meta": { "next_cursor": 200, "per_page": 25 }
}
Returns the per-tournament squad (one row per player per team per edition) with cumulative tournament stats. By default returns rosters across all ingested editions; pass seasons[] to filter.
HTTP Request
GET https://api.balldontlie.io/fifa/worldcup/v1/rosters
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| seasons[] | int[] | Optional. Allowed: 2018, 2022, 2026. When omitted, returns rosters across all editions. |
| team_ids[] | int[] | Optional. Filter to specific team IDs. |
| player_ids[] | int[] | Optional. Filter to specific player IDs. |
| per_page | int | Optional. Page size, max 100. Default 25. |
| cursor | int | Optional. Cursor for the next page. |
Response Fields
| Field | Type | Description |
|---|---|---|
| season | object | Season { id, year } |
| team_id | int | Team ID |
| player | object | Full player object |
| position | string | Primary position code (nullable) |
| appearances | int | Tournament appearances (matches with any minutes) |
| starts | int | Tournament starts |
| minutes_played | int | Total minutes played in the tournament |
| goals | int | Tournament goals |
| assists | int | Tournament assists |
| yellow_cards | int | Tournament yellow cards |
| red_cards | int | Tournament red cards |
| avg_rating | number | Average match rating (nullable) |
Match Lineups
Get Match Lineups
curl "https://api.balldontlie.io/fifa/worldcup/v1/match_lineups?match_ids[]=1" \
-H "Authorization: YOUR_API_KEY"
The above command returns JSON structured like this:
{
"data": [
{
"match_id": 1,
"team_id": 8,
"player": {
"id": 142,
"name": "Christian Pulisic",
"short_name": "C. Pulisic",
"position": "M",
"date_of_birth": "1998-09-18T00:00:00.000Z",
"country_code": "USA",
"country_name": "United States",
"height_cm": 172,
"jersey_number": "10"
},
"is_starter": true,
"is_substitute": false,
"shirt_number": 10,
"position": "AM",
"formation": "4-3-3"
}
],
"meta": { "next_cursor": 100, "per_page": 25 }
}
Returns the registered match-day squad (starters + bench) for one or more matches.
HTTP Request
GET https://api.balldontlie.io/fifa/worldcup/v1/match_lineups
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| match_ids[] | int[] | Optional. Filter to specific match IDs. |
| team_ids[] | int[] | Optional. Filter to specific team IDs. |
| per_page | int | Optional. Page size, max 100. Default 25. |
| cursor | int | Optional. Cursor for the next page. |
Response Fields
| Field | Type | Description |
|---|---|---|
| match_id | int | Match ID |
| team_id | int | Team ID |
| player | object | Full player object |
| is_starter | boolean | Whether the player started the match |
| is_substitute | boolean | Whether the player was on the bench |
| shirt_number | int | Shirt number worn for this match |
| position | string | Position code for this match (nullable) |
| formation | string | Team formation, e.g. "4-3-3" (nullable) |
Match Events
Get Match Events
curl "https://api.balldontlie.io/fifa/worldcup/v1/match_events?match_ids[]=1" \
-H "Authorization: YOUR_API_KEY"
The above command returns JSON structured like this:
{
"data": [
{
"id": 3713,
"match_id": 1030,
"incident_type": "goal",
"incident_class": "penalty",
"time_minute": 16,
"added_time": null,
"period": null,
"is_home": false,
"player": {
"id": 8760,
"name": "Enner Valencia",
"short_name": "E. Valencia",
"position": "F",
"date_of_birth": "1989-11-04T00:00:00.000Z",
"country_code": "ECU",
"country_name": "Ecuador",
"height_cm": 177,
"jersey_number": "10"
},
"assist_player": null,
"player_in": null,
"player_out": null,
"home_score": 0,
"away_score": 1,
"shootout_sequence": null,
"shootout_description": null,
"rescinded": null,
"reason": null
}
],
"meta": { "next_cursor": 3713, "per_page": 25 }
}
Returns time-ordered match events: goals, cards, substitutions, period markers, and penalty-shootout kicks. Most events surface home_score/away_score reflecting the running tally; non-goal events leave them null. The period field is sparse and usually null.
HTTP Request
GET https://api.balldontlie.io/fifa/worldcup/v1/match_events
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| match_ids[] | int[] | Optional. Filter to specific match IDs. |
| per_page | int | Optional. Page size, max 100. Default 25. |
| cursor | int | Optional. Cursor for the next page. |
Response Fields
| Field | Type | Description |
|---|---|---|
| id | int | Event ID |
| match_id | int | Match ID |
| incident_type | string | One of: goal, card, substitution, period, injuryTime, penaltyShootout |
| incident_class | string | E.g. regular, penalty, owngoal, yellow, red, yellowRed, shootoutScored |
| time_minute | int | Minute of the match (nullable) |
| added_time | int | Stoppage-time minute (nullable) |
| period | string | Period label (e.g. "1H", "2H", "ET1", "ET2") — nullable |
| is_home | boolean | Whether the event belongs to the home team (nullable for non-team events) |
| player | object | Primary player (nullable) |
| assist_player | object | Assist player on goals (nullable) |
| player_in | object | Substitution: player coming on (nullable) |
| player_out | object | Substitution: player coming off (nullable) |
| home_score | int | Running home score after this event (nullable) |
| away_score | int | Running away score after this event (nullable) |
| shootout_sequence | int | Penalty shootout kick sequence number (nullable) |
| shootout_description | string | Shootout outcome (Scored, Missed, Saved) — nullable |
| rescinded | boolean | Whether a card was later rescinded (nullable) |
| reason | string | Free-form reason text (nullable) |
Player Match Stats
Get Player Match Stats
curl "https://api.balldontlie.io/fifa/worldcup/v1/player_match_stats?match_ids[]=1" \
-H "Authorization: YOUR_API_KEY"
The above command returns JSON structured like this:
{
"data": [
{
"match_id": 1,
"player_id": 142,
"team_id": 8,
"is_home": true,
"rating": 7.8,
"minutes_played": 90,
"expected_goals": 0.42,
"expected_assists": 0.18,
"goals": 1,
"assists": 0,
"shots_on_target": 2,
"passes_total": 50,
"passes_accurate": 45,
"key_passes": 3,
"tackles": 2,
"tackles_won": 1,
"interceptions": 1,
"duels_won": 4,
"duels_lost": 3,
"fouls_committed": 1,
"was_fouled": 2,
"touches": 60,
"saves": null
}
],
"meta": { "next_cursor": 5000, "per_page": 25 }
}
Returns per-player per-match performance statistics. Goalkeeper-only fields (saves, saves_inside_box, punches, high_claims) are returned null for outfield players.
HTTP Request
GET https://api.balldontlie.io/fifa/worldcup/v1/player_match_stats
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| match_ids[] | int[] | Optional. Filter to specific match IDs. |
| player_ids[] | int[] | Optional. Filter to specific player IDs. |
| team_ids[] | int[] | Optional. Filter to specific team IDs. |
| per_page | int | Optional. Page size, max 100. Default 25. |
| cursor | int | Optional. Cursor for the next page. |
Response Fields
The response includes match_id, player_id, team_id, is_home, plus the following nullable numeric fields: rating, minutes_played, expected_goals, expected_assists, goals, assists, shots_on_target, passes_total, passes_accurate, key_passes, long_balls_total, long_balls_accurate, crosses_total, crosses_accurate, dribbles_attempted, dribbles_completed, tackles, tackles_won, interceptions, clearances, blocked_shots, duels_won, duels_lost, aerial_duels_won, aerial_duels_lost, fouls_committed, was_fouled, touches, possession_lost, ball_recoveries, big_chances_created, big_chances_missed, saves, saves_inside_box, punches, high_claims.
Team Match Stats
Get Team Match Stats
curl "https://api.balldontlie.io/fifa/worldcup/v1/team_match_stats?match_ids[]=1" \
-H "Authorization: YOUR_API_KEY"
The above command returns JSON structured like this:
{
"data": [
{
"match_id": 1,
"team_id": 8,
"is_home": true,
"possession_pct": 60,
"expected_goals": 1.42,
"big_chances": 3,
"big_chances_missed": 1,
"shots_total": 14,
"shots_on_target": 6,
"shots_off_target": 5,
"shots_blocked": 3,
"shots_inside_box": 9,
"shots_outside_box": 5,
"hit_woodwork": 0,
"corners": 6,
"offsides": 2,
"fouls": 10,
"yellow_cards": 1,
"passes_total": 500,
"passes_accurate": 440,
"passes_final_third": 80,
"long_balls_total": 30,
"long_balls_accurate": 18,
"crosses_total": 12,
"crosses_accurate": 4,
"tackles": 16,
"interceptions": 9,
"clearances": 11,
"saves": 3,
"ground_duels_won": 25,
"ground_duels_total": 50,
"aerial_duels_won": 10,
"aerial_duels_total": 18,
"dribbles_completed": 8,
"dribbles_total": 14,
"throw_ins": 22,
"goal_kicks": 6,
"free_kicks": 14
}
],
"meta": { "next_cursor": 200, "per_page": 25 }
}
Per-team per-match aggregates. The possession_pct field is normalized 0-100. Field names follow the BALLDONTLIE soccer API conventions (shots_total, passes_accurate, etc.).
HTTP Request
GET https://api.balldontlie.io/fifa/worldcup/v1/team_match_stats
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| match_ids[] | int[] | Optional. Filter to specific match IDs. |
| team_ids[] | int[] | Optional. Filter to specific team IDs. |
| per_page | int | Optional. Page size, max 100. Default 25. |
| cursor | int | Optional. Cursor for the next page. |
Match Shots
Get Match Shots
curl "https://api.balldontlie.io/fifa/worldcup/v1/match_shots?match_ids[]=1" \
-H "Authorization: YOUR_API_KEY"
The above command returns JSON structured like this:
{
"data": [
{
"id": 5073,
"match_id": 1030,
"player_id": 8760,
"team_id": 20,
"is_home": false,
"shot_type": "goal",
"situation": "penalty",
"body_part": "right-foot",
"goal_type": "penalty",
"xg": 0.7884,
"xgot": 0.9937,
"player_x": 11.5,
"player_y": 50,
"goal_mouth_x": 0,
"goal_mouth_y": 46,
"block_x": null,
"block_y": null,
"time_minute": 16,
"added_time": null,
"time_seconds": 949
}
],
"meta": { "next_cursor": 5073, "per_page": 25 }
}
Returns the shot map for one or more matches. Coordinates are normalized 0-100. xg and xgot are populated for 2022 and 2026 matches; 2018 shots have coordinates and body_part only.
HTTP Request
GET https://api.balldontlie.io/fifa/worldcup/v1/match_shots
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| match_ids[] | int[] | Optional. Filter to specific match IDs. |
| player_ids[] | int[] | Optional. Filter to specific player IDs. |
| per_page | int | Optional. Page size, max 100. Default 25. |
| cursor | int | Optional. Cursor for the next page. |
Response Fields
| Field | Type | Description |
|---|---|---|
| id | int | Shot ID |
| match_id | int | Match ID |
| player_id | int | Shooter ID |
| team_id | int | Team ID |
| is_home | boolean | Whether the shooter's team was the home team |
| shot_type | string | One of: goal, save, miss, block, post |
| situation | string | Play situation (e.g. regular, set-piece) — nullable |
| body_part | string | Body part used (e.g. right-foot, left-foot, header) — nullable |
| goal_type | string | Type of goal (e.g. header, freekick) — nullable |
| xg | number | Expected goals value (nullable for 2018) |
| xgot | number | Expected goals on target value (nullable for 2018) |
| player_x | number | Shooter X position 0-100 (nullable) |
| player_y | number | Shooter Y position 0-100 (nullable) |
| goal_mouth_x | number | Goal-mouth X coordinate (nullable) |
| goal_mouth_y | number | Goal-mouth Y coordinate (nullable) |
| block_x | number | Block X coordinate (nullable) |
| block_y | number | Block Y coordinate (nullable) |
| time_minute | int | Match minute |
| added_time | int | Stoppage-time minute (nullable) |
| time_seconds | int | Time within the match in seconds (nullable) |
Match Momentum
Get Match Momentum
curl "https://api.balldontlie.io/fifa/worldcup/v1/match_momentum?match_ids[]=1" \
-H "Authorization: YOUR_API_KEY"
The above command returns JSON structured like this:
{
"data": [
{ "match_id": 1, "minute": 0, "value": 0 },
{ "match_id": 1, "minute": 1, "value": 12 },
{ "match_id": 1, "minute": 2, "value": -8 }
],
"meta": { "next_cursor": 200, "per_page": 25 }
}
Returns per-minute attack momentum values. Positive values favor the home side; negative values favor the away side.
HTTP Request
GET https://api.balldontlie.io/fifa/worldcup/v1/match_momentum
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| match_ids[] | int[] | Optional. Filter to specific match IDs. |
| per_page | int | Optional. Page size, max 100. Default 25. |
| cursor | int | Optional. Cursor for the next page. |
Response Fields
| Field | Type | Description |
|---|---|---|
| match_id | int | Match ID |
| minute | number | Match minute (may include fractions) |
| value | number | Momentum value |
Match Best Players
Get Match Best Players
curl "https://api.balldontlie.io/fifa/worldcup/v1/match_best_players?match_ids[]=1" \
-H "Authorization: YOUR_API_KEY"
The above command returns JSON structured like this:
{
"data": [
{
"match_id": 1,
"player_id": 142,
"team_id": 8,
"is_home": true,
"side_rank": 1,
"is_man_of_match": true,
"rating": 9.1,
"reason": "scored 1 goal, 3 key passes"
}
],
"meta": { "next_cursor": 200, "per_page": 25 }
}
Returns the top-rated players for each match (best XI per side plus the man of the match).
HTTP Request
GET https://api.balldontlie.io/fifa/worldcup/v1/match_best_players
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| match_ids[] | int[] | Optional. Filter to specific match IDs. |
| per_page | int | Optional. Page size, max 100. Default 25. |
| cursor | int | Optional. Cursor for the next page. |
Response Fields
| Field | Type | Description |
|---|---|---|
| match_id | int | Match ID |
| player_id | int | Player ID |
| team_id | int | Team ID |
| is_home | boolean | Whether the player was on the home side |
| side_rank | int | Rank within the player's side (1 = top) |
| is_man_of_match | boolean | Whether the player was named MOTM |
| rating | number | Match rating (nullable) |
| reason | string | Highlight summary (nullable) |
Match Avg Positions
Get Match Avg Positions
curl "https://api.balldontlie.io/fifa/worldcup/v1/match_avg_positions?match_ids[]=1" \
-H "Authorization: YOUR_API_KEY"
The above command returns JSON structured like this:
{
"data": [
{
"match_id": 1,
"player_id": 142,
"team_id": 8,
"is_home": true,
"avg_x": 50.5,
"avg_y": 60.2
}
],
"meta": { "next_cursor": 200, "per_page": 25 }
}
Returns each player's average pitch position (heatmap centroid) for a given match. Coordinates are normalized 0-100 from the home side's perspective.
HTTP Request
GET https://api.balldontlie.io/fifa/worldcup/v1/match_avg_positions
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| match_ids[] | int[] | Optional. Filter to specific match IDs. |
| team_ids[] | int[] | Optional. Filter to specific team IDs. |
| per_page | int | Optional. Page size, max 100. Default 25. |
| cursor | int | Optional. Cursor for the next page. |
Response Fields
| Field | Type | Description |
|---|---|---|
| match_id | int | Match ID |
| player_id | int | Player ID |
| team_id | int | Team ID |
| is_home | boolean | Whether the player was on the home side |
| avg_x | number | Average X coordinate (0-100) |
| avg_y | number | Average Y coordinate (0-100) |
Match Team Form
Get Match Team Form
curl "https://api.balldontlie.io/fifa/worldcup/v1/match_team_form?match_ids[]=1" \
-H "Authorization: YOUR_API_KEY"
The above command returns JSON structured like this:
{
"data": [
{
"match_id": 762,
"team_id": 27,
"is_home": true,
"avg_rating": 6.6,
"position": 2,
"value": "3"
}
],
"meta": { "next_cursor": 200, "per_page": 25 }
}
Returns a pre-match team form summary: each side's recent average rating, group standings position going in, and a value summary string (a single-digit metric — typically points earned across recent matches).
HTTP Request
GET https://api.balldontlie.io/fifa/worldcup/v1/match_team_form
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| match_ids[] | int[] | Optional. Filter to specific match IDs. |
| per_page | int | Optional. Page size, max 100. Default 25. |
| cursor | int | Optional. Cursor for the next page. |
Response Fields
| Field | Type | Description |
|---|---|---|
| match_id | int | Match ID |
| team_id | int | Team ID |
| is_home | boolean | Whether the team is the home side |
| avg_rating | number | Average rating across recent matches (nullable) |
| position | int | Position going into the match (nullable) |
| value | string | Form summary value (typically recent-match points as a single-digit string, e.g. "3") |