SportAPI Документация
RU
C Документация продуктаCoupon API
v1
Услуга и цены ↗ Получить доступ ↗
Coupon API / Резервный polling

Резервный 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 — нет. Поэтому дедупликация выполняется на двух уровнях:

ИсточникСвязующий ключПравило
CallbackbatchIdПовтор одного пакета не обрабатывается повторно.
Callback и pollingcoupon_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 минут

  1. Возобновите обычный polling.
  2. Выполните /calculated с окном, которое полностью покрывает перерыв.
  3. Обновите найденные купоны по coupon_code.
  4. Возобновите расписание с перекрывающимися окнами.

Пример после перерыва в 40 минут:

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

Небольшой запас нужен, чтобы не потерять результаты на границе интервала.

Перерыв превышал 120 минут

  1. Получите из своей базы коды купонов, актуальный финальный результат которых еще не подтвержден.
  2. Разделите их на группы не более 100 кодов.
  3. Запросите группы через POST /api/partner/coupons/results с coupon_ids.
  4. При необходимости восстановите купоны, созданные во время сбоя, запросами по периодам создания не более 24 часов.
  5. Сопоставьте каждый результат по coupon_code.
  6. После сверки вернитесь к обычному /calculated с перекрытием.

Если локально известен только один проблемный купон, используйте /coupons/get.

Обработка ответа

HTTP 200 означает, что сервер обработал HTTP-запрос, но бизнес-результат нужно проверять отдельно:

  1. проверить HTTP-код;
  2. разобрать JSON;
  3. убедиться, что верхнеуровневое поле code равно 1;
  4. обработать весь массив купонов;
  5. обновить купоны и ставки идемпотентно;
  6. выполнить финансовые операции только для еще не обработанных расчетных переходов.

Не считайте пустой массив ошибкой. Он может означать, что в выбранном окне нет подходящих купонов.

При транспортной ошибке или временной недоступности API не перемещайте временное окно вперед. Повторите тот же запрос, а после восстановления используйте окно с запасом.

Контрольный список

  • Polling работает даже при включенном callback.
  • Временные окна регулярных запросов перекрываются.
  • Значение time не превышает 120 минут.
  • После длительного перерыва используются известные coupon_code.
  • Запросы по кодам разбиваются максимум по 100 элементов.
  • Поиск по датам учитывает время создания, а не расчета.
  • coupon_code хранится строкой с ведущими нулями.
  • Обрабатывается весь массив ответа, а не только первый купон.
  • Callback и polling обновляют одну локальную запись.
  • Повторное получение результата не повторяет списание или начисление.
  • Финансовое действие выполняется по real_win, а не по potential_win.
  • Статус 15 не считается финальным.

Подробное описание каждого метода находится в следующем разделе: «Получение одного купона».