---
id: match-model
title: Match Data Model
description: Description of the main match model and its relationships with sport, tournament, teams, score, and odds.
version: v1
language: en
---

# Match Data Model

## What Is a Match?

A match is the main Sport Line API object. It connects:

- a sport;
- a country and tournament;
- teams or participants;
- start time;
- Prematch or Live data;
- score, period, and timer;
- odds;
- statistics;
- submatches;
- video and Live 3D Tracker.

Different methods return the same match with different levels of detail. The client
must not expect every field to be present or populated in every response.

The complete list of JSON fields, types, and values is available in the
[Sport Line API Field Reference](field-reference.md).

## Primary Identifier

Use `game_id` to work with a match.

```json
{
  "game_id": 746146992
}
```

Use this value to request detailed data:

```http
GET https://YOUR_API_DOMAIN/v1/event/746146992/group/live/en
```

Always take `game_id` from a current API response. Do not generate it yourself or use
`sgame_id`, `stat_id`, `game_num`, `vi`, or `zp` in its place.

## Main Match and Submatch

Two fields connect a main match with its submatches:

| Field | Meaning |
|---|---|
| `game_id` | ID of the current object: the main match or a submatch |
| `game_mid` | ID of the main match |

For a main match, the values are usually the same:

```json
{
  "game_id": 746146992,
  "game_mid": 746146992,
  "game_dop_name": ""
}
```

A submatch has its own `game_id`, while `game_mid` points to the main match:

```json
{
  "game_id": 746147010,
  "game_mid": 746146992,
  "game_dop_name": "Corners"
}
```

In this example:

- `746147010` is the ID of the “Corners” submatch;
- `746146992` is the ID of the main match;
- to retrieve corner odds, request `event` using `746147010`.

Do not replace `game_id` with `game_mid`. The values match for the main match but serve
different purposes for a submatch.

## Where Match Objects Are Returned

### `events`

The [`events`](../api-reference/events.md) method groups matches by tournament:

```text
body
└── tournament
    └── events_list
        └── match
```

The object contains the main match data and a short set of best odds. `sub_games` and
`event_plan` are returned as empty arrays here.

### `event`

The [`event`](../api-reference/event.md) method returns one detailed object directly in
`body`:

```text
body
└── detailed match or submatch object
```

Use this method to retrieve:

- the full available odds list;
- the submatch list in `sub_games`;
- a populated `event_plan` with the complete team composition of a group match;
- detailed data for the selected match.

### `topmatches` and `toplist`

By default, these methods return short summaries. With `full=true`, each item becomes an
extended object similar to a match from `events`, but the odds list remains short.

`full=true` does not replace an `event` request.

### `search`

The [`search`](../api-reference/search.md) method returns a short summary of each matching
match with country and tournament IDs, but without odds, statistics, submatches, video,
or tracker data.

## Data Availability by Method

| Data | `events` | `event` | `topmatches` / `toplist` | With `full=true` | `search` |
|---|---:|---:|---:|---:|---:|
| `game_id`, `game_mid`, `game_start` | yes | yes | yes | yes | yes |
| Team and tournament names | yes | yes | yes | yes | yes |
| Country and tournament IDs | yes | yes | no | yes | yes |
| Team IDs and participant arrays | yes | yes | no | yes | no |
| Short odds list | yes | no | no | yes | no |
| Full odds list | no | yes | no | no | no |
| `stat_list` field | yes | yes | no | no | no |
| Populated `sub_games` | no | yes | no | no | no |
| Populated `event_plan` | no | yes | no | no | no |
| `va`, `vi`, `zp` | yes | yes | yes | yes | no |

In this table, “yes” means that the field or corresponding data is part of the response
structure. An array may be empty, and an optional value may be `null`. Statistics in
`stat_list` are available only in Live `events` and `event` requests.

The “With `full=true`” column refers to extended `topmatches` and `toplist` responses.

## Sport, Country, and Tournament

A match may contain:

```json
{
  "sport_id": 1,
  "sport_name": "Football",
  "country_id": 231,
  "country_name": "England",
  "tournament_id": 88637,
  "tournament_name": "England. Premier League"
}
```

Use numeric IDs for application logic and relationships. Names depend on the requested
language and are intended for display.

Do not link objects only by `sport_name`, `country_name`, or `tournament_name`: names
may differ between languages.

## Teams and Participants

The main fields for the two sides are:

```json
{
  "opp_1_id": 50679,
  "opp_1_ids": [50679],
  "opp_1_name": "Arsenal",
  "opp_1_icon": "08a25897e35d75d7261a8095b9599aad.png",
  "opp_2_id": 2074,
  "opp_2_ids": [2074],
  "opp_2_name": "Coventry City",
  "opp_2_icon": "2074.png"
}
```

`opp_1_ids` and `opp_2_ids` are used when one side consists of multiple participants,
such as a tennis doubles pair or a group competition.

Participant IDs may be absent from short `topmatches`, `toplist`, and `search`
responses. If you need them, request `event` using `game_id`.

### Participant Icons

The `opp_1_icon` and `opp_2_icon` values are file names. Remove the original extension
and insert the remaining name into the URL:

```text
https://cdn.sportapi.net/opp/v1/color/{iconName}.webp
```

Example:

```text
opp_1_icon: 8bd073a686a067e6732d8d1688a517c0.png
iconName:    8bd073a686a067e6732d8d1688a517c0
```

```text
https://cdn.sportapi.net/opp/v1/color/8bd073a686a067e6732d8d1688a517c0.webp
```

## Start Time

`game_start` contains the start date and time as a Unix timestamp in seconds:

```json
{
  "game_start": 1787338800
}
```

Convert this value to the required date and time zone in the application.

Do not determine whether a match is Live using only `game_start`. Also account for the
method and sports line type from which the object was retrieved.

## Prematch and Live Are Separate Objects

A Prematch match may disappear from `line` and later appear in `live`, but its Live
version receives a new `game_id`.

```text
Prematch: game_id A
          match disappears from line
Live:     game_id B
```

Sport Line API does not provide a reliable field that unambiguously links these two
objects. Therefore, do not automatically merge the Prematch and Live versions of a
match.

Do not attempt to link them using:

- identical team names;
- an identical `game_start`;
- the tournament;
- `sgame_id` or `stat_id`.

Matching values do not constitute a confirmed relationship.

## Live Match Score and State

Main Live fields:

| Field | Purpose |
|---|---|
| `score_full` | Current overall score |
| `score_period` | Score by period or for the current playing segment |
| `score_extra` | Additional score, such as the current tennis game score |
| `period_name` | Current period name |
| `timer` | Current match timer value in seconds |
| `extra_time` | Added time, for example `+10` |
| `finale` | Completion indicator, not available for every match |
| `pitch` | ID of the serving participant in applicable sports |

Score and period formats depend on the sport. Do not apply football-specific parsing
rules to every sport.

In Prematch, these fields usually contain initial values, empty strings, or `null`.

### Converting `timer` to Minutes

`timer` is provided in seconds. Divide it by `60` to obtain minutes:

```text
minutes = timer / 60
```

To display the value as `MM:SS`:

```js
const minutes = Math.floor(timer / 60);
const seconds = timer % 60;
const value = `${minutes}:${String(seconds).padStart(2, '0')}`;
```

For example, `timer=3376` corresponds to `56:16`.

If the interface shows only the minute number, round the result according to the
interface rules. To calculate the number of fully elapsed minutes, use
`Math.floor(timer / 60)`.

## End of Match Availability

If a Prematch match is no longer available under its previous `game_id`, `event` may
return:

```json
{
  "status": 1,
  "page": "/v1/event",
  "body": {
    "message": "Game id finished"
  }
}
```

This message does not explain the exact reason. The match may have:

- moved from Prematch to Live with a new ID;
- been cancelled;
- disappeared from the sports line for another reason.

The API does not return a separate reliable status for each of these cases. After
receiving `Game id finished`, stop requesting the old `game_id`, but do not
automatically mark the match as finished or cancelled.

## Submatches

In a detailed `event` response, `sub_games` contains links to available submatches:

```json
{
  "sub_games": [
    {
      "game_id": 746147013,
      "game_num": 150080,
      "game_name": "2nd half"
    },
    {
      "game_id": 746147010,
      "game_num": 205978,
      "game_name": "Corners"
    }
  ]
}
```

The `sub_games` items do not contain odds. For each required submatch, make a separate
`event` request using its `game_id`.

In `events`, `topmatches?full=true`, and `toplist?full=true`, `sub_games` is returned as
an empty array.

## Group Matches

For a group match, the detailed `event` method may return a populated `event_plan`. The
main match may be named “Home — Away,” while the array contains the complete list of
actual teams playing on the home and away sides.

In an `events` list, the field is always empty:

```json
{
  "event_plan": []
}
```

A populated `event_plan` must be retrieved through a specific `event` request.

For a detailed explanation of additional matches, submatches, and the difference
between `sub_games` and `event_plan`, see
[Additional Matches and Submatches](sub-events.md).

## Odds

`game_oc_counter` shows the total number of available bets or selections for the match.
`game_oc_list` contains the markets and selections themselves.

The structure depends on the method:

- `events`, `topmatches?full=true`, and `toplist?full=true` contain a short list of best
  odds;
- `event` with the `group` format contains the full available list, organized into
  markets and nested columns.

For a specific match, use `group` because the data is already arranged into columns and
sorted by value. Preserve the API response order; there is no need to rebuild or
re-sort the selections on the client side.

The detailed structure of markets, columns, and selections is documented in
[Odds and Betting Market Data Model](odds.md).

## Statistics

Live statistics are returned in `stat_list`. The set of statistics depends on the sport
and the specific match.

Four statistics from an actual Live match:

```json
"stat_list": [
  {
    "id": 93,
    "name": "xG",
    "opp1": "1.45",
    "opp2": "0.03"
  },
  {
    "id": 45,
    "name": "Attacks",
    "opp1": "61",
    "opp2": "54"
  },
  {
    "id": 58,
    "name": "Dangerous attacks",
    "opp1": "44",
    "opp2": "19"
  },
  {
    "id": 29,
    "name": "Possession %",
    "opp1": "65",
    "opp2": "35"
  }
]
```

| Field | Description |
|---|---|
| `id` | Statistic ID |
| `name` | Statistic name in the requested language |
| `opp1` | Value for the first team or participant from `opp_1_name` |
| `opp2` | Value for the second team or participant from `opp_2_name` |

`opp1` and `opp2` are strings even when they contain an integer or decimal number. They
may be displayed as received. For calculations, convert them to a numeric type while
accounting for the possible format of the specific statistic.

Do not interpret a missing statistic or an empty `stat_list` as a zero value.

For details about the structure, value types, and confirmed statistics, see
[Live Match Statistics Data Model](live-statistics.md).

## Video Streaming

| Field | Value |
|---|---|
| `va` | `1` means video is available; `null` means it is unavailable |
| `vi` | Live match video stream ID or `null` |

The value `va=0` is not used.

`vi` is a string ID, not a ready-to-use URL. SportAPI does not stream matches from top
leagues. Detailed rules for checking and using these fields are available in
[Video Streaming in Sport Line API](../additional-services/video-streaming.md).

## Live 3D Tracker

| Field | Value |
|---|---|
| `zp` | ID of the ready-made Live 3D Tracker widget or `null` |

For Live 3D Tracker, the relationship is:

```text
tracker gameid = sports line zp
```

If `zp` is `null`, the tracker is unavailable for the match.

`game_id`, `vi`, and `zp` serve different purposes and cannot replace one another.

The relationship with the sports line and the list of supported sports are summarized
in [Live 3D Tracker in Sport Line API](../additional-services/live-3d-tracker.md).
[Complete embedding instructions](https://sportapi.net/docs/live-3d-tracker/service-overview.html) are available in the service documentation.

## Fields You Must Not Rely On

The following fields are legacy, test, or reserved:

| Field | Status |
|---|---|
| `sgame_id` | Test field for future match, team, and player statistics |
| `stat_id` | Test field for future detailed statistics |
| `game_num` | Legacy field planned for removal |
| `stat_list_extra` | Reserved test field |
| `game_plan` | Reserved test field |

Do not use these values as required IDs, relationships, or match-state indicators.

## Recommended Workflow

```text
menu
  ↓
events
  ↓ game_id
main match event
  ├── full odds
  ├── stat_list
  ├── sub_games ── game_id ──> submatch event
  ├── event_plan
  ├── vi
  └── zp
```

1. Retrieve the match list through `events`.
2. Use the selected match's `game_id` to request `event`.
3. If you need bets on a submatch, take its ID from `sub_games` and make another
   `event` request.
4. Update Prematch and Live matches separately.
5. Do not link Prematch and Live versions without a confirmed relationship identifier.

## Related Documents

- [`events` — Match List](../api-reference/events.md)
- [`event` — Specific Match](../api-reference/event.md)
- [Core Concepts](../getting-started/core-concepts.md)
- [Data Update Guidelines](../getting-started/update-guidelines.md)
- [Error Handling](../getting-started/error-handling.md)
- [Field Reference](field-reference.md)
