SportApi
API documentation · version 1.2.0

Odds, Bets, and Coupons — API Technical Documentation

This file contains a concise standalone guide for connecting to the SportAPI Coupon Settlement System. Details and rare cases are in full documentation.

Core flow http
POST /api/partner/login
POST /api/partner/coupons/place
GET  /api/partner/coupons/calculated?time=10

1. What you need to get from the manager

  • base URL API;
  • client account login and password;
  • when using callback - enable the function and the secret phrase callback_secret.

The examples use a conditional address:

BASE_URL="https://coupon-api.example.com"

In production, use HTTPS. All dates are transmitted as Unix timestamp in milliseconds, and monetary values ​​are transmitted as decimal numbers without fixed precision.

2. API response format

Success:

{
  "code": 1,
  "body": {},
  "error_code": null,
  "error_message": null,
  "date": 1784970000000,
  "time_ms": 5,
  "path": "/api/partner/example"
}

The business error usually also comes with HTTP 200:

{
  "code": 0,
  "body": null,
  "error_code": 1002,
  "error_message": "Not all params",
  "date": 1784970000000,
  "time_ms": 5,
  "path": "/api/partner/example"
}

Always check the HTTP code, then code, then error_code. Do not use the text error_message as a software key.

3. Authorization

POST /api/partner/login
Content-Type: application/json
{
  "username": "partner-demo",
  "password": "strong-password"
}

The field login is supported as a compatible alias username.

Successful response:

{
  "code": 1,
  "body": {
    "token": "<jwt-token>",
    "user_id": 17,
    "username": "partner-demo"
  },
  "error_code": null,
  "error_message": null
}

In all protected requests, pass:

Authorization: Bearer <jwt-token>

Basic login errors:

CodeReason
1002Login or password not sent.
1003Unknown login or incorrect password.
1004The client account has been disabled.
1006Access date has expired.
1007The client balance is zero or negative.

These errors are returned from HTTP 200, code = 0. HTTP 401 of a protected method means that the JWT is missing, invalid, expired, or revoked; Sign in again. HTTP 403 means inappropriate role or access denied.

4. Bet pointer

Each selected outcome is transmitted as a ready-made line from the sports line:

line_type#game_id#group_id#type_id#rate#coefficient[#player_id]

Examples:

line#737779544#1#1#0#1.85
live#738917381|119|5869|0.5#3.6#149439538
  • line_type: line or live;
  • rate: total/handicap parameter or 0;
  • player_id: optional player ID;
  • delimiters # and | are supported.

Do not collect or correct the pointer manually - pass the value obtained from the line unchanged.

5. Coupon placement

POST /api/partner/coupons/place
Authorization: Bearer <jwt-token>
Content-Type: application/json
{
  "list_bets": [
    "line#737779544#1#1#0#1.85"
  ],
  "amount": 10,
  "currency": "USD",
  "callback_url": "https://partner.example.com/api/coupon-result",
  "lang": "en",
  "mode": "reject",
  "mode_type": null,
  "multi": false
}
FieldMandatoryPurpose
list_betsYesOne or more pointers.
amountYesThe positive amount of one coupon being created.
currencyNoAny string designation, including virtual currency.
callback_urlNoURL callback; without a callback you can not send it, you can pass null, an empty string or a site domain.
langNoA two-letter code for one of approximately 50 supported languages. The language of names is fixed upon creation.
modeNoreject or accept; default reject.
mode_typeFor acceptAllowed direction of the odds change.
multiNoOne general coupon or individual singles; default false.

Odds

SettingsBehavior
mode = rejectReject creation when odds change.
mode = accept, mode_type = 1Accept only odds increases.
mode = accept, mode_type = 2Accept only odds decreases.
mode = accept, mode_type = 3Accept any change.

Singles, accumulators and multi

RequestResultDebit of client balance
One outcomeOne singleamount
Multiple outcomes, multi = falseOne accumulatoramount
Multiple outcomes, multi = trueSeparate single for each outcomeamount × number of created coupons

One accumulator train can contain no more than 15 events. You cannot combine multiple bets on the same match, including the main match, halves, periods, corners, fouls and other related sub-events. This combination returns 506.

6. Confirmation of coupon and bet placement

Full successful response with coupon and accepted bet data inside events_data:

{
  "code": 1,
  "body": {
    "coupons": [
      {
        "coupon_code": "000000000272",
        "amount": 10,
        "win": 18.5,
        "potential_win": 18.5,
        "real_win": null,
        "coef": 1.85,
        "original_coef": 1.85,
        "calculate_coef": null,
        "has_return": false,
        "date": 1784970000000,
        "status": 0,
        "asian": false,
        "calculate_date": null,
        "coupon_type": 1,
        "events_count": 1,
        "events_data": [
          {
            "id": 912,
            "game_id": 737779544,
            "main_game_id": 737779544,
            "is_sub_game": false,
            "parent_game_id": null,
            "sub_game_key": null,
            "raw_pointer": "line#737779544#1#1#0#1.85",
            "line_type": "line",
            "is_live": false,
            "bet_group_id": 1,
            "bet_group_name": "Match result",
            "bet_id": 1,
            "bet_name": "First team to win",
            "sport_id": 1,
            "sport_name": "Football",
            "tournament_id": 10001,
            "tournament": "National League",
            "event_date": 1784971800000,
            "status": 0,
            "opp1": "Team A",
            "opp2": "Team B",
            "coef": 1.85,
            "calc_coef": null,
            "bet_score": "line#737779544#1#1#0#1.85",
            "calculate_date": null,
            "calculate_score": null,
            "settlement_reason_code": null,
            "settlement_reason": null,
            "placement_score_full": null,
            "placement_score_periods": null,
            "calculation_score_full": null,
            "calculation_score_periods": null,
            "timer": null,
            "dop_name": null,
            "rate": "0",
            "sgame_id": null,
            "game_num": null,
            "stat_id": null,
            "team1_id": 101,
            "team2_id": 102,
            "opp_icon1": 101,
            "opp_icon2": 102
          }
        ]
      }
    ]
  },
  "error_code": null,
  "error_message": null,
  "date": 1784970000015,
  "time_ms": 45,
  "path": "/api/partner/coupons/place"
}

Coupon fields

Each item body.coupons[] is a separate coupon created.

FieldTypeMeaning
coupon_codestringPublic 12 digit coupon code. Store as a string to avoid losing leading zeros.
amountnumberThe coupon amount transferred upon creation.
winnumberCurrent displayed winning amount.
potential_winnumberPossible winnings before final settlement.
real_winnumber/nullActual payout amount after calculation; before calculation - null.
coefnumberCurrent or final coupon ratio.
original_coefnumberTotal coupon odds at the time of placement.
calculate_coefnumber/nullFinal settlement multiplier; before settlement — null.
has_returnbooleantrue, if the coupon contains a bet with a refund status.
dateintegerCoupon creation date, Unix timestamp in milliseconds.
statusintegerCurrent coupon status. The values ​​are described in the “Coupon and bet statuses” section.
asianbooleanSign of the presence of Asian settlement, including half winnings or losses.
calculate_dateinteger/nullCoupon calculation date in milliseconds; before calculation - null.
coupon_typeintegerCoupon type: 1 — single, 2 — accumulator.
events_countintegerNumber of bets inside the coupon.
events_dataarrayThe full array of bets included in the coupon.

Bet fields

Each element of events_data[] describes a specific accepted bet within the coupon.

FieldTypeMeaning
idinteger/nullInternal ID of the accepted bet. Used in conjunction with coupon_code to find a bet within a coupon.
game_idintegerID of the event or sub-event on which the bet is placed.
main_game_idinteger/nullID of the main match to which the event or sub-event belongs.
is_sub_gamebooleantrue, if the bet relates to a half, period, set, corners or other sub-event.
parent_game_idinteger/nullThe ID of the immediate parent event, if one exists.
sub_game_keystring/nullTechnical key of a sub-event or period.
raw_pointerstringThe original bet pointer accepted by the API.
line_typestringLine type: line - pre-match, live - real-time event.
is_livebooleantrue, if the bet was created on a live line.
bet_group_idintegerID of the bet group or market.
bet_group_namestring/nullLocalized name of the bet group.
bet_idintegerID of the selected selection within the bet group.
bet_namestring/nullLocalized full name of the selected selection.
sport_idinteger/nullSport ID.
sport_namestring/nullLocalized name of the sport.
tournament_idinteger/nullTournament ID.
tournamentstring/nullLocalized name of the tournament.
event_dateinteger/nullEvent start date, Unix timestamp in milliseconds.
statusintegerCurrent bet settlement status. Not to be confused with coupon status.
opp1string/nullName of the first team or participant.
opp2string/nullName of the second team or participant.
coefnumberThe bet odds at which the bet was accepted.
calc_coefnumber/nullCalculated bet multiplier; before calculation - null.
bet_scorestringLegacy API compatible field containing the bet indicator rather than the match score.
calculate_dateinteger/nullBet settlement date in milliseconds; before calculation - null.
calculate_scorestring/nullThe account used to calculate the bet.
settlement_reason_codestring/nullStable machine code of the reason for settlement or refund; before calculation - null.
settlement_reasonstring/nullExplanatory text of the reason for settlement or refund; before calculation - null.
placement_score_fullstring/nullTotal event score at the time the bet was created, if available.
placement_score_periodsstring/nullScore by period at the time the bet was created, if available.
calculation_score_fullstring/nullThe total score of the event at the time the bet is settled.
calculation_score_periodsstring/nullScore by period at the time of bet settlement.
timerinteger/nullEvent timer at the time of data saving, if available.
dop_namestring/nullName of the sub-event: half, period, set, inning, etc.
ratestringOutcome parameter, for example, the value of the total or handicap; for an outcome without a parameter - "0".
sgame_idstring/nullSub-event foreign key.
game_numinteger/nullGame number, if provided by the source.
stat_idstring/nullExternal statistical event ID.
team1_idinteger/nullID of the first team or participant.
team2_idinteger/nullID of the second team or participant.
opp_icon1integer/nullCompatible ID of the first command icon; matches team1_id.
opp_icon2integer/nullCompatible second team icon ID; matches team2_id.

The value null is normal for data that has not yet been calculated or is not available. Do not automatically replace it with 0 or the empty string.

Consider the coupon accepted only if code = 1 and the presence of objects in body.coupons. Before this, the basket is a preliminary choice: the selection could disappear, be blocked or the odds change.

After success:

  1. save all body.coupons objects, not just the first one;
  2. store coupon_code as a string with leading zeros;
  3. save the required data from events_data;
  4. match the coupon to the end user;
  5. record the user’s financial transaction in the partner’s system.

Identifiers:

FieldPurpose
coupon_codePublic coupon code.
events_data[].idID of the specific accepted bet inside the coupon.
callback events_data[].uuidThe same bet ID, passed as a string.
batchIdID of the callback batch version, not the coupon or bet.

currency is not returned in the full model and callback. If the currency is needed, save the value from the create request.

7. Creation errors

CodeReasonAction
10No request body.Correct the request.
11Invalid pointer.Get the current pointer from the line.
12Invalid amount.Pass a positive number.
501The odds have changed.Show new value or change mode.
502The outcome is unavailable.Remove or update the bet in the bet slip.
503The outcome is blocked.Report temporary unavailability.
504Outcome verification error.Do not consider the coupon accepted; repeat later.
506In an accumulator contains bets from the same match.Leave one outcome or use separate singles.
507Insufficient client balance.Top up your balance or reduce the total amount.
1002Invalid parameter set.Correct parameters.
10000Internal error.Record the error and check the result before retrying.

For 501504, the new API returns the affected bets in body.changes[]. Field change_type: 1 — the odds increased, 2 — the odds decreased, null — direction does not apply.

Don’t blindly retry POST /coupons/place after timeout: the first request may have been accepted and retrying will create a duplicate.

8. Receiving coupons

OperationEndpointResult
One couponGET /api/partner/coupons/get?coupon_code={code}Coupon at body.
ActiveGET /api/partner/coupons/activeArray in body[].
Recent calculationsGET /api/partner/coupons/calculated?time=10Array in body[]; maximum 120 minutes.
By code/periodPOST /api/partner/coupons/resultsArray in body.coupons.
Client balanceGET /api/partner/balancebody.balance.

You can transfer up to 100 values using codes:

{
  "coupon_ids": ["000000000272", "000000000273"]
}

Or pass the creation period no more than 24 hours:

{
  "start_date": 1784880000000,
  "end_date": 1784966400000
}

Do not combine coupon_ids and dates in the same query. results filters by creation time, and calculated filters by final settlement time.

9. Coupon and bet statuses

Coupon statuses:

CodeMeaningFinal
0Active or partially settled.No
2Won.Yes
4Lost.Yes
8Fully refunded.Yes
15Returned for recalculation; expect a new result.No

Bet statuses:

CodeMeaningcalc_coef
0Not calculated.null
1Win.Original odds
2Losing.0
3Return.1
4Awaiting recalculation.null
21Half the winnings.(coef + 1) / 2
22Half loss.0.5
23Push.1

For financial accrual to the end user, use the ready-made real_win. Do not use potential_win and do not recalculate the payout yourself. Before calculation, real_win, calculate_coef, calc_coef and calculate_date are equal to null, not 0.

At the first status of the coupon 15, if the previous result has already been financially processed, the partner once again debits amount from the end user, expects a new final status and charges a new real_win. Protect operations from reprocessing.

10. Reason for calculation

Each bet in the full model and callback has:

FieldPurpose
settlement_reason_codeStable settlement/refund reason code.
settlement_reasonExplanatory source text.

Before calculation, both fields are equal to null. For a localized notification, use code like:

  • MATCH_POSTPONED - the match has been postponed;
  • MATCH_CANCELLED - match cancelled;
  • MARKET_PUSH - return according to market rules.

If the code is unknown, save it and use the non-empty settlement_reason as a fallback text. Do not calculate the payout from the reason - use statuses and real_win.

These fields explain the calculation or return that has already been performed and are not a separate realtime feed of the match status.

11. Callback

Callback is optional. A partner can only work through polling. For callback, the manager must enable the function and create callback_secret; The URL is sent in every coupon created.

The partner determines the callback URL independently. In production it should use https://; in a test environment, http:// is allowed.

The system sends:

POST {callback_url}
Content-Type: application/json
X-Coupon-Signature: sha256=<hex_hmac_sha256>

Short payload:

{
  "event": "coupons.settled",
  "batchId": "d407e986f3a64d9d36a77bf532322ef8",
  "couponCount": 1,
  "coupons": [
    {
      "coupon_code": "000000000272",
      "realWin": 18.5,
      "calculate_coefficient": 1.85,
      "status": 2,
      "calculate_date": 1784973600000,
      "events_data": [
        {
          "uuid": "912",
          "status": 1,
          "calculate_coefficient": 1.85,
          "calculate_date": 1784973600000,
          "calculate_score": "2:1",
          "settlement_reason_code": "REMOTE_WIN",
          "settlement_reason": "Win",
          "timer": 0
        }
      ]
    }
  ]
}

Mandatory rules:

  1. calculate sha256=<hex(HMAC-SHA256(raw_body, callback_secret))> from the exact source bytes of the body before JSON parsing and compare signatures in a secure way;
  2. process all items coupons, the package can contain up to 100 coupons;
  3. store batchId with a unique index;
  4. repeated batchId should not repeat the debit or accrual;
  5. one coupon_code can come with different batchId during progressive calculation and recalculation;
  6. return HTTP 200 only after the entire packet has been securely stored.

The minimum successful response is an empty HTTP 200. Advanced:

{
  "success": true,
  "processed": 1
}

processed must equal couponCount. Responses 201, 202, and 204 are not considered successful.

Replays are performed only in case of timeout, transport error or HTTP 500, 502, 503, 504: immediately, then after 1, 5, 15 and 60 minutes - no more than five sendings. There is no automatic retry on HTTP 200 with success: false or partial processed.

12. Polling fallback

Even with callback, periodically check the results:

GET /api/partner/coupons/calculated?time=10

After a break of more than 120 minutes, use POST /api/partner/coupons/results over saved coupon_ids or creation periods up to 24 hours. Receiving the same state again should not repeat financial transactions.

13. Security and storage

  • store login, password, JWT and callback_secret only on the server;
  • do not pass JWT in the URL and do not write the full token in the logs;
  • use decimal type for money;
  • store coupon_code as a string;
  • save amount, the required bet data and currency, if used;
  • distinguish between coupon and bet statuses;
  • accept unknown fields and reason codes without error;
  • Make all end-user financial transactions idempotent.

14. Old API and Cashout

Old routes continue to be supported, but new integrations must use /api/partner/**. Old answers and errors have different formats. To update an existing client, use a single file “Migrating from the old API”.

Cashout is in development, not fully tested and not recommended for production.

15. Final checklist

  • Received BASE_URL, login and password.
  • JWT is transmitted as a Bearer token.
  • The pointers are taken from the line without modification.
  • The cart is saved as an accepted coupon only after code = 1.
  • Processed multi, accumulator restrictions and errors 501507.
  • The automatic debit of the client balance has been taken into account.
  • All coupon_code and bet IDs are saved.
  • The final payout is taken from real_win.
  • The callback is checked against the source bytes and deduplicated using batchId.
  • Backup polling has been configured.
  • The user balance is separate from the client balance SportAPI.

Detailed documentation begins with API overview. The complete endpoint map is in manual.

Need more documentation or integration help?