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

Result Callbacks

Callbacks allow the partner to receive coupon settlement changes without continuously polling the API.

Callbacks are optional. The partner may retrieve results only through coupon read methods or combine callbacks with periodic reconciliation.

Enabling callbacks

If the partner wants to use callbacks:

  1. inform the manager;
  2. provide the manager with the required connection details;
  3. the manager enables callbacks and creates the secret phrase callback_secret;
  4. store the secret on the server side;
  5. provide the handler URL in callback_url whenever a coupon is placed.

The secret phrase is used to verify the HMAC signature. It is not returned by the Client API and must not be exposed to the browser, logs, or public code.

Delivery conditions

A callback is sent only when all of the following are true:

  • the manager enabled callbacks for the account;
  • a secret phrase is configured for the account;
  • a non-empty callback_url was provided when the specific coupon was placed.

If any condition is not met, retrieve the result through API requests.

Handler URL

The partner defines callback_url and provides it when placing a coupon:

{
  "callback_url": "https://partner.example.com/api/coupon-result"
}

Rules:

  • use only https:// in production;
  • http:// is permitted in the test environment;
  • one coupon may have only one callback_url;
  • different coupons may use different URLs;
  • the URL is stored with the coupon and used for its subsequent updates;
  • the endpoint must accept POST requests and JSON.

With multi = true, the URL is stored for every single created.

If callbacks are not used, omit the field or provide null, an empty string, or the partner’s main website domain. The main domain is not a callback handler and should be used only when callbacks are disabled.

Network access and IP allowlist

The endpoint must be accessible to incoming requests from the SportAPI Coupon Settlement System.

IP filtering on the partner side is optional. A specific outgoing IP address is not fixed in the public documentation. If the partner wants to use an allowlist, obtain the current address from the manager.

HMAC signature verification is mandatory regardless of IP filtering.

HTTP request

The system sends:

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

The signature is calculated from the exact bytes of the JSON body. Do not parse and reserialize the JSON before verifying the signature.

The complete algorithm and code examples are provided in Callback signature verification.

Event type

The event field always contains:

coupons.settled

This value is used for:

  • final settlement of a single;
  • an intermediate accumulator state;
  • the first losing bet in an accumulator;
  • the final accumulator state;
  • returning a coupon for recalculation;
  • a new result after recalculation.

The event name does not mean that every received snapshot is necessarily final. Always check coupons[].status and the bet statuses.

Batch delivery

One HTTP request may contain up to 100 coupon snapshots:

{
  "couponCount": 2,
  "coupons": [
    {},
    {}
  ]
}

couponCount is the number of entries in coupons. The handler must iterate over the entire array rather than only the first coupon.

One batch contains snapshots for one account and one callback_url.

Example payload

Example intermediate accumulator state:

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

In this example, the first bet is settled and the second remains active. The coupon therefore remains at status 0, while realWin and calculate_coefficient are still 0.

Top-level fields

FieldTypeDescription
eventstringEvent type. Always coupons.settled.
batchIdstringIdentifier of the specific callback batch version. Used for idempotency.
clientIdintegerInternal partner account ID. Informational only.
couponCountintegerNumber of entries in the coupons array.
couponsarrayCoupon settlement snapshots.

Coupon snapshot fields

FieldTypeDescription
coupon_codestringPublic coupon code.
realWinnumberActual payout. 0 in an intermediate snapshot.
calculate_coefficientnumberFinal settlement multiplier. 0 in an intermediate snapshot.
statusintegerCurrent coupon status.
calculate_dateinteger/nullLatest settlement date among the settled bets, as Unix milliseconds.
events_dataarrayAll coupon bets, including those not yet settled.

Bet fields

FieldTypeDescription
uuidstringStable internal identifier of the bet within the coupon.
statusintegerCurrent bet status.
calculate_coefficientnumber/nullBet settlement multiplier.
calculate_dateinteger/nullBet settlement date, as Unix milliseconds.
calculate_scorestringSettlement score; may be an empty string for an active bet.
settlement_reason_codestring/nullStable machine-readable settlement or return reason code; null before settlement.
settlement_reasonstring/nullSettlement or return reason text; null before settlement.
timerintegerCompatibility field, currently 0.

Use settlement_reason_code for analytics and program branching. settlement_reason may contain the original reason text and is primarily intended for storage, logging, or display. The set of codes may grow, so an unknown code must not cause the callback to be rejected.

If the partner displays the result reason to the user, it is better to localize a custom message based on the code. For example, MATCH_POSTPONED means the match was postponed, MATCH_CANCELLED means it was cancelled, and MARKET_PUSH means a return under market rules. For an unknown code, use settlement_reason as fallback text, but not as a key for financial logic.

Data not included in callbacks

A callback contains a settlement snapshot rather than the complete coupon record. It does not include:

  • amount;
  • currency;
  • sport and tournament names;
  • team names;
  • market and outcome names;
  • the original bet pointer.

However, the callback does include settlement_reason_code and settlement_reason for every bet.

Store the missing data after coupon placement or retrieve it through coupon read methods.

Identifiers

Do not confuse the purposes of these identifiers:

FieldWhat it identifies
coupon_codeThe coupon.
events_data[].uuidA specific bet within the coupon.
batchIdA specific callback batch version.

In the full coupon model, a bet has the numeric field events_data[].id. In a callback, the same ID is provided as a string in uuid.

Recommended relationships in the partner database:

coupon: coupon_code
bet: coupon_code + uuid
callback delivery: batchId

batchId is not a coupon or bet ID.

Multiple callbacks for one coupon

The same coupon_code may normally arrive several times:

  • an accumulator is updated as its bets are settled;
  • the first loss is sent immediately;
  • after all bets in a losing accumulator are settled, the final snapshot arrives;
  • recalculation creates a new state.

Every new state receives a new batchId. A repeated HTTP delivery of an existing batch retains the same batchId.

Do not treat another occurrence of coupon_code as a duplicate. Update the coupon state by coupon_code, and identify a repeat of the same delivery by batchId.

Singles and accumulators

For a single, a callback is sent after a result becomes available.

For an accumulator:

  1. until the accumulator loses, a new snapshot is sent after each subsequent bet is settled;
  2. on the first losing outcome, a snapshot with coupon status 4 is sent immediately;
  3. subsequent intermediate changes to the losing accumulator are not sent;
  4. after all bets are settled, the final complete snapshot is sent.

The complete scenario is described in Settlement lifecycle.

Recalculation

When a coupon is returned for recalculation:

  • the coupon receives status 15;
  • the corresponding bet receives status 4;
  • a snapshot with this state is sent immediately;
  • after recalculation, a new snapshot with current statuses is sent.

If the previous result has already been financially processed, on first receiving status 15 the partner:

  1. debits the stake amount again;
  2. waits for a new final result;
  3. credits the new realWin value.

The callback does not contain amount, so store it when the coupon is placed or retrieve it through a read API method.

The financial operation is performed once. A repeated delivery with the same batchId must not debit or credit funds again.

Minimum processing flow

Recommended order:

  1. read the original request body as bytes;
  2. verify X-Coupon-Signature;
  3. begin a transaction;
  4. store batchId with a unique constraint;
  5. if batchId has already been processed, do not repeat business operations;
  6. process every entry in coupons;
  7. update coupons by coupon_code and bets by uuid;
  8. commit the financial operations;
  9. commit the transaction;
  10. return HTTP 200.

See Retries and idempotency for details.

Successful response

Minimum successful response:

HTTP/1.1 200 OK

The body may be empty.

Recommended extended response:

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

The processed value must equal couponCount.

Return HTTP 200 only after every entry in the batch has been committed successfully.

Responses 201, 202, and 204 are not considered successful delivery acknowledgements: the current contract requires HTTP 200 specifically.

Negative or partial acknowledgement

Even with HTTP 200, the response body may indicate an error:

  • success: false — the batch was not processed;
  • processed < couponCount — only part of the batch was processed.

Such an acknowledgement is treated as a final error and is not retried automatically. Therefore, do not return success: false or a partial processed value with the expectation that delivery will be retried.

Temporary errors must return one of the supported HTTP status codes. The retry schedule and conditions are described in Retries and idempotency.

Next section: Callback signature verification.