Резервный polling
Polling — это периодическая проверка состояния купонов через клиентский API Системы расчета купонов SportAPI.
Его можно использовать:
- как основной способ получения результатов, если callback не подключен;
- как резервную сверку при работающем callback;
- для восстановления после временной недоступности callback endpoint;
- для проверки конкретного купона по запросу пользователя или службы поддержки.
Callback и polling не исключают друг друга. Наиболее надежная схема — принимать callback для быстрых обновлений и дополнительно периодически сверять рассчитанные купоны через API.
Все запросы этого раздела требуют действующий Bearer JWT:
Authorization: Bearer <token>
Доступные способы проверки
| Задача | Метод |
|---|---|
| Найти купоны, окончательно рассчитанные за последние N минут | GET /api/partner/coupons/calculated |
| Получить актуальное состояние известных купонов списком | POST /api/partner/coupons/results с coupon_ids |
| Найти купоны по времени их создания | POST /api/partner/coupons/results с start_date и end_date |
| Проверить один купон | GET /api/partner/coupons/get |
| Получить все активные купоны | GET /api/partner/coupons/active |
Для новой интеграции используйте маршруты /api/partner/**.
Рекомендуемая резервная схема
Например, партнер может выполнять запрос каждые 5 минут:
GET /api/partner/coupons/calculated?time=10 HTTP/1.1
Host: coupon-api.example.com
Authorization: Bearer <token>
Accept: application/json
В этом примере:
- polling запускается каждые 5 минут;
- каждый запрос повторно проверяет последние 10 минут;
- соседние временные окна перекрываются.
Перекрытие защищает от пропуска результата, если один запуск не состоялся из-за перезапуска приложения, сетевой ошибки или временной недоступности API.
Повторное получение уже обработанного купона является нормальным. Система партнера должна обновлять существующую запись, а не создавать новый купон и не повторять финансовую операцию.
Интервал запуска партнер выбирает с учетом требуемой скорости обновления и своей нагрузки. Рекомендуется запрашивать период как минимум в два раза больше обычного интервала polling.
Недавно рассчитанные купоны
Используйте:
GET /api/partner/coupons/calculated?time={minutes}
Пример:
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"
Параметр time определяет, за сколько последних минут нужно вернуть окончательно рассчитанные купоны.
Правила параметра:
| Условие | Поведение |
|---|---|
time не передан | Используются последние 5 минут. |
time <= 0 | Значение заменяется на 5 минут. |
time > 120 | Используются последние 120 минут. |
| Допустимый рабочий диапазон | От 1 до 120 минут. |
Отбор выполняется по времени окончательного расчета купона, а не по времени его создания.
Метод не возвращает:
- активные купоны;
- купоны других партнеров.
Этот endpoint удобен для регулярного polling, но одного вызова недостаточно для восстановления после перерыва продолжительностью более 120 минут.
Проверка известных купонов списком
Если в системе партнера есть купоны, для которых еще не зафиксирован актуальный финальный результат, запросите их по кодам:
POST /api/partner/coupons/results HTTP/1.1
Host: coupon-api.example.com
Authorization: Bearer <token>
Content-Type: application/json
{
"coupon_ids": [
"000000000272",
"000000000273"
]
}
В одном запросе можно передать не более 100 кодов.
Особенности:
- повторяющиеся коды во входном массиве удаляются;
- неизвестные купоны и купоны других партнеров не включаются в ответ;
- порядок купонов в ответе может отличаться от порядка
coupon_ids; - количество элементов в ответе может быть меньше количества переданных кодов.
Поэтому сопоставляйте результат по coupon_code, а не по позиции элемента в массиве.
Ответ имеет общий формат:
{
"code": 1,
"body": {
"query_type": "ids",
"coupons": []
},
"error_code": null,
"error_message": null,
"date": 1784970000000,
"time_ms": 8,
"path": "/api/partner/coupons/results"
}
Массив body.coupons содержит полные актуальные модели найденных купонов.
Такой запрос особенно полезен:
- после перерыва polling более чем на 120 минут;
- для периодической проверки локально незавершенных купонов;
- после получения статуса
15, пока ожидается новый результат; - для пакетной сверки данных партнера с API.
Поиск по периоду создания
Второй режим POST /api/partner/coupons/results позволяет найти купоны по времени создания:
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 и end_date передаются в Unix-миллисекундах.
Ограничения:
- оба значения обязательны;
end_dateдолжен быть большеstart_date;- один интервал не может превышать 24 часа;
- нельзя одновременно передавать даты и
coupon_ids; - ошибка параметров возвращается с
error_code = 1002.
В ответе body.query_type имеет значение time.
Важно. Этот режим отбирает купоны по времени создания, а не по времени расчета. Он подходит для восстановления списка купонов, созданных в определенный период, но не заменяет
/calculatedдля поиска результатов, появившихся позднее.
Например, если купон был создан неделю назад и сегодня получил новый результат, запрос только за сегодняшний период создания его не найдет. Для такого купона используйте /calculated либо запрос по известному coupon_code.
Проверка одного купона
Для точечной проверки используйте:
GET /api/partner/coupons/get?coupon_code=000000000272 HTTP/1.1
Host: coupon-api.example.com
Authorization: Bearer <token>
Accept: application/json
Всегда передавайте coupon_code как строку полностью, включая ведущие нули.
Если купон не найден или принадлежит другому партнеру, API возвращает:
{
"code": 0,
"error_code": 471,
"error_message": "Coupon not found"
}
Этот метод подходит для:
- открытия карточки купона;
- проверки результата по обращению пользователя;
- разрешения расхождения между callback и локальными данными;
- получения полной модели, если callback не содержит нужных полей.
Активные купоны
Получить все активные купоны партнера можно запросом:
GET /api/partner/coupons/active HTTP/1.1
Host: coupon-api.example.com
Authorization: Bearer <token>
Accept: application/json
Параметры не требуются. Метод возвращает активные купоны в полном формате.
Используйте его для восстановления списка незавершенных купонов, но не вместо /calculated: завершенный купон исчезает из списка активных и должен быть получен через методы результатов.
Совместная обработка callback и polling
Callback содержит batchId, а ответы polling — нет. Поэтому дедупликация выполняется на двух уровнях:
| Источник | Связующий ключ | Правило |
|---|---|---|
| Callback | batchId | Повтор одного пакета не обрабатывается повторно. |
| Callback и polling | coupon_code | Обновляется одна и та же локальная запись купона. |
| Ставка внутри купона | coupon_code + id или coupon_code + uuid | Обновляется существующая ставка. |
В полной модели polling ставка имеет поле events_data[].id. В callback та же ставка передается как events_data[].uuid в строковом виде.
Не создавайте отдельные локальные купоны для callback и polling. Оба источника описывают состояние одного купона.
Также нельзя выполнять начисление только потому, что финальный купон снова появился в polling. Финансовая операция должна быть защищена уникальным ключом и выполняться один раз для конкретного расчетного состояния.
Если данные callback и polling были получены почти одновременно и отличаются, запросите текущую полную модель через GET /api/partner/coupons/get и синхронизируйте локальную запись с ней. Не определяйте более новое состояние только по порядку прихода HTTP-запросов.
Восстановление после недоступности
Перерыв не превышал 120 минут
- Возобновите обычный polling.
- Выполните
/calculatedс окном, которое полностью покрывает перерыв. - Обновите найденные купоны по
coupon_code. - Возобновите расписание с перекрывающимися окнами.
Пример после перерыва в 40 минут:
GET /api/partner/coupons/calculated?time=50
Небольшой запас нужен, чтобы не потерять результаты на границе интервала.
Перерыв превышал 120 минут
- Получите из своей базы коды купонов, актуальный финальный результат которых еще не подтвержден.
- Разделите их на группы не более 100 кодов.
- Запросите группы через
POST /api/partner/coupons/resultsсcoupon_ids. - При необходимости восстановите купоны, созданные во время сбоя, запросами по периодам создания не более 24 часов.
- Сопоставьте каждый результат по
coupon_code. - После сверки вернитесь к обычному
/calculatedс перекрытием.
Если локально известен только один проблемный купон, используйте /coupons/get.
Обработка ответа
HTTP 200 означает, что сервер обработал HTTP-запрос, но бизнес-результат нужно проверять отдельно:
- проверить HTTP-код;
- разобрать JSON;
- убедиться, что верхнеуровневое поле
codeравно1; - обработать весь массив купонов;
- обновить купоны и ставки идемпотентно;
- выполнить финансовые операции только для еще не обработанных расчетных переходов.
Не считайте пустой массив ошибкой. Он может означать, что в выбранном окне нет подходящих купонов.
При транспортной ошибке или временной недоступности API не перемещайте временное окно вперед. Повторите тот же запрос, а после восстановления используйте окно с запасом.
Контрольный список
- Polling работает даже при включенном callback.
- Временные окна регулярных запросов перекрываются.
- Значение
timeне превышает 120 минут. - После длительного перерыва используются известные
coupon_code. - Запросы по кодам разбиваются максимум по 100 элементов.
- Поиск по датам учитывает время создания, а не расчета.
coupon_codeхранится строкой с ведущими нулями.- Обрабатывается весь массив ответа, а не только первый купон.
- Callback и polling обновляют одну локальную запись.
- Повторное получение результата не повторяет списание или начисление.
- Финансовое действие выполняется по
real_win, а не поpotential_win. - Статус
15не считается финальным.
Подробное описание каждого метода находится в следующем разделе: «Получение одного купона».