SportAPI Documentation
EN
C Product documentationCoupon API
v1
Service & pricing ↗ Get access ↗
Coupon API / Migrating from the legacy API

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

OperationBeforeNowClient change
AuthenticationPOST /api/v2/loginPOST /api/partner/loginUse the extended response and new HTTP 401/403 rules.
Coupon creationPOST /bet/placePOST /api/partner/coupons/placeRead the body.coupons array instead of a coupon directly from body.
Coupon retrievalGET /coupons/getGET /api/partner/coupons/getUse the new complete coupon model.
Coupons by periodGET /coupons/listPOST /api/partner/coupons/resultsSend JSON with start_date and end_date.
Coupons by codeNo separate modePOST /api/partner/coupons/resultsSend up to 100 values in coupon_ids.
Recent settlementsGET /coupons/calculatedGET /api/partner/coupons/calculatedThe window of up to 120 minutes remains; the coupon model is extended.
Active couponsNot fully documentedGET /api/partner/coupons/activeRetrieve all active client coupons.
BalanceNo separate read methodGET /api/partner/balanceAdded a read-only request for the client balance. Coupon creation automatically deducts from it.
Cashout quoteGET /coupons/cashoutNo new route yetThe function is untested and under development; do not use it in production until a separate announcement.

Authentication and Access

BeforeNow
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

BeforeNow
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

BeforeNow
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, and rate;
  • optional player_id was 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

FieldBeforeNow
list_betsOne or more string pointers.Preserved; at least one entry.
amountfloat.Positive decimal number; required.
currencyBet currency.Preserved as an optional string. Any standard, virtual, internal, or fictional currency may be used; ISO 4217 is not required.
callback_urlResult URL.Stored separately for each coupon; an empty value disables callback for that coupon.
langExamples 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.
modeaccept or reject.Preserved; the new API defaults to reject.
mode_type1, 2, 3.The directional logic is preserved.
multiNumber 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 — one amount;
  • multi = trueamount × 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

SituationLegacy behaviorNew behavior
Odds changedGeneral error 501.501, details in body.changes[].
Outcome absent501, status nodata.Separate error 502, status no_data.
Outcome blocked501, status block.Separate error 503, status block.
Outcome validation failedGeneral 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_win and real_win;
  • original_coef and calculate_coef;
  • has_return;
  • raw_pointer, line_type, and is_live;
  • main_game_id, is_sub_game, parent_game_id, and sub_game_key;
  • score at acceptance and settlement score;
  • sport_name and tournament_id;
  • team1_id and team2_id;
  • opp_icon1 and opp_icon2;
  • settlement_reason_code and settlement_reason for 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

BeforeNow
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 200 acknowledgement;
  • settlement_reason_code and settlement_reason in 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

  1. Start storing coupon_code as a string.
  2. Add support for the new response envelope.
  3. Move to POST /api/partner/login.
  4. Move to POST /api/partner/coupons/place and read body.coupons[].
  5. Move to body.changes[] and separate errors 501504.
  6. Add new fields and statuses without removing legacy handling.
  7. Choose result delivery: polling, callbacks, or both.
  8. If callbacks are selected, arrange them with the manager, verify HMAC, and deduplicate by batchId.
  9. Use calculated or results to retrieve and reconcile results.
  10. Verify handling of coupon statuses 8, 15 and bet statuses 4, 23.
  11. Verify correct handling of calculate_date = null before settlement.
  12. Account for a separate amount deduction for every coupon with multi = true.
  13. Prevent accumulators with more than 15 events or related bets from the same match.
  14. Store required coupon and bet data only after a successful creation response.
  15. If coupon currency is required, store it in the partner system at creation.
  16. Handle 507 as an atomic rejection without created coupons or a client-balance deduction.
  17. Store settlement_reason_code and do not use settlement_reason text as a program key.
  18. After verifying the new integration, phase out calls to legacy routes.