SportAPI Documentation
EN
C Product documentationCoupon API
v1
Service & pricing ↗ Get access ↗
Coupon API / Coupon placement

Coupon Placement

Use the following endpoint to register the bets selected by a user:

POST /api/partner/coupons/place

The method validates the submitted outcomes and creates one or more coupons.

The old API used POST /bet/place. This endpoint remains supported, but its response format and some error codes are different. New integrations should use /api/partner/coupons/place. All required changes are described in Migrating from the old API.

Authentication

The method requires a client JWT:

Authorization: Bearer <client_token>

The owner of the created coupons is determined by the JWT. See Authentication for details.

Minimum request

The following fields are required to place a coupon:

  • list_bets — an array of pointers to the selected outcomes;
  • amount — a positive stake amount.

Example single:

curl --request POST \
  --url "$BASE_URL/api/partner/coupons/place" \
  --header "Accept: application/json" \
  --header "Authorization: Bearer <client_token>" \
  --header "Content-Type: application/json" \
  --data '{
    "list_bets": [
      "line#737779544#1#1#0#1.85"
    ],
    "amount": 10
  }'

If mode and multi are omitted, the safe defaults are used:

{
  "mode": "reject",
  "multi": false
}

Complete request example

curl --request POST \
  --url "$BASE_URL/api/partner/coupons/place" \
  --header "Accept: application/json" \
  --header "Authorization: Bearer <client_token>" \
  --header "Content-Type: application/json" \
  --data '{
    "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
  }'

Request fields

FieldTypeRequiredDescription
list_betsarray[string]YesOne or more pointers to selected outcomes. The array cannot be empty.
amountnumberYesPositive stake amount.
currencystring/nullNoAny string identifying the currency, such as USD, UAH, COIN, or the name of the partner’s internal currency.
callback_urlstring/nullNoThe partner specifies this URL. When callbacks are used, it is the result handler URL. Without callbacks, the partner’s main website domain may be provided.
langstring/nullNoTwo-letter language code for names in the coupon data.
modestring/nullNoRule for handling changed odds: reject or accept. Default: reject.
mode_typeinteger/nullFor mode = "accept"Additional rule that determines which odds changes may be accepted. Values are described in Odds changes and outcome availability.
multiboolean/nullNofalse creates one combined coupon; true creates a separate single for every entry in list_bets. Default: false. See Singles, accumulators, and multi for details.

list_bets

Each array entry represents one bet and is submitted as a string:

{
  "list_bets": [
    "line#737779544#1#1#0#1.85",
    "live#738917381#119#5869#0.5#3.6"
  ]
}

Complete pointers must be obtained from selected sports-line outcomes or iframe and submitted without modification. The format is described in detail on the Bet pointer page.

amount

amount is the stake for one coupon being created. It is submitted as a positive decimal number without a fixed number of decimal places:

{
  "amount": 10.5
}

With multi = false, this is the stake for the combined single or accumulator. With multi = true, this stake is applied separately to every single created. A detailed total stake example is provided in Singles, accumulators, and multi.

After successful placement, the API automatically debits this amount from the SportAPI client account balance. This is the integration balance, not the end user’s balance in the partner’s system.

currency

Provide the currency identifier used by the partner:

{
  "currency": "USD"
}

The field is not limited to official currencies and does not require an ISO 4217 code. It may identify a regular, virtual, internal, or fictional currency.

For example:

{
  "currency": "COIN"
}

The API treats currency as a string identifier. To ensure that the partner can associate coupons correctly, use the same identifier for the same currency in every placement request.

callback_url

The partner specifies the callback_url. If callbacks are used, provide the full URL of the result handler:

{
  "callback_url": "https://partner.example.com/api/coupon-result"
}
  • use only https:// in production;
  • http:// is permitted in the test environment;
  • null, an empty string, or an omitted field disables callback delivery for the coupon being placed;
  • with multi = true, the URL is stored for every coupon created.

If callbacks are not used, omit the field or provide null or an empty string. The partner’s main website domain may also be provided, for example:

{
  "callback_url": "https://partner.example.com"
}

Provide the main domain instead of an endpoint only when callbacks are not enabled for the account. The main domain is not treated as a callback handler URL. If the manager enables callbacks, all new coupons must specify the full endpoint URL that accepts and processes POST requests.

Callbacks are optional: current coupon states can be obtained through regular API requests. A partner that wants to use callbacks must inform the manager. The manager enables delivery and creates a secret phrase for signature verification.

Receiver configuration, signatures, and delivery retries are described in Callbacks.

lang

Provide a two-letter language code:

{
  "lang": "en"
}

This language is used for sport, tournament, team, bet group, and outcome names in coupon data. The API supports approximately 50 languages; the full list is not published in this documentation.

The language is fixed when the coupon is placed. The coupon can subsequently be retrieved only in the language specified in lang at placement time. The same coupon cannot currently be requested in another translation. Support for multiple language variants of one coupon is in development.

mode and mode_type

In brief:

  • mode = "reject" — do not create the coupon if the odds have changed;
  • mode = "accept" — allow changed odds to be accepted according to the mode_type rule.

The mode_type values, responses to odds changes, and recommended interface behavior are described separately in Odds changes and outcome availability.

multi

In brief:

  • multi = false — all entries in list_bets form one coupon;
  • multi = true — each entry forms a separate single.

With multi = true, several coupons are created, so a successful response always contains the body.coupons array. Financial behavior and examples are described in Singles, accumulators, and multi.

What the API validates

Before creating the coupon, the SportAPI Coupon Settlement System validates:

  1. the request and pointer formats;
  2. whether the outcomes exist in the current sports line;
  3. whether the outcomes are blocked;
  4. whether the odds are current;
  5. that an accumulator does not contain multiple outcomes from the main match and its related sub-events;
  6. that amount is positive;
  7. that the client account balance is sufficient to create all coupons.

A coupon is considered accepted only after a successful API response.

Important. Do not store the contents of the partner’s bet slip as an accepted coupon before receiving confirmation from the API. The bet slip contains only the user’s preliminary selection. During placement, the Settlement System validates the outcomes again. By that time, an outcome may have disappeared from the sports line, become blocked, or changed its odds. In this case, the API rejects the request and the coupon is not accepted.

Create an accepted coupon record in the partner’s system only when code = 1, and store the coupons returned in body.coupons. When code = 0 is returned or no coupons were created, do not store preliminary bet slip data as an accepted coupon.

Balance debit and atomicity

Coupon placement follows an all-or-nothing rule:

  • with multi = false, one amount is debited from the client account balance;
  • with multi = true, amount × number of singles being created is debited;
  • all coupons are created together;
  • if the total balance is insufficient, the balance remains unchanged and no coupon is created.

A successful response with code = 1 means that the coupons were created and the corresponding amount has already been debited from the SportAPI client balance.

The partner manages the end user’s balance independently. Preliminary reservation and final debiting in the partner’s system do not replace the automatic debit from the SportAPI client balance and are not performed by this API.

Successful response

Example response for a single:

{
  "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,
            "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": "Test tournament",
            "event_date": 1784977200000,
            "status": 0,
            "opp1": "Team 1",
            "opp2": "Team 2",
            "team1_id": 101,
            "team2_id": 102,
            "opp_icon1": 101,
            "opp_icon2": 102,
            "coef": 1.85,
            "calc_coef": null,
            "bet_score": "line#737779544#1#1#0#1.85",
            "calculate_date": null,
            "calculate_score": null,
            "rate": "0"
          }
        ]
      }
    ]
  },
  "error_code": null,
  "error_message": null,
  "date": 1784970000015,
  "time_ms": 45,
  "path": "/api/partner/coupons/place"
}

The operation is successful when all of the following are true:

  • a successful HTTP response was received;
  • code = 1;
  • body.coupons contains the created coupons.

Even when one coupon is created, body.coupons is an array. With multi = true, it contains a separate object for every single created.

Returned data

Each entry in body.coupons contains:

  • coupon data: code, amount, odds, potential and actual payout, status, and dates;
  • events_data — an array containing all bets in the coupon;
  • for each bet: the original pointer, event, market, names, odds, settlement status, and other available data.

The partner decides which coupon and bet fields must be stored in the partner’s system. However, coupon_code must always be stored: it is the linking key used to retrieve and update the coupon later.

Store coupon_code as a string to preserve leading zeros:

000000000272

Bet identifier within a coupon

A coupon has its own coupon_code, while every bet in events_data has an internal id:

{
  "coupon_code": "000000000272",
  "events_data": [
    {
      "id": 912,
      "game_id": 737779544,
      "status": 0
    }
  ]
}

If the partner stores and updates bets separately, we recommend storing:

coupon_code + events_data[].id

This combination uniquely identifies a specific bet within a specific coupon.

In a callback, the bet identifier is provided as a string in events_data[].uuid. For example, uuid = "912" corresponds to the bet with id = 912 in the full coupon model.

The game_id and bet_id fields have different purposes: they identify the sporting event and selected outcome type, but are not IDs of the specific accepted bet.

Do not confuse the bet identifier with batchId: batchId identifies a callback delivery, not a coupon or an individual bet.

All returned fields are described in Coupon and bet model.

Initial coupon state

Immediately after placement:

  • the coupon has status 0;
  • its bets have status 0;
  • real_win is null;
  • calculate_coef is null;
  • calculate_date is null for both the coupon and its bets.

The value 0 is not used instead of null for calculate_date.

Statuses and subsequent settlement are described in Statuses and payouts.

Placement errors

error_codeCause
10The request body was not provided.
11At least one bet pointer has an invalid format.
12amount is missing or is not a positive number.
501The odds changed and were not accepted under the specified rules.
502The outcome is not available in the current sports line.
503The outcome is blocked.
504An error occurred while validating the outcome.
506One accumulator contains multiple outcomes from the same match: the main event and/or related sub-events. See Bets from the same match in an accumulator.
507The client account balance is insufficient to create all coupons.
1002An invalid set of parameters was provided.
10000Internal service error.

Errors 501504 return details about affected outcomes in body.changes. Do not treat the response as successful only because the HTTP status is 200.

When the balance is insufficient, the API returns HTTP 200 with code = 0:

{
  "code": 0,
  "error_code": 507,
  "error_message": "Insufficient balance",
  "date": 1753000000000,
  "time_ms": 5,
  "path": "/api/partner/coupons/place"
}

When 507 is returned, do not store any coupon as accepted. The entire operation was rejected and the client balance was not changed.

After a network or server error, do not retry the request automatically until you have ruled out the possibility that the first request was processed. This protects the user from accidental duplicate coupons.

Next section: Singles, accumulators, and multi.