Migrating from the Legacy API
This document compares the legacy old_api_calc.txt description with Client OpenAPI 1.2.0. It is intended for existing integrators already using /api/v2/login, /bet/place, and /coupons/**.
All integration changes required for migration are described on this page. A partner should not need to read the rest of the documentation to move to the new API.
Key Point
Legacy routes remain supported in compatibility mode, and there are currently no plans to remove them. /api/partner/** is recommended for new integrations. Migration may be gradual, but never assume that a new route returns the legacy response structure.
Route Changes
| Operation | Before | Now | Client change |
|---|---|---|---|
| Authentication | POST /api/v2/login | POST /api/partner/login | Use the extended response and new HTTP 401/403 rules. |
| Coupon creation | POST /bet/place | POST /api/partner/coupons/place | Read the body.coupons array instead of a coupon directly from body. |
| Coupon retrieval | GET /coupons/get | GET /api/partner/coupons/get | Use the new complete coupon model. |
| Coupons by period | GET /coupons/list | POST /api/partner/coupons/results | Send JSON with start_date and end_date. |
| Coupons by code | No separate mode | POST /api/partner/coupons/results | Send up to 100 values in coupon_ids. |
| Recent settlements | GET /coupons/calculated | GET /api/partner/coupons/calculated | The window of up to 120 minutes remains; the coupon model is extended. |
| Active coupons | Not fully documented | GET /api/partner/coupons/active | Retrieve all active client coupons. |
| Balance | No separate read method | GET /api/partner/balance | Added a read-only request for the client balance. Coupon creation automatically deducts from it. |
| Cashout quote | GET /coupons/cashout | No new route yet | The function is untested and under development; do not use it in production until a separate announcement. |
Authentication and Access
| Before | Now |
|---|---|
The primary login field was login. | The primary field is username; login remains a compatible alias. |
Every login rejection was mapped to error_code = 99, Wrong login or password. | New login distinguishes an incomplete request (1002), invalid credentials (1003), disabled account (1004), expired access (1006), and insufficient balance (1007). These business errors use HTTP 200 and code = 0. |
An invalid token on legacy routes returned HTTP 200, code = 0, error_code = 1003. | New protected routes use HTTP 401; an unsuitable role returns HTTP 403. |
| The legacy document did not describe reliable client data isolation. | Ownership is determined only by the signed client JWT. An unknown coupon and a coupon owned by another client are indistinguishable. |
Response Format
| Before | Now |
|---|---|
Envelope: code, body, error_code, error_message, date. | Diagnostic fields time_ms and path were added. |
Successful creation returned one coupon directly in body. | body.coupons is always an array because multi = true may create multiple coupons. |
| Clients often relied on a successful HTTP status. | A business error usually still uses HTTP 200; code must be checked. |
A new client must consider creation successful only when all conditions are met:
HTTP 200
code = 1
body.coupons contains the created coupon or coupons
Do not store bet-slip contents as an accepted coupon before this response: during creation, an outcome may disappear, become blocked, or change odds.
Coupon Code
| Before | Now |
|---|---|
Examples used codes of different lengths: "0934412", "1009982318". | Public coupon_code is a string, usually containing 12 digits, such as "000000000272". |
| The code could mistakenly be stored as a number. | Store it as a string to preserve leading zeros. |
| The distinction between public code and database ID was not explicit. | coupon_code is not the internal record ID. |
Bet Pointer
Legacy document:
<type_line>#<game_id>|<bet_group_id>|<bet_id>|<param>#<coefficient>
New canonical format:
line_type#game_id#group_id#type_id#rate#coefficient[#player_id]
Specific changes:
- position names are standardized as
line_type,group_id,type_id, andrate; - optional
player_idwas added for player markets; - both
#and|separators are officially accepted, including the compatible mixed format; - the server validates format, availability, blocking, and current outcome odds;
- invalid format has the separate code
11.
Creation Parameters
| Field | Before | Now |
|---|---|---|
list_bets | One or more string pointers. | Preserved; at least one entry. |
amount | float. | Positive decimal number; required. |
currency | Bet currency. | Preserved as an optional string. Any standard, virtual, internal, or fictional currency may be used; ISO 4217 is not required. |
callback_url | Result URL. | Stored separately for each coupon; an empty value disables callback for that coupon. |
lang | Examples used individual language codes. | Send a two-letter language code; the API supports about 50 languages. Language is fixed at creation, and an existing coupon cannot currently be retrieved in another translation. The complete language list is not published. |
mode | accept or reject. | Preserved; the new API defaults to reject. |
mode_type | 1, 2, 3. | The directional logic is preserved. |
multi | Number 0/1; marked as under development. | Boolean false/true; with true, each outcome creates a separate coupon. |
With multi = true, amount applies to every single created. For example, two outcomes with amount = 10 create two separate coupons with a total deduction of 20.
Client Balance Deduction
Successful creation in the new API atomically deducts the total amount from the SportAPI client account balance:
multi = false— oneamount;multi = true—amount × number of coupons created.
If the total balance is insufficient, the API returns HTTP 200, code = 0, error_code = 507, Insufficient balance. No coupon is created and the client balance does not change. Partial success with multi = true is impossible.
Do not confuse this balance with the partner end-user wallet: SportAPI changes the client balance automatically, while the partner performs the financial operation in its own user system.
With multi = false, several outcomes form one accumulator. An accumulator may contain no more than 15 events. It also cannot combine several bets from one match tree, such as the main match and corners, or corners and fouls. Such a combination returns error_code = 506.
Changed or Unavailable Outcomes
| Situation | Legacy behavior | New behavior |
|---|---|---|
| Odds changed | General error 501. | 501, details in body.changes[]. |
| Outcome absent | 501, status nodata. | Separate error 502, status no_data. |
| Outcome blocked | 501, status block. | Separate error 503, status block. |
| Outcome validation failed | General server error. | Separate business error 504, status error. |
In the new API, body.changes is always an array. The client no longer needs to support different body types for a single and an accumulator.
change_type uses only numeric values:
1— odds increased;2— odds decreased;null— the outcome is blocked, absent, or failed validation.
String values increase and decrease are not used.
Coupon Model
The new model adds or explicitly separates:
- internal bet ID
events_data[].id; potential_winandreal_win;original_coefandcalculate_coef;has_return;raw_pointer,line_type, andis_live;main_game_id,is_sub_game,parent_game_id, andsub_game_key;- score at acceptance and settlement score;
sport_nameandtournament_id;team1_idandteam2_id;opp_icon1andopp_icon2;settlement_reason_codeandsettlement_reasonfor the reason for settlement or return.
The legacy response did not contain a separate accepted-bet ID. In the new API, a partner can store a specific bet using:
coupon_code + events_data[].id
In callbacks, this bet ID is sent as a string in events_data[].uuid. batchId serves another purpose: it identifies the callback batch version and is used for delivery deduplication.
Treat every client date as a Unix timestamp in milliseconds. The legacy exception that described event_date in seconds must no longer be used.
Before coupon or bet settlement, calculate_date is null. The value 0 is no longer used.
Money and odds are decimal numbers without fixed precision. The partner defines rounding and storage rules in its own system.
currency is not part of the complete coupon model or callback. If required for financial accounting, store the submitted value with coupon_code in the partner system.
Use settlement_reason_code for program logic. settlement_reason is explanatory text and may change; accept and store unknown codes.
Statuses
The legacy document described only coupon statuses 0, 2, 4 and bet statuses 0, 1, 2, 3, 21, 22.
The new contract additionally defines:
- coupon
8— return; - coupon
15— returned for recalculation and awaiting a new result; - bet
4— awaiting recalculation; - bet
23— push; - settlement multipliers for returns and half results;
- separate original, working, and settlement odds.
When a coupon is returned for recalculation, a callback is sent immediately with coupon status 15 and outcome status 4. After recalculation, another callback is sent with the current statuses.
If the previous coupon result was already processed, on first receiving status 15, the partner must deduct the bet amount again. After the new final status, credit the new real_win. A repeated callback with the same batchId must not change the balance again. amount is absent from callbacks, so store it at coupon creation or retrieve it through a read endpoint.
Retrieving Results
| Before | Now |
|---|---|
| Primary method: periodic request for settled coupons. | An optional signed callback was added. The partner may keep polling as the primary method or use it for fallback reconciliation. |
/coupons/list returned history with a limited and not fully defined selection. | /api/partner/coupons/results has two precise modes: up to 100 codes or a creation period up to 24 hours. |
| The difference between creation and settlement time was unclear. | results filters by creation time; calculated filters by final settlement time. |
Callback
The legacy document accepted callback_url but did not define a reliable public delivery protocol.
The new API defines:
- event
coupons.settled; - HMAC-SHA256 in
X-Coupon-Signature; - signature over the exact body bytes;
- batches of up to 100 snapshots;
- delivery-version identifier
batchId, which is not a coupon or bet ID; - idempotent processing;
- progressive accumulator updates;
- immediate notification of the first loss;
- final snapshot after every bet is settled;
- retries after temporary errors in 1, 5, 15, and 60 minutes;
- mandatory HTTP
200acknowledgement; settlement_reason_codeandsettlement_reasonin every bet of the settlement snapshot.
Callbacks are enabled at the partner’s request. The partner informs the manager, who creates the signature secret. The partner sets the URL in callback_url during coupon creation. Use HTTPS in production; HTTP is allowed in the test environment.
The integration documentation does not need to publish a permanent sender IP. If the partner additionally uses an IP allowlist, obtain the current address from the manager. IP filtering is an additional control and does not replace HMAC verification.
Minimum Migration Plan
- Start storing
coupon_codeas a string. - Add support for the new response envelope.
- Move to
POST /api/partner/login. - Move to
POST /api/partner/coupons/placeand readbody.coupons[]. - Move to
body.changes[]and separate errors501–504. - Add new fields and statuses without removing legacy handling.
- Choose result delivery: polling, callbacks, or both.
- If callbacks are selected, arrange them with the manager, verify HMAC, and deduplicate by
batchId. - Use
calculatedorresultsto retrieve and reconcile results. - Verify handling of coupon statuses
8,15and bet statuses4,23. - Verify correct handling of
calculate_date = nullbefore settlement. - Account for a separate
amountdeduction for every coupon withmulti = true. - Prevent accumulators with more than 15 events or related bets from the same match.
- Store required coupon and bet data only after a successful creation response.
- If coupon currency is required, store it in the partner system at creation.
- Handle
507as an atomic rejection without created coupons or a client-balance deduction. - Store
settlement_reason_codeand do not usesettlement_reasontext as a program key. - After verifying the new integration, phase out calls to legacy routes.