> ## 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.

# Data Model

> How events, markets, participants, lines, and prices relate to each other in the V2 API.

The V2 API organizes sports data in a nested hierarchy. Understanding this structure is essential for parsing event responses, building odds screens, and processing delta updates.

## Hierarchy Overview

```
Event
├── score                    # Live score, game clock, status
├── teams[]                  # Away team (index 0), Home team (index 1)
├── schedule                 # Season info, event name
└── markets[]                # Array of market types
      ├── market_id          # e.g., 1 = Moneyline, 2 = Spread, 3 = Total
      ├── period_id          # 0 = full game, 1 = first half, etc.
      └── participants[]     # Teams, players, or result types
            ├── id           # Participant identifier
            ├── type         # TYPE_TEAM, TYPE_PLAYER, or TYPE_RESULT
            └── lines[]      # Available lines for this participant
                  ├── id     # 32-character hex line identifier
                  ├── value  # Line value (e.g., "-3.5") or empty for moneyline
                  └── prices # Map of affiliate_id → price object
                        {affiliate_id}:
                          ├── id            # Numeric string price identifier
                          ├── price         # American odds (e.g., -110, +150)
                          ├── is_main_line  # true if this is the consensus line
                          └── updated_at    # ISO 8601 timestamp
```

## Event Object

Each event represents a single game or match. Events are the top-level objects returned by `/api/v2/sports/{sportID}/events/{date}`.

| Field                  | Type    | Description                                                                                                    |
| ---------------------- | ------- | -------------------------------------------------------------------------------------------------------------- |
| `event_id`             | string  | Canonical event identifier string. Use this value in V2 path params, filters, delta consumers, and cache keys. |
| `sport_id`             | integer | Sport identifier. See [Sport IDs](/reference/sports).                                                          |
| `event_uuid`           | string  | Compatibility identifier retained for older integrations. Do not assume it matches `event_id`.                 |
| `event_date`           | string  | Scheduled start time in ISO 8601 UTC                                                                           |
| `rotation_number_away` | integer | Away team rotation number (not used for soccer)                                                                |
| `rotation_number_home` | integer | Home team rotation number (not used for soccer)                                                                |
| `score`                | object  | Live score and game status. See [Score Object](#score-object) below.                                           |
| `teams`                | array   | Two-element array: `[away_team, home_team]`. See [Team Object](#team-object) below.                            |
| `schedule`             | object  | Season metadata: `season_type`, `season_year`, `event_name`, `league_name`                                     |
| `markets`              | array   | Array of [Market objects](#market-object) with odds data                                                       |

<Note>
  For V2 REST endpoints and WebSocket filters, pass the `event_id` value returned in event payloads. Do not substitute `event_uuid`.
</Note>

### Score Object

| Field                  | Type    | Description                                                                                                                       |
| ---------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `event_status`         | string  | Current status (e.g., `STATUS_SCHEDULED`, `STATUS_IN_PROGRESS`, `STATUS_FINAL`). See [Event Statuses](/reference/event-statuses). |
| `score_away`           | integer | Away team score                                                                                                                   |
| `score_home`           | integer | Home team score                                                                                                                   |
| `score_away_by_period` | array   | Score breakdown by period                                                                                                         |
| `score_home_by_period` | array   | Score breakdown by period                                                                                                         |
| `venue_name`           | string  | Arena or stadium name. May be an empty string when unavailable from the live feed.                                                |
| `venue_location`       | string  | City and state. May be an empty string when unavailable from the live feed.                                                       |
| `game_clock`           | integer | Game clock in seconds                                                                                                             |
| `display_clock`        | string  | Formatted clock display (e.g., "4:32")                                                                                            |
| `game_period`          | integer | Current period number                                                                                                             |
| `broadcast`            | string  | TV broadcast network                                                                                                              |
| `event_status_detail`  | string  | Human-readable status (e.g., "3rd Quarter - 4:32")                                                                                |
| `updated_at`           | string  | ISO 8601 timestamp of the last score update                                                                                       |

<Note>
  Treat `score` as best-effort live feed data. Fields such as `venue_name`, `venue_location`, `broadcast`, `display_clock`, and the period arrays may be empty strings, empty arrays, or `0` until the upstream source provides them. Use `updated_at` to judge freshness.
</Note>

### Team Object

| Field          | Type    | Description                                                      |
| -------------- | ------- | ---------------------------------------------------------------- |
| `team_id`      | integer | Normalized team identifier (stable across seasons and endpoints) |
| `name`         | string  | Full team name (e.g., "Cleveland Cavaliers")                     |
| `mascot`       | string  | Team mascot (e.g., "Cavaliers")                                  |
| `abbreviation` | string  | Short abbreviation (e.g., "CLE")                                 |
| `record`       | string  | Current season record (e.g., "42-14")                            |
| `is_away`      | boolean | `true` if this is the away team                                  |
| `is_home`      | boolean | `true` if this is the home team                                  |

## Market Object

Each market represents a type of bet (moneyline, spread, total, player prop, etc.). Markets are nested inside events.

| Field                | Type    | Description                                                                           |
| -------------------- | ------- | ------------------------------------------------------------------------------------- |
| `id`                 | integer | Instance identifier for this market on this event                                     |
| `market_id`          | integer | Canonical market type ID. See [Market IDs](/reference/markets).                       |
| `period_id`          | integer | Period this market applies to. `0` = full game. See [Period IDs](/reference/periods). |
| `name`               | string  | Display name (e.g., "Moneyline", "Total Over/Under")                                  |
| `market_description` | string  | Human-readable description                                                            |
| `participants`       | array   | Array of [Participant objects](#participant-object)                                   |

## Participant Object

Participants are the entities you can bet on within a market — teams, players, or result types (Over/Under).

| Field   | Type    | Description                                                              |
| ------- | ------- | ------------------------------------------------------------------------ |
| `id`    | integer | Participant identifier (team ID, player ID, or `0`/`1` for result types) |
| `type`  | string  | `TYPE_TEAM`, `TYPE_PLAYER`, or `TYPE_RESULT`                             |
| `name`  | string  | Display name (e.g., "Cleveland Cavaliers", "Donovan Mitchell", "Over")   |
| `lines` | array   | Array of [Line objects](#line-object)                                    |

<Note>
  **`id` is the stable, joinable identifier — join on `id`, not `name`.** What `id` points to depends on `type`:

  * **`TYPE_TEAM`** — `id` is the normalized team ID. It is stable across seasons and endpoints, and matches `event.teams[].team_id`. Fetch the full team at `GET /api/v2/teams/{team_id}`.
  * **`TYPE_PLAYER`** — `id` is the player ID. Fetch the full player (team, names, position) at `GET /api/v2/players/{player_id}`.
  * **`TYPE_RESULT`** — `id` is a small outcome index (e.g. `0`/`1` for Over/Under) and is **not** a team or player resource key.

  Because every distinct team and player has a distinct `id`, joining on `id` resolves shared-name collisions that joining on `name` cannot. To look up an `id` from a name once, use the roster at `GET /api/v2/teams/{team_id}/players` or the team list at `GET /api/v2/sports/{sportID}/teams`.
</Note>

## Line Object

A line represents a specific betting line for a participant. For spreads and totals, the `value` contains the line number. For moneylines, `value` is an empty string.

| Field    | Type   | Description                                                               |
| -------- | ------ | ------------------------------------------------------------------------- |
| `id`     | string | 32-character hex identifier for this line                                 |
| `value`  | string | Line value: `"-3.5"` for spread, `"224.5"` for total, `""` for moneyline  |
| `prices` | object | Map of affiliate ID → [Price object](#price-object). Keyed by sportsbook. |

<Note>
  `line_value_is_participant` tells you where the meaningful selection detail lives. When it is `true`, the participant carries the selection and the line `value` may be a placeholder or label. When it is `false`, display the line `value` when present; it may be a number, threshold, method, round, or other outcome qualifier.
</Note>

## Price Object

A price is the odds offered by a single sportsbook for a specific line.

| Field          | Type    | Description                                                                                                                                   |
| -------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`           | string  | Numeric string identifier for this price                                                                                                      |
| `price`        | number  | American odds (e.g., `-110`, `+150`). A value of `0.0001` means the line is off the board. See [Sentinel Values](/reference/sentinel-values). |
| `is_main_line` | boolean | `true` if this is the primary/consensus line. Use `main_line=true` query param to filter to main lines only.                                  |
| `updated_at`   | string  | ISO 8601 timestamp of the last price update                                                                                                   |

Fields that appear in delta/history responses:

| Field         | Type   | Description                                                                |
| ------------- | ------ | -------------------------------------------------------------------------- |
| `price_delta` | number | Difference from the previous price (present in some delta responses)       |
| `closed_at`   | string | ISO 8601 timestamp when the line was closed. Empty string if still active. |

## Traversing the Data

### Reading a moneyline price

```
event.markets[0].participants[0].lines[0].prices["19"].price
```

Gives you the DraftKings (affiliate 19) moneyline price for the first participant (away team).

### Reading a spread value and price

```
event.markets[1].participants[0].lines[0].value    → "-3.5"
event.markets[1].participants[0].lines[0].prices["19"].price → -110
```

### Iterating all prices for an event

```python theme={null}
for market in event["markets"]:
    for participant in market["participants"]:
        for line in participant["lines"]:
            for affiliate_id, price_obj in line["prices"].items():
                print(f"{market['name']} | {participant['name']} | "
                      f"{line['value']} | {affiliate_id}: {price_obj['price']}")
```

## Delta Responses

Delta endpoints return a different shape. Instead of the nested event → market → participant → line → price hierarchy, they return **flat change records**:

| Field            | Description                                   |
| ---------------- | --------------------------------------------- |
| `event_id`       | Which event changed                           |
| `market_id`      | Which market                                  |
| `participant_id` | Which participant                             |
| `affiliate_id`   | Which sportsbook                              |
| `line`           | Line value                                    |
| `price`          | New price                                     |
| `previous_price` | Previous price (empty string if new)          |
| `change_type`    | `"new"`, `"price_change"`, or `"line_change"` |

Use the `event_id`, `market_id`, `participant_id`, and `affiliate_id` to locate the correct entry in your local cache and replace the price. See the [Efficient Polling guide](/guides/efficient-polling) for the full update pattern.
