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

# Sportrix Data Model: Sports, Leagues, and Match Objects

> Understand how Sportrix Data organizes sports data into sports, leagues, and matches — and how live snapshots relate to catalog records.

Sportrix Data organizes all sports content into a three-level hierarchy: sports contain leagues, leagues contain matches, and each match can carry a live snapshot or a final result. Understanding this structure helps you navigate the API efficiently and know which endpoint to call at each stage of a match's lifecycle.

## The hierarchy

Every piece of data in Sportrix Data flows down from a sport through a league to a match, with live and result data attached to individual matches.

<CardGroup cols={2}>
  <Card title="Sport" icon="trophy">
    The top-level category (e.g. Soccer). Your account is configured with an **enabled-sports allowlist** — you only ever see sports, leagues, and matches within that allowlist.
  </Card>

  <Card title="League" icon="list">
    A competition or tournament within a sport (e.g. USA MLS Next Pro League). Every league belongs to exactly one sport and is identified by a numeric `id`.
  </Card>

  <Card title="Match" icon="futbol">
    A single fixture between two teams within a league. Identified by a numeric `id` and carries scheduling and status information.
  </Card>

  <Card title="Live Snapshot / Result" icon="chart-line">
    Real-time or frozen point-in-time data attached to a match. A live snapshot reflects the current state; a result holds the half-time and full-time snapshots.
  </Card>
</CardGroup>

## Sport

A sport object has two fields:

| Field  | Type    | Description                                                                |
| ------ | ------- | -------------------------------------------------------------------------- |
| `id`   | integer | Numeric sport identifier — use this as the `sport` parameter on `/leagues` |
| `name` | string  | Display name, e.g. `"Soccer"`                                              |

Your account has an **enabled-sports allowlist**. Requests for sports, leagues, or matches outside that allowlist return empty results rather than an error — see [Scopes and Permissions](/concepts/scopes) for details.

## League

A league belongs to a sport and groups a set of matches together.

| Field  | Type    | Description                                                                               |
| ------ | ------- | ----------------------------------------------------------------------------------------- |
| `id`   | integer | Numeric league identifier — use this as the `league` parameter on `/matches` and `/teams` |
| `name` | string  | Display name, e.g. `"USA USL W-League Women"`                                             |

## Team

A team belongs to a league. Use [`GET /teams`](/api/teams) to list the teams in a league along with their kit thumbnails.

| Field      | Type   | Description                                                                                                  |
| ---------- | ------ | ------------------------------------------------------------------------------------------------------------ |
| `name`     | string | Team name                                                                                                    |
| `silk_url` | string | Public CDN URL of the team's silk (kit thumbnail). May be an empty string (`""`) until the silk is resolved. |

<Note>
  Team names also appear directly on match objects as `home_team` and `away_team` strings — you do not need to call `/teams` to render a match. Use `/teams` when you need the silk URL or the full team roster for a league.
</Note>

## Match

A match represents a single fixture between two teams.

| Field        | Type     | Description                                                                                                                        |
| ------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `id`         | integer  | Numeric match identifier — use this for `/matches/{id}`, `/matches/{id}/live`, `/matches/{id}/result`, and WebSocket subscriptions |
| `home_team`  | string   | Home team name                                                                                                                     |
| `away_team`  | string   | Away team name                                                                                                                     |
| `start_time` | datetime | Scheduled kick-off time (ISO 8601, UTC)                                                                                            |
| `status`     | string   | Current match status — see table below                                                                                             |

### Match status values

| Status          | Meaning                                                                                                                    |
| --------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `NOT_STARTED`   | Scheduled, not yet kicked off                                                                                              |
| `STARTED`       | In play (including half-time)                                                                                              |
| `CLOSE_OF_PLAY` | A multi-day cricket Test between days — at stumps, still ongoing. Resumes the next day and stays visible until `FINISHED`. |
| `FINISHED`      | Completed                                                                                                                  |

<Note>
  `CLOSE_OF_PLAY` counts as live/ongoing alongside `STARTED`. The "active" endpoints ([`/leagues/active`](/api/leagues), [`/matches/active`](/api/matches)) and the per-sport [`/matches/live`](/api/matches) feed all include matches in this state, and you can pass `status=CLOSE_OF_PLAY` to filter `/matches`.
</Note>

<Note>
  Matches that a data provider has marked as suspended or postponed are **never returned** by the API — they are filtered out of every catalog response automatically.
</Note>

## Live snapshot

A live snapshot is attached to a match and represents its state at a particular moment. It is returned by `GET /matches/{id}/live` and delivered over the WebSocket stream. It contains:

* **`score`** — current home and away goals
* **`clock`** — current minute, second, period, whether the clock is running, and added time
* **`stats`** — a map of stat keys (e.g. `shots_on_target`, `possession`, `corners`) to per-side integers
* **`events`** — a timeline of match incidents (goals, cards, corners, substitutions, etc.)
* **`ball`** — last event-anchored ball position as normalized x/y coordinates (0–1)
* **`phase`** — a decoded description of the current game state (e.g. `"Dangerous attack"`, `"Safe possession"`)

<Info>
  The live snapshot uses its own lowercase `status` field that is separate from the catalog match status. The values are: `live`, `ht` (half-time), `ft` (full-time), and `not_started`. These differ deliberately from the uppercase `NOT_STARTED` / `STARTED` / `FINISHED` values on the match object.
</Info>

## Result

A result object is returned by `GET /matches/{id}/result` and contains two frozen snapshots taken at key moments:

| Field       | Type           | Description                                                                                                                                    |
| ----------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `half_time` | object \| null | Snapshot frozen at half-time (`status: "ht"`). **Does not include `events`** — the full timeline lives in `full_time`. `null` if not captured. |
| `full_time` | object \| null | Snapshot frozen at full-time (`status: "ft"`), including the complete `events` timeline. `null` if the match has not yet finished.             |

Each snapshot inside the result is a live snapshot object in the same format described above.

## Timestamps

All timestamps throughout the API — including `start_time` on matches and `updated_at` on live snapshots — are **ISO 8601 in UTC**, for example:

```
2026-06-18T02:00:00Z
```

Query parameters that accept a datetime (`start_after`, `start_before`) use the same format.
