> ## Documentation Index
> Fetch the complete documentation index at: https://www.thestatsapi.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> For the complete API reference (every endpoint, query parameter and response field), fetch https://api.thestatsapi.com/llms.txt. Only use endpoints, parameters and fields listed there.
> Base URL: https://api.thestatsapi.com/api. Auth header: Authorization: Bearer YOUR_API_KEY. Keep the key in server-side code only.

# Get player and team stats, xG, shotmaps and heatmaps

> Get season stats for players and teams, per-match team and player stats with xG, shotmaps and heatmaps, and check which matches have that data.

Use this page to get season totals and per-match stats for players and teams, including xG, shots and heatmaps.

<Tip>
  **Fastest way: ask your AI.** Set up your coding tool once with [Build with AI](/docs/build-with-ai), then paste:

  ```text Prompt wrap theme={null}
  Using TheStatsAPI (reference: https://api.thestatsapi.com/llms.txt), build a player page for Bukayo Saka: his Premier League season stats, and for his last match his rating, shots, xG and a heatmap. Check the availability flags before calling optional endpoints. Keep the API key server-side.
  ```
</Tip>

## Which endpoint to use

| You want | Endpoint | Needs |
| - | - | - |
| A player's season totals | `GET /football/players/{player_id}/stats` | `season_id` (required), `competition_id` (optional) |
| A team's season record | `GET /football/teams/{team_id}/stats` | `season_id` (required) |
| Team stats for one match, with xG | `GET /football/matches/{match_id}/stats` | A finished match |
| Player stats for one match, with xG | `GET /football/matches/{match_id}/player-stats` | A finished match |
| Every shot with its xG | `GET /football/matches/{match_id}/shotmap` | `shotmap_available: true` on the match |
| A player's heatmap for one match | `GET /football/matches/{match_id}/players/{player_id}/heatmap` | The player played |
| A player's heatmap for a season | `GET /football/players/{player_id}/competitions/{competition_id}/seasons/{season_id}/heatmap` | The player played in that competition season |

For matches in progress, use the live endpoints instead. See [Live matches](/docs/guides/live-matches).

The JavaScript examples run on your server and read your key from the `THESTATSAPI_API_KEY` environment variable.

## Player season stats

`season_id` is required. Add `competition_id` to count one competition only, and `stage=regular` or `stage=playoff` to split league matches from play-offs.

<CodeGroup>
  ```bash curl theme={null}
  curl "https://api.thestatsapi.com/api/football/players/pl_45126714/stats?season_id=sn_6125938&competition_id=comp_3039" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const params = new URLSearchParams({ season_id: "sn_6125938", competition_id: "comp_3039" });
  const res = await fetch(
    `https://api.thestatsapi.com/api/football/players/pl_45126714/stats?${params}`,
    { headers: { Authorization: `Bearer ${process.env.THESTATSAPI_API_KEY}` } }
  );
  const { data } = await res.json();
  console.log(data.appearances, data.scoring.goals, data.scoring.assists);
  ```
</CodeGroup>

Response (Bukayo Saka, Premier League 25/26, trimmed):

```json Response theme={null}
{
  "data": {
    "player_id": "pl_45126714",
    "season_id": "sn_6125938",
    "competition_id": "comp_3039",
    "team_id": "tm_9145",
    "rating": 7.64,
    "appearances": 31,
    "starts": 21,
    "minutes_played": 2225,
    "scoring": { "goals": 7, "assists": 5, "big_chances_created": 12 },
    "shooting": { "total_shots": 71, "shots_on_target": 27 },
    "passing": { "total_passes": 773, "pass_accuracy": 76.7, "key_passes": 63 },
    "defending": { "tackles": 41, "interceptions": 16 },
    "discipline": { "yellow_cards": 2, "red_cards": 0 }
  }
}
```

Leave out `season_id` and you get:

```json theme={null}
{ "error": { "code": "BAD_REQUEST", "message": "season_id is required", "status_code": 400 } }
```

## Team season stats

<CodeGroup>
  ```bash curl theme={null}
  curl "https://api.thestatsapi.com/api/football/teams/tm_9145/stats?season_id=sn_6125938" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch(
    "https://api.thestatsapi.com/api/football/teams/tm_9145/stats?season_id=sn_6125938",
    { headers: { Authorization: `Bearer ${process.env.THESTATSAPI_API_KEY}` } }
  );
  const { data } = await res.json();
  ```
</CodeGroup>

```json Response theme={null}
{
  "data": {
    "team_id": "tm_9145",
    "season_id": "sn_6125938",
    "competition_id": "comp_3039",
    "matches_played": 38,
    "wins": 26,
    "draws": 7,
    "losses": 5,
    "points": 85,
    "position": 1,
    "goals_for": 71,
    "goals_against": 27,
    "goal_difference": 44,
    "form": "WWWWW"
  }
}
```

You get `404` when the team has no stats for that season.

## One match: team and player stats with xG

The examples use Brighton 3-0 Arsenal (`mt_155834755`). Team stats come split into `all`, `first_half` and `second_half`.

<CodeGroup>
  ```bash curl theme={null}
  # Team stats
  curl "https://api.thestatsapi.com/api/football/matches/mt_155834755/stats" \
    -H "Authorization: Bearer YOUR_API_KEY"

  # One player's stats (comma-separate several IDs)
  curl "https://api.thestatsapi.com/api/football/matches/mt_155834755/player-stats?player_ids=pl_45126714" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const headers = { Authorization: `Bearer ${process.env.THESTATSAPI_API_KEY}` };
  const match = "https://api.thestatsapi.com/api/football/matches/mt_155834755";

  const { data: stats } = await (await fetch(`${match}/stats`, { headers })).json();
  console.log(stats.overview.expected_goals?.all); // { home: 1.31, away: 1.63 }

  const { data: players } = await (
    await fetch(`${match}/player-stats?player_ids=pl_45126714`, { headers })
  ).json();
  console.log(players[0].rating, players[0].shooting.expected_goals);
  ```
</CodeGroup>

Team stats (trimmed):

```json Response theme={null}
{
  "data": {
    "match_id": "mt_155834755",
    "overview": {
      "ball_possession": { "all": { "home": 40, "away": 60 } },
      "expected_goals": {
        "all": { "home": 1.31, "away": 1.63 },
        "first_half": { "home": 0.36, "away": 0.39 },
        "second_half": { "home": 0.95, "away": 1.24 }
      },
      "total_shots": { "all": { "home": 17, "away": 11 } }
    }
  }
}
```

The response also has `shots`, `attack`, `passes`, `duels`, `defending`, `goalkeeping` and `np_expected_goals` groups. `expected_goals` is `null` when the match has no xG.

Player stats (trimmed):

```json Response theme={null}
{
  "data": [
    {
      "player_id": "pl_45126714",
      "player_name": "Bukayo Saka",
      "team_id": "tm_9145",
      "position": "F",
      "rating": 7.06,
      "minutes_played": 81,
      "shooting": {
        "total_shots": 2,
        "shots_on_target": 1,
        "expected_goals": 0.35,
        "expected_assists": 0.53
      }
    }
  ]
}
```

## Shotmap

Every shot with its xG, result, body part, situation and pitch position. Add `player_id` for one player's shots.

Every shot is drawn as if attacking the same goal. `x` runs from 0 at that goal line to 100 at the shooter's own goal line (the edge of the box is 16.5). `y` runs across the pitch, with 50 at the centre of the goal.

<CodeGroup>
  ```bash curl theme={null}
  curl "https://api.thestatsapi.com/api/football/matches/mt_155834755/shotmap?player_id=pl_45126714" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch(
    "https://api.thestatsapi.com/api/football/matches/mt_155834755/shotmap?player_id=pl_45126714",
    { headers: { Authorization: `Bearer ${process.env.THESTATSAPI_API_KEY}` } }
  );
  const { data: shots } = await res.json();
  for (const s of shots) console.log(s.minute, s.result, s.expected_goals, s.x, s.y);
  ```
</CodeGroup>

One shot (trimmed):

```json Response theme={null}
{
  "id": "sh_575269648",
  "player_id": "pl_45126714",
  "player_name": "Bukayo Saka",
  "team_id": "tm_9145",
  "x": 7.9,
  "y": 45.3,
  "minute": 45,
  "result": "save",
  "expected_goals": 0.303,
  "situation": "fast_break",
  "body_part": "right_foot",
  "is_goal": false,
  "is_on_target": true,
  "is_penalty": false
}
```

## Heatmaps

Heatmap points use `x` and `y` from 0 to 100.

<CodeGroup>
  ```bash curl theme={null}
  # One match
  curl "https://api.thestatsapi.com/api/football/matches/mt_155834755/players/pl_45126714/heatmap" \
    -H "Authorization: Bearer YOUR_API_KEY"

  # A whole season in one competition
  curl "https://api.thestatsapi.com/api/football/players/pl_45126714/competitions/comp_3039/seasons/sn_6125938/heatmap" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const headers = { Authorization: `Bearer ${process.env.THESTATSAPI_API_KEY}` };
  const base = "https://api.thestatsapi.com/api/football";

  const { data: matchMap } = await (
    await fetch(`${base}/matches/mt_155834755/players/pl_45126714/heatmap`, { headers })
  ).json();

  const { data: seasonMap } = await (
    await fetch(`${base}/players/pl_45126714/competitions/comp_3039/seasons/sn_6125938/heatmap`, { headers })
  ).json();
  ```
</CodeGroup>

<Tabs>
  <Tab title="Match heatmap">
    ```json theme={null}
    {
      "data": {
        "match_id": "mt_155834755",
        "player": { "id": "pl_45126714", "name": "Bukayo Saka" },
        "team": { "id": "tm_9145", "name": "Arsenal", "side": "away" },
        "points": [{ "x": 69, "y": 9 }, { "x": 31, "y": 7 }, { "x": 55, "y": 13 }]
      }
    }
    ```

    One point per touch (46 in this match).
  </Tab>

  <Tab title="Season heatmap">
    ```json theme={null}
    {
      "data": {
        "player": { "id": "pl_45126714", "name": "Bukayo Saka" },
        "competition": { "id": "comp_3039", "name": "Premier League" },
        "season": { "id": "sn_6125938", "name": "Premier League 25/26" },
        "points": [{ "x": 59, "y": 3, "count": 1 }, { "x": 59, "y": 8, "count": 3 }]
      }
    }
    ```

    Touches are grouped into pitch cells, with a `count` per cell.
  </Tab>
</Tabs>

Both return `404` when there's no heatmap, for example for an unused substitute, or a match or competition without positional data.

## Check what's available first

Not every competition or match has every kind of stat. Check these flags before you call an optional endpoint:

| Where | Flag | Meaning |
| - | - | - |
| Competition | `has_team_stats`, `has_player_stats` | The competition has team or player stats. |
| Competition | `xg_available` | The competition has xG data. |
| Match | `xg_available` | The match has xG (team-level or per-shot). |
| Match | `shotmap_available` | `/shotmap` has shots with xG values. Can be `false` while `xg_available` is `true`. |
| Match | `xg_quality` | `full` when shots carry per-shot xG, `none` otherwise. Treat unknown values as `none`. |

To find competitions with player stats or xG, use [List coverage by competition](/docs/api-reference/coverage/leagues) with `data_type=player_stats` or `data_type=xg`. To see which seasons of one competition have them, use [Get coverage for a competition](/docs/api-reference/coverage/league). See [Coverage](/docs/concepts/coverage).

`/stats` and `/player-stats` return `404` in two cases. `STATS_NOT_AVAILABLE_AT_SOURCE` means the match was only covered at score and lineup level, so detailed stats will never exist. `NOT_FOUND` means the match doesn't exist or its stats aren't in yet.

## API reference

* [Get a player's season stats](/docs/api-reference/players/stats)
* [Get a team's season stats](/docs/api-reference/teams/stats)
* [Get match stats](/docs/api-reference/matches/stats) and [Get match player stats](/docs/api-reference/matches/player-stats)
* [Get match shotmap](/docs/api-reference/matches/shotmap)
* [Get a player's match heatmap](/docs/api-reference/matches/player-heatmap) and [Get a player's season heatmap](/docs/api-reference/players/season-heatmap)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.