Polling Fallback
Polling is the periodic retrieval of coupon states through the SportAPI Coupon Settlement System Client API.
It can be used:
- as the primary way to receive results when callbacks are not enabled;
- as fallback reconciliation while callbacks are operating;
- to recover after the callback endpoint was temporarily unavailable;
- to check a specific coupon at the request of a user or support team.
Callbacks and polling are not mutually exclusive. The most reliable approach is to use callbacks for fast updates and additionally reconcile settled coupons through the API at regular intervals.
Every request in this section requires a valid Bearer JWT:
Authorization: Bearer <token>
Available verification methods
| Task | Method |
|---|---|
| Find coupons finally settled during the last N minutes | GET /api/partner/coupons/calculated |
| Retrieve the current state of known coupons as a list | POST /api/partner/coupons/results with coupon_ids |
| Find coupons by their placement time | POST /api/partner/coupons/results with start_date and end_date |
| Check one coupon | GET /api/partner/coupons/get |
| Retrieve all active coupons | GET /api/partner/coupons/active |
Use /api/partner/** endpoints for new integrations.
Recommended fallback flow
For example, the partner may send a request every 5 minutes:
GET /api/partner/coupons/calculated?time=10 HTTP/1.1
Host: coupon-api.example.com
Authorization: Bearer <token>
Accept: application/json
In this example:
- polling runs every 5 minutes;
- every request checks the last 10 minutes again;
- adjacent time windows overlap.
The overlap prevents a result from being missed if one run does not occur because of an application restart, network error, or temporary API outage.
Receiving an already processed coupon again is normal. The partner system must update the existing record rather than create a new coupon or repeat a financial operation.
The partner chooses the polling interval according to the required update speed and its own load. We recommend requesting a period at least twice as long as the normal polling interval.
Recently settled coupons
Use:
GET /api/partner/coupons/calculated?time={minutes}
Example:
BASE_URL="https://coupon-api.example.com"
TOKEN="<jwt-token>"
curl "$BASE_URL/api/partner/coupons/calculated?time=10" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json"
The time parameter defines how many recent minutes of finally settled coupons should be returned.
Parameter rules:
| Condition | Behavior |
|---|---|
time is omitted | The last 5 minutes are used. |
time <= 0 | The value is replaced with 5 minutes. |
time > 120 | The last 120 minutes are used. |
| Supported working range | 1 to 120 minutes. |
Coupons are selected by final settlement time, not placement time.
The method does not return:
- active coupons;
- coupons belonging to other partners.
This endpoint is convenient for regular polling, but one call is not sufficient to recover after an interruption longer than 120 minutes.
Checking a list of known coupons
If the partner system contains coupons for which a current final result has not yet been recorded, request them by code:
POST /api/partner/coupons/results HTTP/1.1
Host: coupon-api.example.com
Authorization: Bearer <token>
Content-Type: application/json
{
"coupon_ids": [
"000000000272",
"000000000273"
]
}
One request may contain no more than 100 codes.
Behavior:
- duplicate codes in the input array are removed;
- unknown coupons and coupons belonging to other partners are omitted from the response;
- the coupon order in the response may differ from the order of
coupon_ids; - the response may contain fewer entries than the number of submitted codes.
Match results by coupon_code, not by array position.
The response uses the common format:
{
"code": 1,
"body": {
"query_type": "ids",
"coupons": []
},
"error_code": null,
"error_message": null,
"date": 1784970000000,
"time_ms": 8,
"path": "/api/partner/coupons/results"
}
The body.coupons array contains the complete current models of the coupons that were found.
This request is especially useful:
- after a polling interruption longer than 120 minutes;
- to periodically check coupons that are locally considered incomplete;
- after receiving status
15, while waiting for a new result; - for batch reconciliation of partner data with the API.
Searching by placement period
The second POST /api/partner/coupons/results mode finds coupons by placement time:
POST /api/partner/coupons/results HTTP/1.1
Host: coupon-api.example.com
Authorization: Bearer <token>
Content-Type: application/json
{
"start_date": 1784880000000,
"end_date": 1784966400000
}
start_date and end_date are Unix timestamps in milliseconds.
Restrictions:
- both values are required;
end_datemust be greater thanstart_date;- one interval cannot exceed 24 hours;
- dates and
coupon_idscannot be submitted together; - a parameter error returns
error_code = 1002.
In the response, body.query_type is time.
Important. This mode selects coupons by placement time, not settlement time. It is suitable for restoring the list of coupons placed during a particular period, but it does not replace
/calculatedwhen searching for results that appeared later.
For example, if a coupon was placed one week ago and received a new result today, a request for today’s placement period will not find it. Use /calculated or a request with its known coupon_code.
Checking one coupon
For a targeted check, use:
GET /api/partner/coupons/get?coupon_code=000000000272 HTTP/1.1
Host: coupon-api.example.com
Authorization: Bearer <token>
Accept: application/json
Always submit the complete coupon_code as a string, including leading zeros.
If the coupon is not found or belongs to another partner, the API returns:
{
"code": 0,
"error_code": 471,
"error_message": "Coupon not found"
}
This method is suitable for:
- opening a coupon detail page;
- checking a result in response to a user request;
- resolving a discrepancy between a callback and local data;
- retrieving the full model when a callback does not contain the required fields.
Active coupons
Retrieve all active partner coupons with:
GET /api/partner/coupons/active HTTP/1.1
Host: coupon-api.example.com
Authorization: Bearer <token>
Accept: application/json
No parameters are required. The method returns active coupons in the full format.
Use it to restore the list of incomplete coupons, but not as a replacement for /calculated: a completed coupon disappears from the active list and must be retrieved through result methods.
Combined callback and polling processing
Callbacks contain batchId, while polling responses do not. Deduplication therefore occurs at two levels:
| Source | Linking key | Rule |
|---|---|---|
| Callback | batchId | A repeated batch is not processed again. |
| Callback and polling | coupon_code | Both update the same local coupon record. |
| Bet within a coupon | coupon_code + id or coupon_code + uuid | The existing bet is updated. |
In the full polling model, a bet has the field events_data[].id. In a callback, the same bet is provided as events_data[].uuid in string form.
Do not create separate local coupons for callback and polling data. Both sources describe the state of the same coupon.
Do not credit funds only because a final coupon appears in polling again. The financial operation must be protected by a unique key and performed once for the specific settlement state.
If callback and polling data arrive almost simultaneously and differ, request the current full model through GET /api/partner/coupons/get and synchronize the local record with it. Do not decide which state is newer only from the order in which the HTTP requests arrived.
Recovery after an outage
Interruption of no more than 120 minutes
- Resume regular polling.
- Call
/calculatedwith a window that fully covers the interruption. - Update the returned coupons by
coupon_code. - Resume the schedule with overlapping windows.
Example after a 40-minute interruption:
GET /api/partner/coupons/calculated?time=50
The small margin prevents results at the interval boundary from being missed.
Interruption longer than 120 minutes
- Retrieve from your database the codes of coupons whose current final result has not yet been confirmed.
- Split them into groups of no more than 100 codes.
- Request each group through
POST /api/partner/coupons/resultswithcoupon_ids. - If necessary, restore coupons placed during the outage using placement periods of no more than 24 hours.
- Match every result by
coupon_code. - After reconciliation, return to regular
/calculatedpolling with overlapping windows.
If only one problematic coupon is known locally, use /coupons/get.
Processing the response
HTTP 200 means that the server processed the HTTP request, but the business result must be checked separately:
- check the HTTP status;
- parse the JSON;
- verify that the top-level
codeequals1; - process the entire coupon array;
- update coupons and bets idempotently;
- perform financial operations only for settlement transitions not yet processed.
Do not treat an empty array as an error. It may mean that no matching coupons exist in the selected window.
After a transport error or temporary API outage, do not move the time window forward. Repeat the same request and, after recovery, use a window with a safety margin.
Checklist
- Polling operates even when callbacks are enabled.
- Regular request windows overlap.
- The
timevalue does not exceed 120 minutes. - Known
coupon_codevalues are used after a long interruption. - Requests by code contain no more than 100 entries.
- Date searches use placement time rather than settlement time.
coupon_codeis stored as a string with leading zeros.- The entire response array is processed, not only the first coupon.
- Callback and polling data update the same local record.
- Receiving the same result again does not repeat a debit or credit.
- Financial actions use
real_win, notpotential_win. - Status
15is not treated as final.
Detailed descriptions of the methods begin in the next section: Retrieving a single coupon.