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

# Stats

> Stat definitions, REST box scores, and live team/player game-stat deltas

## Overview

The stats endpoints provide statistical data at multiple levels: a reference catalog of all stat definitions, team-level game stats per event, and player-level game stats per event. Season-level stats are available through the [Teams endpoints](/api-reference/v2/teams). For supported live games, changed box-score rows also stream over the V2 WebSocket.

## Live Game Stats over WebSocket

On Ultra plans and higher, subscribe to the `stats` channel on the multiplexed endpoint:

```json theme={null}
{
  "action": "subscribe",
  "id": "game-stats",
  "channel": "stats",
  "params": { "event_ids": ["EVENT_ID"] }
}
```

For supported live games, team and player changes stream at play latency — typically within a few seconds of the corresponding play-by-play update. Like all live game data (plays included), stats trail the on-field action by roughly 15–20 seconds, in line with the typical broadcast delay. The frames are row-level deltas, not full boxes: each `team_stats[].stats` or `player_stats[].stats` entry contains one changed value and its stat dictionary. Keep `value` as a string and upsert by owner ID plus `stat_id`.

Because `stats` has no snapshot or replay source, use this sequence on first connect, reconnect (including a `buffer_overflow:reconnect_and_catchup` close), or a detected gap:

1. Subscribe and buffer incoming `game_stats` frames.
2. Fetch the current team box from `GET /api/v2/events/{eventID}/stats` and player box from `GET /api/v2/events/{eventID}/players/stats`.
3. Replace your local baseline, then merge the buffered deltas in order.
4. Continue merging live deltas. A zero-row frame with `complete: true` is the terminal completion marker; mark the cached box complete and treat repeats as idempotent. A zero-row frame without `complete: true` is an invalidation fallback; refetch both REST resources.

The combined `live` channel includes the same `game_stats` frames alongside scores and plays. Each changed nested stat row costs one stats data point; a zero-row completion marker or invalidation fallback costs one. See the [WebSocket reference](/api-reference/v2/websocket#game-stats-messages) for the full payload, filters, completion and fallback shapes, and recovery rules.

***

## Endpoints

<Accordion title="GET /api/v2/stats — List all stat definitions">
  Returns the catalog of all available stat definitions, including IDs, names, and associated sports. Use this to discover which `stats_ids` are valid for filtering.

  ### Parameters

  | Parameter  | Type  | Required | Description                                                 |
  | ---------- | ----- | -------- | ----------------------------------------------------------- |
  | `id`       | query | No       | Filter by a specific stat ID                                |
  | `sport_id` | query | No       | Filter by sport ID to see only stats relevant to that sport |

  <CodeGroup>
    ```bash All stat definitions theme={null}
    curl "https://therundown.io/api/v2/stats?key=YOUR_API_KEY"
    ```

    ```bash NBA stats only theme={null}
    curl "https://therundown.io/api/v2/stats?key=YOUR_API_KEY&sport_id=4"
    ```

    ```bash Lookup a specific stat theme={null}
    curl "https://therundown.io/api/v2/stats?key=YOUR_API_KEY&id=1"
    ```

    ```python Python theme={null}
    import requests

    resp = requests.get(
        "https://therundown.io/api/v2/stats",
        headers={"X-TheRundown-Key": "YOUR_API_KEY"},
        params={"sport_id": 4}
    )
    stats = resp.json()
    for s in stats:
        print(f"{s['id']}: {s['display_name']}")
    ```

    ```javascript JavaScript theme={null}
    const resp = await fetch(
      "https://therundown.io/api/v2/stats?key=YOUR_API_KEY&sport_id=4"
    );
    const stats = await resp.json();
    stats.forEach(s => console.log(`${s.id}: ${s.display_name}`));
    ```
  </CodeGroup>

  ### Example Response

  ```json theme={null}
  [
    {
      "id": 1,
      "name": "points",
      "display_name": "Points",
      "abbreviation": "PTS",
      "sport_id": 4,
      "category": "scoring"
    },
    {
      "id": 2,
      "name": "rebounds",
      "display_name": "Rebounds",
      "abbreviation": "REB",
      "sport_id": 4,
      "category": "rebounding"
    },
    {
      "id": 3,
      "name": "assists",
      "display_name": "Assists",
      "abbreviation": "AST",
      "sport_id": 4,
      "category": "playmaking"
    },
    {
      "id": 4,
      "name": "steals",
      "display_name": "Steals",
      "abbreviation": "STL",
      "sport_id": 4,
      "category": "defense"
    },
    {
      "id": 5,
      "name": "blocks",
      "display_name": "Blocks",
      "abbreviation": "BLK",
      "sport_id": 4,
      "category": "defense"
    }
  ]
  ```
</Accordion>

<Accordion title="GET /api/v2/events/{eventID}/stats — Team game stats">
  Returns team-level statistics for a specific event (game). Includes box score data like points, rebounds, assists, etc.

  ### Parameters

  | Parameter   | Type  | Required | Description                                                                            |
  | ----------- | ----- | -------- | -------------------------------------------------------------------------------------- |
  | `eventID`   | path  | Yes      | Canonical V2 event ID from the `event_id` field                                        |
  | `stats_ids` | query | No       | Comma-separated stat IDs to include (max 12). If omitted, returns all available stats. |
  | `team_id`   | query | No       | Filter to a specific team                                                              |

  <CodeGroup>
    ```bash All team stats for a game theme={null}
    curl "https://therundown.io/api/v2/events/EVENT_ID/stats?key=YOUR_API_KEY"
    ```

    ```bash Specific stats for one team theme={null}
    curl "https://therundown.io/api/v2/events/EVENT_ID/stats?key=YOUR_API_KEY&stats_ids=1,2,3&team_id=42"
    ```

    ```python Python theme={null}
    import requests

    resp = requests.get(
        "https://therundown.io/api/v2/events/EVENT_ID/stats",
        headers={"X-TheRundown-Key": "YOUR_API_KEY"},
        params={"stats_ids": "1,2,3"}
    )

    for team_stat in resp.json():
        print(f"{team_stat['team']['name']}")
        for stat in team_stat["stats"]:
            print(f"  {stat['stat']['display_name']}: {stat['value']}")
    ```

    ```javascript JavaScript theme={null}
    const resp = await fetch(
      "https://therundown.io/api/v2/events/EVENT_ID/stats?key=YOUR_API_KEY&stats_ids=1,2,3"
    );
    const teamStats = await resp.json();
    teamStats.forEach(t => {
      console.log(t.team.name);
      t.stats.forEach(s => console.log(`  ${s.stat.display_name}: ${s.value}`));
    });
    ```
  </CodeGroup>

  ### Example Response

  ```json theme={null}
  [
    {
      "team": {
        "team_id": 42,
        "name": "Boston Celtics",
        "abbreviation": "BOS",
        "is_away": true,
        "is_home": false
      },
      "meta": { "complete": true, "event_id": "EVENT_ID" },
      "stats": [
        { "team_id": 42, "stat_id": 1, "stat": { "id": 1, "name": "points", "display_name": "Points", "abbreviation": "PTS", "sport_id": 4 }, "event_id": "EVENT_ID", "value": "112" },
        { "team_id": 42, "stat_id": 2, "stat": { "id": 2, "name": "rebounds", "display_name": "Rebounds", "abbreviation": "REB", "sport_id": 4 }, "event_id": "EVENT_ID", "value": "48" }
      ]
    },
    {
      "team": {
        "team_id": 45,
        "name": "Los Angeles Lakers",
        "abbreviation": "LAL",
        "is_away": false,
        "is_home": true
      },
      "meta": { "complete": true, "event_id": "EVENT_ID" },
      "stats": [
        { "team_id": 45, "stat_id": 1, "stat": { "id": 1, "name": "points", "display_name": "Points", "abbreviation": "PTS", "sport_id": 4 }, "event_id": "EVENT_ID", "value": "105" },
        { "team_id": 45, "stat_id": 2, "stat": { "id": 2, "name": "rebounds", "display_name": "Rebounds", "abbreviation": "REB", "sport_id": 4 }, "event_id": "EVENT_ID", "value": "42" }
      ]
    }
  ]
  ```

  <Note>
    Stats are only available for events that have started or completed. Requesting stats for a future event returns an empty array. The nested team identity includes canonical `is_away` and `is_home` flags.
  </Note>
</Accordion>

<Accordion title="GET /api/v2/events/{eventID}/players/stats — Player game stats">
  Returns individual player statistics for a specific event. Includes per-player box score data.

  ### Parameters

  | Parameter    | Type  | Required | Description                                     |
  | ------------ | ----- | -------- | ----------------------------------------------- |
  | `eventID`    | path  | Yes      | Canonical V2 event ID from the `event_id` field |
  | `stats_ids`  | query | No       | Comma-separated stat IDs to include (max 12)    |
  | `player_ids` | query | No       | Comma-separated player IDs to filter (max 6)    |

  <CodeGroup>
    ```bash All player stats for a game theme={null}
    curl "https://therundown.io/api/v2/events/EVENT_ID/players/stats?key=YOUR_API_KEY"
    ```

    ```bash Specific players theme={null}
    curl "https://therundown.io/api/v2/events/EVENT_ID/players/stats?key=YOUR_API_KEY&player_ids=100,101,102"
    ```

    ```bash Specific stat categories theme={null}
    curl "https://therundown.io/api/v2/events/EVENT_ID/players/stats?key=YOUR_API_KEY&stats_ids=1,2,3"
    ```

    ```python Python theme={null}
    import requests

    resp = requests.get(
        "https://therundown.io/api/v2/events/EVENT_ID/players/stats",
        headers={"X-TheRundown-Key": "YOUR_API_KEY"},
        params={"stats_ids": "1,2,3"}
    )
    for p in resp.json():
        print(f"{p['player']['display_name']}")
        for s in p["stats"]:
            print(f"  {s['stat']['display_name']}: {s['value']}")
    ```

    ```javascript JavaScript theme={null}
    const resp = await fetch(
      "https://therundown.io/api/v2/events/EVENT_ID/players/stats?key=YOUR_API_KEY&stats_ids=1,2,3"
    );
    const playerStats = await resp.json();
    playerStats.forEach(p => {
      console.log(p.player.display_name);
      p.stats.forEach(s => console.log(`  ${s.stat.display_name}: ${s.value}`));
    });
    ```
  </CodeGroup>

  ### Example Response

  ```json theme={null}
  [
    {
      "player": {
        "id": 1002,
        "display_name": "Jayson Tatum",
        "position": "SF",
        "team_id": 42
      },
      "meta": { "complete": true, "event_id": "EVENT_ID" },
      "stats": [
        { "stat": { "id": 1, "name": "points", "display_name": "Points", "abbreviation": "PTS", "sport_id": 4 }, "value": "32" },
        { "stat": { "id": 2, "name": "rebounds", "display_name": "Rebounds", "abbreviation": "REB", "sport_id": 4 }, "value": "9" }
      ]
    },
    {
      "player": {
        "id": 1001,
        "display_name": "LeBron James",
        "position": "SF",
        "team_id": 45
      },
      "meta": { "complete": true, "event_id": "EVENT_ID" },
      "stats": [
        { "stat": { "id": 1, "name": "points", "display_name": "Points", "abbreviation": "PTS", "sport_id": 4 }, "value": "28" },
        { "stat": { "id": 3, "name": "assists", "display_name": "Assists", "abbreviation": "AST", "sport_id": 4 }, "value": "10" }
      ]
    }
  ]
  ```

  <Note>
    Player REST rows omit IDs already represented by the group: use `player.id` for the owner, `meta.event_id` for the event, and `stat.id` for the stat key. Live WebSocket rows additionally carry explicit `player_id` and `stat_id` fields.
  </Note>
</Accordion>

<Note>
  MLB game-stat definitions include `startingPitcher` and the sparse `positionPlayerPitching` flag. Query `GET /api/v2/stats?sport_id=3` to discover their current IDs; do not hard-code IDs.
</Note>

***

## Stats at Different Levels

| Level             | Endpoint                                     | Description                        |
| ----------------- | -------------------------------------------- | ---------------------------------- |
| **Definitions**   | `GET /api/v2/stats`                          | What stats exist and their IDs     |
| **Team game**     | `GET /api/v2/events/{eventID}/stats`         | Team box score for one game        |
| **Player game**   | `GET /api/v2/events/{eventID}/players/stats` | Player box score for one game      |
| **Team season**   | `GET /api/v2/teams/{teamID}/stats`           | Aggregate team stats for a season  |
| **Player season** | `GET /api/v2/teams/{teamID}/players/stats`   | Per-player season stats for a team |
