NAV
shell javascript python

PREMIER LEAGUE API V2

Welcome to the BALLDONTLIE PREMIER LEAGUE API V2. This API contains data from 2010-current. 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.

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:

  1. Copy this URL: https://www.balldontlie.io/openapi/epl.yml
  2. Share it with your preferred AI assistant (ChatGPT, Claude, Gemini, etc.)
  3. Tell the AI what you want to build (e.g., "Create a dashboard showing this week's Premier League matches")
  4. The AI will read the OpenAPI spec and write the code for you

Example prompts to try:

This makes it incredibly easy for non-technical users, analysts, and researchers to leverage our sports 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:

  1. Get your API key from app.balldontlie.io
  2. Copy our Google Sheets script
  3. Paste it into your Google Sheet (Extensions > Apps Script)
  4. Start using functions in your cells

Example functions:

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 Premier League 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
Rosters Yes Yes Yes
Players Yes Yes Yes
Standings Yes Yes Yes
Matches No Yes Yes
Match Events No Yes Yes
Match Lineups No Yes Yes
Player Match Stats No No Yes
Team Match Stats No No Yes
Betting Odds No No Yes
Player Props 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, 600 req/min). ALL-ACCESS is also available as a 48-hour trial. 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 "https://api.balldontlie.io/epl/v2/teams" \
  -H "Authorization: YOUR_API_KEY"
const response = await fetch("https://api.balldontlie.io/epl/v2/teams", {
  headers: {
    "Authorization": "YOUR_API_KEY"
  }
});
const data = await response.json();
import requests

response = requests.get(
    "https://api.balldontlie.io/epl/v2/teams",
    headers={"Authorization": "YOUR_API_KEY"}
)
data = response.json()

Make sure to replace YOUR_API_KEY with 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

Pagination

This API uses cursor based pagination rather than limit/offset. Endpoints that support pagination will send back responses with a meta key that looks like what is displayed on the right.

{
  "meta": {
    "next_cursor": 90,
    "per_page": 25
  }
}

You can use per_page to specify the maximum number of results. It defaults to 25 and doesn't allow values larger than 100.

You can use next_cursor to get the next page of results. Specify it in the request parameters like this: ?cursor=NEXT_CURSOR.

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/epl/v2/teams" \
  -H "Authorization: YOUR_API_KEY"

# With optional season parameter
curl "https://api.balldontlie.io/epl/v2/teams?season=2024" \
  -H "Authorization: YOUR_API_KEY"
const response = await fetch("https://api.balldontlie.io/epl/v2/teams", {
  headers: {
    "Authorization": "YOUR_API_KEY"
  }
});
const data = await response.json();

// With optional season parameter
const response2024 = await fetch(
  "https://api.balldontlie.io/epl/v2/teams?season=2024",
  {
    headers: { "Authorization": "YOUR_API_KEY" }
  }
);
const data2024 = await response2024.json();
import requests

response = requests.get(
    "https://api.balldontlie.io/epl/v2/teams",
    headers={"Authorization": "YOUR_API_KEY"}
)
data = response.json()

# With optional season parameter
response_2024 = requests.get(
    "https://api.balldontlie.io/epl/v2/teams",
    params={"season": 2024},
    headers={"Authorization": "YOUR_API_KEY"}
)
data_2024 = response_2024.json()

The above command returns JSON structured like this:

{
  "data": [
    {
      "id": 2,
      "name": "Arsenal",
      "short_name": "Arsenal",
      "abbreviation": "ARS",
      "location": "Arsenal"
    },
    {
      "id": 13,
      "name": "Manchester City",
      "short_name": "Man City",
      "abbreviation": "MNC",
      "location": "Manchester City"
    },
    {
      "id": 12,
      "name": "Liverpool",
      "short_name": "Liverpool",
      "abbreviation": "LIV",
      "location": "Liverpool"
    },
    {
      "id": 7,
      "name": "Chelsea",
      "short_name": "Chelsea",
      "abbreviation": "CHE",
      "location": "Chelsea"
    },
    ...
  ]
}

This endpoint retrieves all teams.

HTTP Request

GET https://api.balldontlie.io/epl/v2/teams

Query Parameters

Parameter Required Description
season false Filter by season year. Defaults to the current season if omitted.

Rosters

Get Team Roster

curl "https://api.balldontlie.io/epl/v2/rosters?team_id=2" \
  -H "Authorization: YOUR_API_KEY"
const response = await fetch(
  "https://api.balldontlie.io/epl/v2/rosters?team_id=2",
  {
    headers: {
      "Authorization": "YOUR_API_KEY"
    }
  }
);
const data = await response.json();
import requests

response = requests.get(
    "https://api.balldontlie.io/epl/v2/rosters",
    params={"team_id": 2},
    headers={"Authorization": "YOUR_API_KEY"}
)
data = response.json()

The above command returns JSON structured like this:

{
  "data": [
    {
      "team_id": 2,
      "player": {
        "id": 33,
        "first_name": "William",
        "last_name": "Saliba",
        "display_name": "William Saliba",
        "short_name": "W Saliba",
        "date_of_birth": "2001-03-24",
        "age": 24,
        "height": "6' 4\"",
        "weight": "203 lbs",
        "citizenship": "France"
      },
      "season": 2025,
      "jersey_number": "2",
      "position": "Defender",
      "position_abbreviation": "D",
      "is_active": true
    },
    {
      "team_id": 2,
      "player": {
        "id": 38,
        "first_name": "Bukayo",
        "last_name": "Saka",
        "display_name": "Bukayo Saka",
        "short_name": "B Saka",
        "date_of_birth": "2001-09-05",
        "age": 24,
        "height": "5' 10\"",
        "weight": "159 lbs",
        "citizenship": "England"
      },
      "season": 2025,
      "jersey_number": "7",
      "position": "Forward",
      "position_abbreviation": "F",
      "is_active": true
    },
    ...
  ]
}

This endpoint retrieves the roster for a specific team.

HTTP Request

GET https://api.balldontlie.io/epl/v2/rosters

Query Parameters

Parameter Required Description
team_id true The team ID to get roster for
season false Returns roster for this season

Players

Get All Players

curl "https://api.balldontlie.io/epl/v2/players?per_page=5" \
  -H "Authorization: YOUR_API_KEY"
const response = await fetch(
  "https://api.balldontlie.io/epl/v2/players?per_page=5",
  {
    headers: {
      "Authorization": "YOUR_API_KEY"
    }
  }
);
const data = await response.json();
import requests

response = requests.get(
    "https://api.balldontlie.io/epl/v2/players",
    params={"per_page": 5},
    headers={"Authorization": "YOUR_API_KEY"}
)
data = response.json()

The above command returns JSON structured like this:

{
  "data": [
    {
      "id": 214,
      "first_name": "Aaron",
      "last_name": "Anselmino",
      "display_name": "Aaron Anselmino",
      "short_name": "A. Anselmino",
      "date_of_birth": "2005-04-29",
      "age": 20,
      "height": "6' 1\"",
      "weight": "183 lbs",
      "citizenship": "Argentina",
      "preferred_foot": "Right",
      "contract_until": "2026-06-30",
      "market_value_euro": 12700000,
      "market_value_updated_at": "2026-04-26",
      "team_ids": [
        7
      ]
    },
    {
      "id": 4027,
      "first_name": "Aaron",
      "last_name": "Bott",
      "display_name": "Aaron Bott",
      "short_name": "A. Bott",
      "date_of_birth": "2004-09-06",
      "age": 21,
      "height": null,
      "weight": null,
      "citizenship": "England",
      "preferred_foot": "Right",
      "contract_until": "2027-06-30",
      "market_value_euro": null,
      "market_value_updated_at": null,
      "team_ids": [
        16
      ]
    },
    {
      "id": 6375,
      "first_name": "Aaron",
      "last_name": "Connolly",
      "display_name": "Aaron Connolly",
      "short_name": "A Connolly",
      "date_of_birth": "2000-01-28",
      "age": 25,
      "height": "5' 9\"",
      "weight": "161 lbs",
      "citizenship": "Republic of Ireland",
      "preferred_foot": null,
      "contract_until": null,
      "market_value_euro": null,
      "market_value_updated_at": null,
      "team_ids": [
        5
      ]
    }
  ]
}

This endpoint retrieves all players.

HTTP Request

GET https://api.balldontlie.io/epl/v2/players

Query Parameters

Parameter Required Description
cursor false The cursor for pagination
per_page false Number of results per page (max 100)
team_ids false Filter by team IDs (array)
search false Search by player name

Standings

Get Standings

curl "https://api.balldontlie.io/epl/v2/standings" \
  -H "Authorization: YOUR_API_KEY"
const response = await fetch(
  "https://api.balldontlie.io/epl/v2/standings",
  {
    headers: {
      "Authorization": "YOUR_API_KEY"
    }
  }
);
const data = await response.json();
import requests

response = requests.get(
    "https://api.balldontlie.io/epl/v2/standings",
    headers={"Authorization": "YOUR_API_KEY"}
)
data = response.json()

The above command returns JSON structured like this:

{
  "data": [
    {
      "team": {
        "id": 2,
        "name": "Arsenal",
        "short_name": "Arsenal",
        "abbreviation": "ARS",
        "location": "Arsenal"
      },
      "season": 2025,
      "rank": 1,
      "rank_change": 0,
      "group_name": "English Premier League 2025-2026",
      "note": "Champions League",
      "games_played": 21,
      "wins": 15,
      "losses": 2,
      "draws": 4,
      "points": 49,
      "goals_for": 40,
      "goals_against": 14,
      "goal_differential": 26,
      "points_per_game": 0
    },
    {
      "team": {
        "id": 13,
        "name": "Manchester City",
        "short_name": "Man City",
        "abbreviation": "MNC",
        "location": "Manchester City"
      },
      "season": 2025,
      "rank": 2,
      "rank_change": 0,
      "group_name": "English Premier League 2025-2026",
      "note": "Champions League",
      "games_played": 22,
      "wins": 13,
      "losses": 5,
      "draws": 4,
      "points": 43,
      "goals_for": 45,
      "goals_against": 21,
      "goal_differential": 24,
      "points_per_game": 0
    },
    ...
  ]
}

This endpoint retrieves team standings.

HTTP Request

GET https://api.balldontlie.io/epl/v2/standings

Query Parameters

Parameter Required Description
season false Returns team standings for this season

Matches

Get All Matches

curl "https://api.balldontlie.io/epl/v2/matches?dates[]=2024-12-22" \
  -H "Authorization: YOUR_API_KEY"
const response = await fetch(
  "https://api.balldontlie.io/epl/v2/matches?dates[]=2024-12-22",
  {
    headers: {
      "Authorization": "YOUR_API_KEY"
    }
  }
);
const data = await response.json();
import requests

response = requests.get(
    "https://api.balldontlie.io/epl/v2/matches",
    params={"dates[]": "2024-12-22"},
    headers={"Authorization": "YOUR_API_KEY"}
)
data = response.json()

The above command returns JSON structured like this:

{
  "data": [
    {
      "id": 1887,
      "season": 2025,
      "home_team_id": 2,
      "away_team_id": 15,
      "date": "2026-04-25T16:30:00.000Z",
      "name": "Newcastle United at Arsenal",
      "short_name": "NEW @ ARS",
      "status": "STATUS_FULL_TIME",
      "status_detail": "FT",
      "home_score": 1,
      "away_score": 0,
      "venue_name": "Emirates Stadium",
      "venue_city": "London",
      "attendance": 60204,
      "referee_name": "Samuel Barrott",
      "referee_country": "England",
      "round_number": 34,
      "venue_latitude": 51.55504,
      "venue_longitude": -0.1084,
      "venue_capacity": 60704,
      "venue_stadium_name": "Emirates Stadium",
      "home_formation": "4-3-3",
      "away_formation": "4-1-4-1",
      "home_manager_name": "Mikel Arteta",
      "away_manager_name": "Eddie Howe",
      "first_half_home_score": 1,
      "first_half_away_score": 0,
      "second_half_home_score": 0,
      "second_half_away_score": 0
    }
  ]
}

This endpoint retrieves all matches.

HTTP Request

GET https://api.balldontlie.io/epl/v2/matches

Query Parameters

Parameter Required Description
cursor false The cursor for pagination
per_page false Number of results per page (max 100)
season false Returns matches for this season
team_ids false Filter matches by team IDs (array)
dates false Filter by dates (array, YYYY-MM-DD)

Match Events

Get Match Events

curl "https://api.balldontlie.io/epl/v2/match_events?match_ids[]=371" \
  -H "Authorization: YOUR_API_KEY"
const response = await fetch(
  "https://api.balldontlie.io/epl/v2/match_events?match_ids[]=371",
  {
    headers: {
      "Authorization": "YOUR_API_KEY"
    }
  }
);
const data = await response.json();
import requests

response = requests.get(
    "https://api.balldontlie.io/epl/v2/match_events",
    params={"match_ids[]": 371},
    headers={"Authorization": "YOUR_API_KEY"}
)
data = response.json()

The above command returns JSON structured like this:

{
  "data": [
    {
      "id": 24832,
      "match_id": 371,
      "team_id": 1,
      "event_type": "goal",
      "event_time": 74,
      "period": 2,
      "player": {
        "id": 20,
        "first_name": "Antoine",
        "last_name": "Semenyo",
        "display_name": "Antoine Semenyo",
        "short_name": "A Semenyo",
        "date_of_birth": "2000-01-07",
        "age": 26,
        "height": "6' 1\"",
        "weight": "172 lbs",
        "citizenship": "Ghana"
      },
      "secondary_player": null,
      "goal_type": "regular",
      "is_own_goal": false
    },
    {
      "id": 24827,
      "match_id": 371,
      "team_id": 131,
      "event_type": "yellow_card",
      "event_time": 38,
      "period": 1,
      "player": {
        "id": 2779,
        "first_name": "Conor",
        "last_name": "Coady",
        "display_name": "Conor Coady",
        "short_name": "C Coady",
        "date_of_birth": "1993-02-25",
        "age": 32,
        "height": "6' 1\"",
        "weight": "174 lbs",
        "citizenship": "England"
      },
      "secondary_player": null,
      "goal_type": null,
      "is_own_goal": false
    },
    {
      "id": 24828,
      "match_id": 371,
      "team_id": 1,
      "event_type": "substitution",
      "event_time": 63,
      "period": 2,
      "player": {
        "id": 17,
        "first_name": "Daniel",
        "last_name": "Jebbison",
        "display_name": "Daniel Jebbison",
        "short_name": "D Jebbison",
        "date_of_birth": "2003-08-13",
        "age": 22,
        "height": "6' 3\"",
        "weight": "150 lbs",
        "citizenship": "Canada"
      },
      "secondary_player": null,
      "goal_type": null,
      "is_own_goal": false
    },
    ...
  ]
}

This endpoint retrieves events (goals, cards, substitutions) for matches.

HTTP Request

GET https://api.balldontlie.io/epl/v2/match_events

Query Parameters

Parameter Required Description
match_ids false Filter by match IDs (array)
cursor false The cursor for pagination
per_page false Number of results per page (max 100)

Match Lineups

Get Match Lineups

curl "https://api.balldontlie.io/epl/v2/match_lineups?match_ids[]=371" \
  -H "Authorization: YOUR_API_KEY"
const response = await fetch(
  "https://api.balldontlie.io/epl/v2/match_lineups?match_ids[]=371",
  {
    headers: {
      "Authorization": "YOUR_API_KEY"
    }
  }
);
const data = await response.json();
import requests

response = requests.get(
    "https://api.balldontlie.io/epl/v2/match_lineups",
    params={"match_ids[]": 371},
    headers={"Authorization": "YOUR_API_KEY"}
)
data = response.json()

The above command returns JSON structured like this:

{
  "data": [
    {
      "match_id": 371,
      "team_id": 1,
      "player": {
        "id": 11,
        "first_name": "Kepa",
        "last_name": "Arrizabalaga",
        "display_name": "Kepa Arrizabalaga",
        "short_name": "K Arrizabalaga",
        "date_of_birth": "1994-10-03",
        "age": 31,
        "height": "6' 2\"",
        "weight": "183 lbs",
        "citizenship": "Spain"
      },
      "is_starter": true,
      "position": "Goalkeeper",
      "position_abbreviation": "G",
      "formation_position": "1",
      "jersey_number": null
    },
    {
      "match_id": 371,
      "team_id": 1,
      "player": {
        "id": 20,
        "first_name": "Antoine",
        "last_name": "Semenyo",
        "display_name": "Antoine Semenyo",
        "short_name": "A Semenyo",
        "date_of_birth": "2000-01-07",
        "age": 26,
        "height": "6' 1\"",
        "weight": "172 lbs",
        "citizenship": "Ghana"
      },
      "is_starter": true,
      "position": "Attacking Midfielder Left",
      "position_abbreviation": "AM-L",
      "formation_position": "11",
      "jersey_number": null
    },
    ...
  ]
}

This endpoint retrieves lineups for matches.

HTTP Request

GET https://api.balldontlie.io/epl/v2/match_lineups

Query Parameters

Parameter Required Description
match_ids false Filter by match IDs (array)
cursor false The cursor for pagination
per_page false Number of results per page (max 100)

Player Match Stats

Get Player Match Stats

curl "https://api.balldontlie.io/epl/v2/player_match_stats?match_ids[]=371" \
  -H "Authorization: YOUR_API_KEY"
const response = await fetch(
  "https://api.balldontlie.io/epl/v2/player_match_stats?match_ids[]=371",
  {
    headers: {
      "Authorization": "YOUR_API_KEY"
    }
  }
);
const data = await response.json();
import requests

response = requests.get(
    "https://api.balldontlie.io/epl/v2/player_match_stats",
    params={"match_ids[]": 371},
    headers={"Authorization": "YOUR_API_KEY"}
)
data = response.json()

The above command returns JSON structured like this:

{
  "data": [
    {
      "match_id": 1887,
      "player_id": 698,
      "team_id": 2,
      "appearances": 1,
      "goals": 0,
      "assists": 0,
      "shots_total": 0,
      "shots_on_target": 0,
      "fouls_committed": 2,
      "fouls_suffered": 2,
      "offsides": 1,
      "saves": null,
      "yellow_cards": 0,
      "red_cards": 0,
      "own_goals": 0,
      "rating": 7.7,
      "minutes_played": 98,
      "expected_goals": null,
      "expected_assists": 0.254,
      "key_passes": 1,
      "passes_total": 16,
      "passes_accurate": 14,
      "long_balls_total": 2,
      "long_balls_accurate": 1,
      "crosses_total": 1,
      "crosses_accurate": null,
      "dribbles_attempted": 2,
      "dribbles_completed": 1,
      "duels_won": 9,
      "duels_lost": 4,
      "aerial_duels_won": 1,
      "aerial_duels_lost": 1,
      "tackles": 5,
      "tackles_won": 2,
      "interceptions": 4,
      "clearances": 5,
      "ball_recoveries": 3,
      "touches": 43,
      "possession_lost": 5,
      "was_fouled": 2,
      "big_chances_created": null,
      "big_chances_missed": null,
      "blocked_shots": null,
      "hit_woodwork": null,
      "total_progression": 23.53,
      "ball_carries_count": 4,
      "ball_carries_distance": 31.23,
      "goalkeeper_saves": null,
      "saves_inside_box": null,
      "penalty_saves": null,
      "punches": null,
      "keeper_sweeper_total": null,
      "keeper_sweeper_accurate": null,
      "shirt_number": 5,
      "lineup_position": "D",
      "was_substitute": false
    },
    {
      "match_id": 1887,
      "player_id": 39,
      "team_id": 2,
      "appearances": 1,
      "goals": 0,
      "assists": 0,
      "shots_total": 1,
      "shots_on_target": 1,
      "fouls_committed": 0,
      "fouls_suffered": 0,
      "offsides": 0,
      "saves": null,
      "yellow_cards": 0,
      "red_cards": 0,
      "own_goals": 0,
      "rating": 7.6,
      "minutes_played": 98,
      "expected_goals": 0.032,
      "expected_assists": 0.198,
      "key_passes": 3,
      "passes_total": 57,
      "passes_accurate": 49,
      "long_balls_total": 2,
      "long_balls_accurate": 1,
      "crosses_total": 1,
      "crosses_accurate": 1,
      "dribbles_attempted": 2,
      "dribbles_completed": null,
      "duels_won": 2,
      "duels_lost": 3,
      "aerial_duels_won": null,
      "aerial_duels_lost": null,
      "tackles": 2,
      "tackles_won": 2,
      "interceptions": null,
      "clearances": null,
      "ball_recoveries": 6,
      "touches": 71,
      "possession_lost": 15,
      "was_fouled": null,
      "big_chances_created": null,
      "big_chances_missed": null,
      "blocked_shots": null,
      "hit_woodwork": null,
      "total_progression": 126.01,
      "ball_carries_count": 29,
      "ball_carries_distance": 280.02,
      "goalkeeper_saves": null,
      "saves_inside_box": null,
      "penalty_saves": null,
      "punches": null,
      "keeper_sweeper_total": null,
      "keeper_sweeper_accurate": null,
      "shirt_number": 8,
      "lineup_position": "M",
      "was_substitute": false
    },
    {
      "match_id": 1887,
      "player_id": 243,
      "team_id": 2,
      "appearances": 1,
      "goals": 1,
      "assists": 0,
      "shots_total": 3,
      "shots_on_target": 1,
      "fouls_committed": 0,
      "fouls_suffered": 1,
      "offsides": 0,
      "saves": null,
      "yellow_cards": 0,
      "red_cards": 0,
      "own_goals": 0,
      "rating": 7.5,
      "minutes_played": 53,
      "expected_goals": 0.132,
      "expected_assists": 0,
      "key_passes": null,
      "passes_total": 11,
      "passes_accurate": 5,
      "long_balls_total": null,
      "long_balls_accurate": null,
      "crosses_total": 1,
      "crosses_accurate": null,
      "dribbles_attempted": 2,
      "dribbles_completed": 1,
      "duels_won": 3,
      "duels_lost": 1,
      "aerial_duels_won": 1,
      "aerial_duels_lost": null,
      "tackles": null,
      "tackles_won": null,
      "interceptions": null,
      "clearances": null,
      "ball_recoveries": 1,
      "touches": 18,
      "possession_lost": 8,
      "was_fouled": 1,
      "big_chances_created": null,
      "big_chances_missed": null,
      "blocked_shots": null,
      "hit_woodwork": null,
      "total_progression": 18.73,
      "ball_carries_count": 7,
      "ball_carries_distance": 65.23,
      "goalkeeper_saves": null,
      "saves_inside_box": null,
      "penalty_saves": null,
      "punches": null,
      "keeper_sweeper_total": null,
      "keeper_sweeper_accurate": null,
      "shirt_number": 10,
      "lineup_position": "F",
      "was_substitute": false
    }
  ]
}

This endpoint retrieves player statistics for matches.

HTTP Request

GET https://api.balldontlie.io/epl/v2/player_match_stats

Query Parameters

Parameter Required Description
match_ids false Filter by match IDs (array)
player_ids false Filter by player IDs (array)
cursor false The cursor for pagination
per_page false Number of results per page (max 100)

Team Match Stats

Get Team Match Stats

curl "https://api.balldontlie.io/epl/v2/team_match_stats?match_ids[]=371" \
  -H "Authorization: YOUR_API_KEY"
const response = await fetch(
  "https://api.balldontlie.io/epl/v2/team_match_stats?match_ids[]=371",
  {
    headers: {
      "Authorization": "YOUR_API_KEY"
    }
  }
);
const data = await response.json();
import requests

response = requests.get(
    "https://api.balldontlie.io/epl/v2/team_match_stats",
    params={"match_ids[]": 371},
    headers={"Authorization": "YOUR_API_KEY"}
)
data = response.json()

The above command returns JSON structured like this:

{
  "data": [
    {
      "match_id": 1887,
      "team_id": 2,
      "possession_pct": 45.4,
      "shots": 11,
      "shots_on_target": 4,
      "fouls": 13,
      "yellow_cards": 2,
      "red_cards": 0,
      "corners": null,
      "passes": 397,
      "pass_accuracy_pct": null,
      "expected_goals": 0.64,
      "big_chances": 0,
      "big_chances_missed": 0,
      "shots_off_target": 2,
      "shots_blocked": 5,
      "shots_inside_box": 6,
      "shots_outside_box": 5,
      "hit_woodwork": 0,
      "offsides": 2,
      "throw_ins": 11,
      "goal_kicks": 6,
      "free_kicks": 10,
      "long_balls_total": 44,
      "long_balls_accurate": 12,
      "crosses_total": 13,
      "crosses_accurate": 2,
      "ground_duels_won": 28,
      "ground_duels_total": 58,
      "aerial_duels_won": 9,
      "aerial_duels_total": 25,
      "dribbles_completed": 5,
      "dribbles_total": 14,
      "tackles": 15,
      "interceptions": 10,
      "clearances": 20,
      "saves": 3,
      "big_saves": 0
    },
    {
      "match_id": 1887,
      "team_id": 15,
      "possession_pct": 54.6,
      "shots": 13,
      "shots_on_target": 3,
      "fouls": 10,
      "yellow_cards": 2,
      "red_cards": 0,
      "corners": null,
      "passes": 479,
      "pass_accuracy_pct": null,
      "expected_goals": 0.94,
      "big_chances": 2,
      "big_chances_missed": 2,
      "shots_off_target": 5,
      "shots_blocked": 5,
      "shots_inside_box": 6,
      "shots_outside_box": 7,
      "hit_woodwork": 0,
      "offsides": 1,
      "throw_ins": 11,
      "goal_kicks": 8,
      "free_kicks": 13,
      "long_balls_total": 48,
      "long_balls_accurate": 20,
      "crosses_total": 18,
      "crosses_accurate": 5,
      "ground_duels_won": 30,
      "ground_duels_total": 58,
      "aerial_duels_won": 16,
      "aerial_duels_total": 25,
      "dribbles_completed": 2,
      "dribbles_total": 9,
      "tackles": 16,
      "interceptions": 12,
      "clearances": 19,
      "saves": 3,
      "big_saves": 1
    }
  ]
}

This endpoint retrieves team statistics for matches.

HTTP Request

GET https://api.balldontlie.io/epl/v2/team_match_stats

Query Parameters

Parameter Required Description
match_ids false Filter by match IDs (array)
team_ids false Filter by team IDs (array)
cursor false The cursor for pagination
per_page false Number of results per page (max 100)

Betting Odds

Get Betting Odds

curl "https://api.balldontlie.io/epl/v2/odds?per_page=3" \
  -H "Authorization: YOUR_API_KEY"
const response = await fetch(
  "https://api.balldontlie.io/epl/v2/odds?per_page=3",
  {
    headers: {
      "Authorization": "YOUR_API_KEY"
    }
  }
);
const data = await response.json();
import requests

response = requests.get(
    "https://api.balldontlie.io/epl/v2/odds",
    params={"per_page": 3},
    headers={"Authorization": "YOUR_API_KEY"}
)
data = response.json()

The above command returns JSON structured like this:

{
  "data": [
    {
      "id": 89549453,
      "match_id": 1773,
      "vendor": "caesars",
      "moneyline_home_odds": -110,
      "moneyline_away_odds": 260,
      "moneyline_draw_odds": 280,
      "updated_at": "2026-01-17T15:01:00.387Z"
    },
    {
      "id": 89548970,
      "match_id": 1773,
      "vendor": "draftkings",
      "moneyline_home_odds": -115,
      "moneyline_away_odds": 270,
      "moneyline_draw_odds": 275,
      "updated_at": "2026-01-17T15:01:00.490Z"
    },
    {
      "id": 89548959,
      "match_id": 1773,
      "vendor": "fanduel",
      "moneyline_home_odds": -120,
      "moneyline_away_odds": 290,
      "moneyline_draw_odds": 290,
      "updated_at": "2026-01-17T15:01:00.416Z"
    }
  ],
  "meta": {
    "next_cursor": 89548959,
    "per_page": 3
  }
}

This endpoint retrieves betting odds for Premier League matches. Premier League odds include moneyline odds for home, away, and draw outcomes only (no spreads or totals).

Available Vendors:

Vendor Description
caesars Caesars Sportsbook
draftkings DraftKings
fanatics Fanatics Sportsbook
fanduel FanDuel
polymarket Polymarket (prediction market)

HTTP Request

GET https://api.balldontlie.io/epl/v2/odds

Query Parameters

Parameter Required Description
cursor false The cursor for pagination
per_page false Number of results per page (max 100)
match_ids false Filter by match IDs (array)
dates false Filter by dates (array, YYYY-MM-DD)

Player Props

The Player Props API provides real-time player prop betting odds for Premier League matches. Player props allow betting on individual player performances such as goals, assists, shots on target, saves, and more.

Market Types

The API supports two market types:

Get Player Props

curl "https://api.balldontlie.io/epl/v2/odds/player_props?match_id=2410" \
  -H "Authorization: YOUR_API_KEY"
const response = await fetch(
  "https://api.balldontlie.io/epl/v2/odds/player_props?match_id=2410",
  {
    headers: {
      "Authorization": "YOUR_API_KEY"
    }
  }
);
const data = await response.json();
import requests

response = requests.get(
    "https://api.balldontlie.io/epl/v2/odds/player_props",
    params={"match_id": 2410},
    headers={"Authorization": "YOUR_API_KEY"}
)
data = response.json()

The above command returns JSON structured like this:

{
  "data": [
    {
      "id": 1125005626,
      "match_id": 2410,
      "player_id": 1240,
      "vendor": "fanduel",
      "prop_type": "anytime_goal",
      "line_value": "1",
      "market": {
        "type": "milestone",
        "odds": 5000
      },
      "updated_at": "2025-12-22T21:54:02.301Z"
    },
    {
      "id": 1125005616,
      "match_id": 2410,
      "player_id": 1243,
      "vendor": "fanduel",
      "prop_type": "shots",
      "line_value": "5",
      "market": {
        "type": "milestone",
        "odds": 2700
      },
      "updated_at": "2025-12-22T21:54:02.301Z"
    },
    {
      "id": 1125005617,
      "match_id": 2410,
      "player_id": 1243,
      "vendor": "fanduel",
      "prop_type": "shots_on_target",
      "line_value": "4",
      "market": {
        "type": "milestone",
        "odds": 6000
      },
      "updated_at": "2025-12-22T21:54:02.301Z"
    },
    ...
  ]
}

This endpoint retrieves player prop betting odds for a specific Premier League match. The match_id parameter is required.

Available Vendors:

Vendor Description
caesars Caesars Sportsbook
draftkings DraftKings
fanduel FanDuel

HTTP Request

GET https://api.balldontlie.io/epl/v2/odds/player_props

Query Parameters

Parameter Required Description
match_id true The match ID to retrieve player props for
player_id false Filter props for a specific player
prop_type false Filter by prop type. See supported types.

Supported Prop Types

The following prop_type values are supported:

Prop Type Description
anytime_goal Score a goal anytime in match
assists Total assists
first_goal Score the first goal of match
first_half_goal Score a goal in the first half
goals_assists Combined goals and assists
header_goal Score a goal with a header
last_goal Score the last goal of match
outside_box_goal Score from outside the box
saves Total saves (goalkeepers)
second_half_goal Score a goal in the second half
shots Total shots
shots_on_target Total shots on target
tackles Total tackles

Note: The actual prop types available may vary by match and sportsbook vendor.

Advanced Match Data Coverage

Advanced match data - expected goals (xG), expected assists (xA), player ratings, momentum graphs, shot maps, average positions, best players, heatmaps, manager names, formations, and the additional team / player metrics in the new endpoints below - is available only for matches played in the current and future seasons:

Older matches still return core data (final score, status, basic player and team stats, lineups, events) as they always have, but the advanced fields above will be null.

Match Shots

Get Match Shots

curl "https://api.balldontlie.io/epl/v2/match_shots?match_ids[]=1887" \
  -H "Authorization: YOUR_API_KEY"

The above command returns JSON structured like this:

{
  "data": [
    {
      "id": 75890,
      "match_id": 1887,
      "player_id": 243,
      "team_id": 2,
      "is_home": true,
      "shot_type": "goal",
      "situation": "corner",
      "body_part": "right-foot",
      "goal_type": "regular",
      "xg": 0.0305,
      "xgot": 0.5614,
      "player_x": 19.6,
      "player_y": 65.4,
      "goal_mouth_x": 0,
      "goal_mouth_y": 54,
      "block_x": null,
      "block_y": null,
      "time_minute": 9,
      "added_time": null,
      "time_seconds": 530
    }
  ],
  "meta": { "next_cursor": 75890, "per_page": 25 }
}

Returns the shot map for one or more matches. Each shot includes expected goals (xG), expected goals on target (xGoT), and pitch coordinates normalized 0-100. goal_mouth_x / goal_mouth_y show where the shot crossed the goal line; block_x / block_y are populated only for blocked shots.

Available for matches in the current and future seasons only - older matches return empty results. Requires GOAT tier.

HTTP Request

GET https://api.balldontlie.io/epl/v2/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, corner, set-piece) - nullable
body_part string Body part used (e.g. right-foot, left-foot, head) - nullable
goal_type string Type of goal (e.g. regular, own-goal) - nullable
xg number Expected goals value (0-1)
xgot number Expected goals on target value (0-1)
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/epl/v2/match_momentum?match_ids[]=1887" \
  -H "Authorization: YOUR_API_KEY"

The above command returns JSON structured like this:

{
  "data": [
    {
  "match_id": 1887,
  "minute": 1,
  "value": 3
}, {
  "match_id": 1887,
  "minute": 2,
  "value": 4
}, {
  "match_id": 1887,
  "minute": 3,
  "value": 5
}
  ],
  "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. The minute field may include fractional values during stoppage time.

Available for matches in the current and future seasons only. Requires GOAT tier.

HTTP Request

GET https://api.balldontlie.io/epl/v2/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 (positive: home favored)

Match Best Players

Get Match Best Players

curl "https://api.balldontlie.io/epl/v2/match_best_players?match_ids[]=1887" \
  -H "Authorization: YOUR_API_KEY"

The above command returns JSON structured like this:

{
  "data": [
    {
      "match_id": 1887,
      "player_id": 243,
      "team_id": 2,
      "is_home": true,
      "side_rank": 1,
      "is_man_of_match": false,
      "rating": 7.5
    }
  ],
  "meta": { "next_cursor": 200, "per_page": 25 }
}

Returns the top-rated players for each match - up to 5 standout performers per side, plus the man of the match. Use is_home to identify which side the player belongs to and side_rank (1 = top performer) to order within each side.

Available for matches in the current and future seasons only. Requires GOAT tier.

HTTP Request

GET https://api.balldontlie.io/epl/v2/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 on a 0-10 scale - nullable

Match Average Positions

Get Match Average Positions

curl "https://api.balldontlie.io/epl/v2/match_avg_positions?match_ids[]=1887&team_ids[]=2" \
  -H "Authorization: YOUR_API_KEY"

The above command returns JSON structured like this:

{
  "data": [
    {
      "match_id": 1887,
      "player_id": 39,
      "team_id": 2,
      "is_home": true,
      "avg_x": 60.12,
      "avg_y": 32.99
    }
  ],
  "meta": { "next_cursor": 200, "per_page": 25 }
}

Returns each player's average pitch position for a given match - a single (x, y) centroid summarising where the player spent most of their time. Coordinates are normalized 0-100 from the home side's perspective.

Available for matches in the current and future seasons only. Requires GOAT tier.

HTTP Request

GET https://api.balldontlie.io/epl/v2/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 Heatmaps

Get Match Heatmaps

curl "https://api.balldontlie.io/epl/v2/match_heatmaps?match_ids[]=1887&player_ids[]=459" \
  -H "Authorization: YOUR_API_KEY"

The above command returns JSON structured like this:

{
  "data": [
    {
      "match_id": 1887,
      "player_id": 459,
      "team_id": 15,
      "dot_count": 96,
      "dots": [{
  "x": 29,
  "y": 66
}, {
  "x": 30,
  "y": 72
}, {
  "x": 30,
  "y": 72
}, ...]
    }
  ],
  "meta": { "next_cursor": 200, "per_page": 25 }
}

Returns per-player heatmap dots - the discrete touch / movement events that, plotted together, reveal where on the pitch a player spent their time. Coordinates are normalized 0-100. dot_count is the total number of dots in the dots array.

Available for matches in the current and future seasons only. Requires GOAT tier.

HTTP Request

GET https://api.balldontlie.io/epl/v2/match_heatmaps

Query Parameters

Parameter Type Description
match_ids[] int[] Optional. Filter to specific match IDs.
player_ids[] int[] Optional. Filter to specific player IDs (recommended - heatmap blobs are large).
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 - nullable
dots array Array of {x, y} integer points
dot_count int Total number of dots

Match Pregame Forms

Get Match Pregame Forms

curl "https://api.balldontlie.io/epl/v2/match_pregame_forms?match_ids[]=1887" \
  -H "Authorization: YOUR_API_KEY"

The above command returns JSON structured like this:

{
  "data": [
    {
      "match_id": 1887,
      "team_id": 2,
      "is_home": true,
      "avg_rating": 6.9,
      "position": 2,
      "value": "70",
      "form": ["W", "W", "W", "L", "L"]
    }
  ],
  "meta": { "next_cursor": 200, "per_page": 25 }
}

Returns a pre-match team-form summary - one row per side. Each row shows the team's recent average rating, league position entering the match, a value summary string (typically points earned across recent matches), and a form array of 1-5 of the team's most-recent results in W / D / L form (newest first). Early-season fixtures may have fewer than 5 entries.

Available for matches in the current and future seasons only. Requires GOAT tier.

HTTP Request

GET https://api.balldontlie.io/epl/v2/match_pregame_forms

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 League position going into the match - nullable
value string Recent-points summary string - nullable
form array Up to 5 of most-recent results (W/D/L) - nullable