---
id: ai-agent-instructions
title: 'AI Agent Task: Integrate Sport Line API'
description: Implementation brief for an AI agent integrating, testing, and documenting Sport Line API safely.
version: v1
language: en
---

# AI Agent Task: Integrate Sport Line API

## Purpose

This file is a technical assignment for an AI agent that must integrate Sport Line API
into an existing client website, application, or backend service.

Study the project's architecture, language, framework, coding conventions, and existing
approach to external APIs. Implement the integration in the project's established
style. Do not replace its architecture, interface, or existing business logic unless
necessary.

This assignment requires implementation and verification, not merely a description of
a possible solution. If the user requests only advice or a plan, do not modify files
without permission.

## Required Reading Before Implementation

Before changing code, study the Sport Line API documentation in this directory.

You must read:

1. [Integration Guide](INTEGRATION-GUIDE.md).
2. [Quick Start](getting-started/quick-start.md).
3. [Authentication and Access](getting-started/authentication-and-access.md).
4. [Core Concepts](getting-started/core-concepts.md).
5. The documentation for every method required by the integration.
6. The relevant data models and the [Field Reference](data-models/field-reference.md).

Do not begin implementation using this assignment alone. Treat the SportAPI
documentation as the primary source for URLs, parameters, fields, response formats,
and data update rules.

If the documentation is missing or its links are unavailable, tell the user before
starting the integration and ask for the complete `client-documentation` directory.

## Integration Goal

Create a secure server-side Sport Line API integration that can:

1. Retrieve the current sports line navigation hierarchy.
2. Display available Prematch and Live matches.
3. Open detailed data for a selected match.
4. Display the odds, statistics, and submatches actually returned by the API.
5. Update data regularly at the permitted frequency.
6. Correctly handle empty responses, access errors, and disappeared matches.

Core integration flow:

```text
menu → events → event
```

## Information Required Before Starting

Inspect the project and locate, or ask the user for:

1. The Sport Line API base URL issued by the SportAPI manager.
2. The API key, which must be stored in a protected environment variable.
3. Required sports line types: Prematch, Live, or both.
4. The response language enabled for the key.
5. Sports included in the client's subscription.
6. Pages, components, or internal APIs that will use the data.
7. Display requirements for matches, odds, and statistics.
8. Whether esports data is required.
9. Whether additional services are connected: Live 3D Tracker, video, results, or a
   betting system.
10. Project requirements for caching, logging, tests, and error handling.

Do not ask the user to publish an active API key in a shared chat. Recommend adding it
to the project's secrets system or a local environment variable.

If required values are unavailable, prepare a secure integration with placeholders and
report what is still needed. Do not invent a base URL, key, sport ID, tournament ID, or
match ID.

To obtain access, the user contacts the SportAPI manager:
[@suport_sportapi](https://t.me/suport_sportapi).

## Configuration

Use the configuration mechanism established by the project. Recommended variable names:

```text
SPORTAPI_BASE_URL=https://YOUR_API_DOMAIN
SPORTAPI_PACKAGE_KEY=YOUR_API_KEY
SPORTAPI_LANGUAGE=en
```

Add a separate sports line type setting when required:

```text
SPORTAPI_LINE_TYPE=live
```

Rules:

- never hard-code an active key in source code;
- never commit the key to Git;
- never pass the key in the URL;
- never expose the key in logs or interface messages;
- never send the key to a browser or mobile application;
- request Sport Line API through the client's backend;
- validate required configuration when the application starts.

One key is intended for one project and one approved environment. It is bound to a
server domain or IP address. Do not use a production key in another environment without
approval from SportAPI.

## Connection Method

Sport Line API is a REST API. WebSocket support is under development and must not be
used in a production integration before its official release.

Every method uses HTTP `GET`.

Pass the API key in the header:

```http
Package: YOUR_API_KEY
```

Also send:

```http
Accept: application/json
```

First-request example:

```bash
curl --request GET \
  --url 'https://YOUR_API_DOMAIN/v1/menu/live/en' \
  --header 'Package: YOUR_API_KEY'
```

## Create One Shared API Client

Do not duplicate HTTP logic in every method. Create one client or request function that:

1. Accepts a relative method path.
2. Adds the base URL.
3. Sends the `Package` and `Accept` headers.
4. Sets reasonable connection and response timeouts.
5. Parses JSON.
6. Checks the HTTP status.
7. Checks `error_code` and `error_message`.
8. Validates the standard `status`, `page`, and `body` envelope.
9. Returns a typed or otherwise predictable result.
10. Never exposes the key in an error.

Use the project's standard HTTP library and established approach to dependency
injection, configuration, and exception handling.

## Standard Response Format

### Successful Response

```json
{
  "status": 1,
  "page": "/v1/menu",
  "body": []
}
```

`body` may be an array, a match object, an empty array, or an object containing a
message. Its type depends on the method.

Do not create business logic for unconfirmed `status` values. After validating the
envelope, always inspect the type and contents of `body`.

### API Error

```json
{
  "error_code": 100,
  "error_message": "Invalid Package"
}
```

Check the JSON for API errors instead of relying only on the HTTP status.

### `event` Service Message

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

Check `body.message` before parsing a match object.

## Prematch and Live

URLs use two sports line types:

| Value | Data |
|---|---|
| `line` | Prematch — matches that have not started |
| `live` | Live — matches currently in progress |

Rules:

- retrieve and store Prematch and Live separately;
- do not mix responses of the two types in one cache entry;
- do not replace `line` with `live` when requesting an old `game_id`;
- a match receives a new `game_id` when it moves to Live;
- the API does not provide a ready-made link between a Prematch match and its Live
  version;
- if the project matches them independently, do not present that match as a guaranteed
  SportAPI relationship.

## Step 1: Retrieve the Current Menu

Primary navigation method:

```http
GET /v1/menu/{type}/{lang}
```

The response contains:

```text
sport
└── country
    └── tournament
```

Use IDs only from a current response of the same sports line type:

- `body[].id` is `sportId`;
- `body[].sub[].id` is `countryId`;
- `body[].sub[].sub[].id` is `tournamentId`.

Do not create a permanent static list of available sports and tournaments. The API
returns only sections that currently contain matches. When the last match disappears,
a tournament or an entire sport may disappear from the next `menu` response.

If the user needs esports and the method supports this selection, add:

```text
?cybersport=true
```

Process traditional sports and esports as separate selections when required by the
project interface.

## Step 2: Retrieve the Match List

```http
GET /v1/events/{sportId}/{tournamentId}/sub/50/{type}/{lang}
```

Required `events` rules:

- use only the `sub` format;
- always pass the technical `count` segment with value `50`;
- do not use `count` for pagination; the result limit has been removed;
- pass a tournament ID or `tournamentId=0` for every tournament of the selected sport;
- even with `tournamentId=0`, retrieve `sportId` from the current menu;
- use the same `type` and `lang` as the selected navigation branch.

Response structure:

```text
body[]
└── tournament object
    └── events_list[]
        └── matches
```

`events` contains a short set of main markets and best odds. Do not automatically call
`event` for every match. Request match details only when the user actually needs them.

## Step 3: Retrieve Match Details

Take `game_id` from the selected match and call:

```http
GET /v1/event/{gameId}/group/{type}/{lang}
```

Required `event` rules:

- use only the `group` format;
- pass the same `line` or `live` type from which `game_id` was retrieved;
- do not expect a match array: a successful `body` contains one object;
- check `body.message` first;
- use `event` for the complete odds list of the selected match;
- preserve the market, column, and selection order created by the API.

The `group` format already groups and sorts odds. Do not rebuild its structure unless
the interface explicitly requires it.

## Identifiers

| Purpose | Field or parameter |
|---|---|
| Sport | `sportId` in a URL; `sport_id` in a match object |
| Country | `countryId` in a URL; `country_id` in a match object |
| Tournament | `tournamentId` in a URL; `tournament_id` in a match object |
| Match or submatch | `gameId` in a URL; `game_id` in JSON |
| Main match of a submatch | `game_mid` |
| Betting selection | `oc_pointer` |
| Live 3D Tracker | `zp` |
| Video stream | `vi` |

Do not derive IDs from names or substitute one identifier for another.

In particular:

- `game_id` requests `event`;
- `zp` is passed as `gameid` to the ready-made Live 3D Tracker;
- `vi` is passed to the separate video widget;
- `oc_pointer` is used by the separate bet placement and settlement system.

Even if some field values happen to match, their purposes remain different.

## Match and Live Data

Account for these fields:

- `game_start`: Unix timestamp in seconds;
- `timer`: match timer in seconds;
- `score_full`: overall score;
- `score_period`: period score;
- `period_name`: current period name;
- `finale`: completion indicator, not available for every match;
- `extra_time`: added time, when populated.

To display minutes, divide `timer` by `60` and round according to the interface
requirements. Do not request the API every second only to update the timer. Update it
locally and synchronize it during the next scheduled request.

Do not rely on `game_num`, `sgame_id`, `stat_id`, `stat_list_extra`, or `game_plan`.
These fields are legacy, reserved, or not currently used by the production API.

## Odds

### In an `events` List

`game_oc_list` contains a short list of markets and best odds. A market's `oc_list` is a
flat array:

```text
game_oc_list[]
└── market
    └── oc_list[]
        └── selection
```

### In Detailed `event/group`

The outer `oc_list` contains columns, and each nested array contains the selections for
that column:

```text
game_oc_list[]
└── market
    └── oc_list[]
        └── column
            └── selections
```

Main selection fields:

| Field | Purpose |
|---|---|
| `oc_name` | Selection name for display |
| `oc_rate` | Current decimal odds |
| `oc_size` | Total, handicap, or another parameter value |
| `oc_pointer` | Unique bet or selection code |
| `oc_block` | `true` means blocked; `false` means available |
| `op_id` | Player or participant ID for a player-specific bet |

Processing rules:

- do not require a `1X2` market;
- do not expect a draw in tennis or basketball;
- available markets depend on the sport and match;
- use `group_id` as the technical market ID;
- do not use translated names as permanent IDs;
- match selection updates by `oc_pointer`, not by `oc_rate`;
- if `oc_block: true`, do not allow the selection to be chosen;
- if a selection disappears from a new response, do not display its old odds as
  current;
- do not require `columns` to equal the number of nested arrays;
- preserve the order returned by the API.

## Submatches

The submatch list is returned only in detailed `event`, in `sub_games`.

It may contain:

- a separate half, set, or period;
- corners;
- first-half corners;
- cards;
- fouls;
- player statistics;
- other additional lines.

Each submatch has its own `game_id`. Request it with the same method:

```http
GET /v1/event/{subgameId}/group/{type}/{lang}
```

The returned odds apply only to the selected submatch. For example, odds for the
“First-half Corners” submatch do not apply to every corner or the entire match.

`game_mid` contains the main match ID. Do not treat `sub_games` in an `events` list as a
data source: the field is not used there and is normally empty.

## Group Matches

`event_plan` is used only in a detailed `event` response for group events.

The main match may be named “Home — Away,” while `event_plan` contains the complete list
of actual teams competing on each side. The field is not used in an `events` list.

Do not confuse `event_plan` with `sub_games`.

## Live Statistics

Main statistics are returned in `stat_list` and are available only for Live:

- in the `events` match list;
- in a detailed `event` response.

The statistic set depends on the sport and specific match. Process the array dynamically
using the actual `id`, `name`, `opp1`, and `opp2` values returned.

Do not rename statistics yourself. Do not treat a submatch's statistics as separate
statistics for its type: the main match's statistics may be repeated in a submatch.

Sport Line API is not a detailed analytics API. Match history, H2H, and team and player
analysis belong to a separate service that is under development.

## Ready-made Icons

Use the SportAPI CDN in the interface:

| Object | URL template |
|---|---|
| Sport | `https://cdn.sportapi.net/sports/v1/color/{sportId}.webp` |
| Country | `https://cdn.sportapi.net/flags/v1/color/{countryId}.webp` |
| Tournament | `https://cdn.sportapi.net/tournaments/v1/color/{tournamentId}.webp` |
| Team or participant | `https://cdn.sportapi.net/opp/v1/color/{iconName}.webp` |

For a team, use `opp_1_icon` or `opp_2_icon`. Remove the original extension, if present,
before inserting the value into `{iconName}`.

Provide a fallback when an icon is missing or fails to load.

## Update Frequency

Each interval is the minimum delay between requests for the same data set.

| Method | Live | Prematch (`line`) |
|---|---:|---:|
| `menu` | at least 20 seconds | at least 60 seconds |
| `sports`, `countries`, `tournaments` | at least 60 seconds | at least 120 seconds |
| `events` | at least 7 seconds | at least 30 seconds |
| `event` | at least 5 seconds | at least 30 seconds |
| `topmatches` | at least 30 seconds | at least 120 seconds |
| `toplist` | not used | at least 120 seconds |

Required rules:

1. Do not start the next request for the same data before the previous one finishes.
2. Do not update `menu` at the `event` frequency.
3. Do not request `event` for every listed match unless necessary.
4. After a temporary network error, use an increasing delay.
5. Do not automatically retry key, language, subscription, or URL parameter errors.
6. If the manager provides different intervals, use the manager's values.

There is no hard monthly request quota, but violating the intervals or creating
excessive load may result in a warning and key suspension until the integration is
fixed.

## Caching

Caching and processing responses on the client side are allowed and recommended.

When implementing a cache:

- include the method and every parameter that changes the response;
- separate `line` and `live`;
- account for the language and esports flag;
- do not present an old response as current after receiving a new empty array;
- do not retain a disappeared selection as available;
- do not include the API key in a cache key or stored response body.

Use the project's existing caching infrastructure. Do not add a new database or
external service unless the task requires it.

## Empty States and Errors

Handle at least these situations:

| Situation | Action |
|---|---|
| `body: []` | Show an empty state; do not treat it as a system error |
| `Game not found` | Report that the match is unavailable; refresh the list if needed |
| `Game id finished` | Stop updating the old ID and request current `events` |
| `Missing Package header` | Check that the `Package` header is sent |
| `Invalid Package` | Check the key and environment configuration |
| `Package has expired` | Report that access must be renewed |
| `Access denied` | Check the subscription and available `sportId` |
| `Invalid language` | Check the language code |
| `The language is not available in your package.` | Check subscription languages |
| `Wrong data type (accept only live or line)` | Correct the sports line type value |
| unknown JSON | Record a safe diagnostic error without exposing the key |
| timeout or temporary network error | Show a temporary state and retry after a delay |

Do not use `Game id finished` to determine whether a match ended, was cancelled, was
postponed, or moved to Live. The API does not distinguish these reasons.

Do not leave an infinite loading indicator. Use the project's existing loading, empty,
and error-state components.

## Additional Methods

The following methods are optional. Do not implement or call them automatically unless
the project needs them:

| Method | Purpose |
|---|---|
| `sports` | Separate sport list |
| `countries` | Countries for the selected sport |
| `tournaments` | Tournaments for the selected sport and country |
| `topmatches` | Live or Prematch top-match selection |
| `toplist` | Top matches for one selected sport, Prematch only |
| `search` | Match search using URL-encoded text |

Normally use `menu`, which returns sports, countries, and tournaments in one request.
The step-by-step `sports → countries → tournaments` chain is needed only for specific
interface scenarios.

Do not use `events-by-period`. Its contract requires correction and is not ready for
client integration.

## Live 3D Tracker and Video

Do not integrate the tracker or video merely because the sports line contains their
fields. They are separate paid services with their own keys and access conditions.

### Live 3D Tracker

- works only for Live;
- availability is determined by `zp`;
- the widget's `gameid` equals `zp`, not `game_id`;
- do not create the widget when `zp: null`;
- the tracker must support the sport;
- use the ready-made `iframe` or `embed.js`.

If the user explicitly requests the tracker and has access, follow the
[Live 3D Tracker integration documentation](https://sportapi.net/docs/live-3d-tracker/service-overview.html).

### Video Streaming

- available only for some Live matches;
- `va: 1` and a non-empty `vi` mean video is available;
- `va: null` or `vi: null` means video is unavailable;
- `vi` is a string ID, not a URL;
- video is displayed in a separate ready-made widget through an `iframe`;
- SportAPI does not stream matches from top leagues.

Do not develop a custom video player or insert `vi` directly into `src` without the
separate video-service documentation.

## Bet Placement System

Sport Line API provides data but does not itself create bet slips, accept bets, or
settle results.

If the client has a separate bet placement and settlement system:

- use `oc_pointer` as the unique code of the selected outcome;
- pass it without modification;
- check the current `oc_rate` and `oc_block` before selection;
- follow the [Bet Pointer](https://sportapi.net/docs/coupon/bet-placement/bet-pointer.html) and
  [Coupon Placement](https://sportapi.net/docs/coupon/bet-placement/place-coupon.html) documentation.

Do not create a fake bet-submission flow based only on Sport Line API.

## Implementation Order

1. Study the project and locate its existing HTTP client, configuration, cache, and
   error handling.
2. Identify the backend layer where the key can be stored securely.
3. Add configuration without committing secret values.
4. Implement a shared Sport Line API client.
5. Add models or types for the standard envelope and required methods.
6. Implement the core `menu → events → event` flow.
7. Add separate Prematch and Live handling when both are required.
8. Implement loading, empty-result, and error states.
9. Add caching and updates using the required intervals.
10. Add optional methods only when requested by the user.
11. Write or update tests.
12. Run available project checks: tests, linting, type checks, and build.
13. Update the sample configuration and startup instructions without an active key.

If the project already contains part of the integration, do not create a parallel
implementation. Inspect and extend the existing code in the established style.

## Prohibited Actions

- Do not expose or log the API key.
- Do not request Sport Line API directly from a browser.
- Do not hard-code static IDs without checking the current `menu`.
- Do not link Prematch and Live by `game_id`.
- Do not use `game_id` in place of `zp` or `vi`.
- Do not treat `status: 1` as a guarantee that data is present.
- Do not treat an empty array as a system error.
- Do not expect identical markets, selections, or statistics for every match.
- Do not re-sort `group` markets and odds unless necessary.
- Do not use `count` as a limit or pagination value.
- Do not request the API every second to update a timer.
- Do not run parallel update loops for the same data.
- Do not use WebSocket before its official release.
- Do not use `events-by-period` before the method is fixed.
- Do not add unconfirmed fields, statuses, or values.
- Do not integrate paid additional services without a client request and access.

## Verification Checklist

After implementation, verify that:

1. The key exists only in protected backend configuration.
2. Requests contain the `Package` header.
3. Live and Prematch responses are not mixed.
4. Navigation IDs come from the current API.
5. `events` is called with `sub/50`.
6. `event` is called with `group`.
7. `tournamentId=0` correctly returns tournaments for the selected sport.
8. The flat `oc_list` from `events` and nested `oc_list` from `event` are parsed
   separately.
9. Markets and selections are not tied only to a `1X2` structure.
10. A blocked or disappeared selection cannot be chosen as current.
11. A submatch is requested with its own `game_id`.
12. `body: []`, `Game not found`, and `Game id finished` are handled separately.
13. The timer is displayed from seconds without creating one-second API requests.
14. Update intervals match the documentation.
15. A repeated request does not start before the previous request finishes.
16. Icons have a fallback.
17. Optional methods are not called unnecessarily.
18. The key is absent from logs, the client bundle, test snapshots, and Git.
19. Tests, linting, type checks, and build succeed.
20. Project documentation lists the required variables and startup procedure.

If a real request cannot be made because the key or an approved environment is
unavailable, use saved JSON examples or test fixtures. List the external checks the
user must perform after access is available.

## Report Format

After implementation, report:

- which files changed;
- where configuration is stored;
- which methods were implemented;
- how Prematch and Live are separated;
- how odds, submatches, and statistics are handled;
- which update intervals are used;
- which errors and empty states are implemented;
- which tests and checks were run;
- which data, keys, or external checks are still required;
- which additional services were intentionally not connected.

## Detailed Documentation

Use the following documents as the primary sources for Sport Line API structure and
rules:

- [Sport Line API Integration Guide](INTEGRATION-GUIDE.md)
- [Quick Start](getting-started/quick-start.md)
- [Authentication and Access](getting-started/authentication-and-access.md)
- [Core Concepts](getting-started/core-concepts.md)
- [`menu`](api-reference/menu.md)
- [`events`](api-reference/events.md)
- [`event`](api-reference/event.md)
- [Field Reference](data-models/field-reference.md)
- [Odds](data-models/odds.md)
- [Statistics](data-models/live-statistics.md)
- [Submatches](data-models/sub-events.md)
- [Error Handling](getting-started/error-handling.md)
- [Integration Examples](examples/README.md)
- [SportAPI FAQ](../../client-faq/en/README.md)

SportAPI support: [@suport_sportapi](https://t.me/suport_sportapi).

Official website: [sportapi.net](https://sportapi.net).
