Переход со старого API
Этот документ сравнивает старое описание old_api_calc.txt с клиентским OpenAPI 1.2.0. Он нужен существующим интеграторам, которые уже работают с /api/v2/login, /bet/place и /coupons/**.
Все необходимые изменения интеграции должны быть описаны на этой странице. Для перехода на новый API партнеру не должно требоваться чтение остальных разделов документации.
Главное
Старые маршруты продолжают поддерживаться в совместимом режиме, и их удаление в настоящее время не планируется. Для новых интеграций рекомендуется /api/partner/**. Переход можно выполнять поэтапно, но нельзя предполагать, что новый маршрут возвращает старую структуру ответа.
Изменения маршрутов
| Операция | Было | Стало | Что изменить у клиента |
|---|---|---|---|
| Авторизация | POST /api/v2/login | POST /api/partner/login | Перейти на расширенный ответ и новые правила HTTP 401/403. |
| Создание купона | POST /bet/place | POST /api/partner/coupons/place | Читать массив body.coupons, а не купон непосредственно из body. |
| Получение купона | GET /coupons/get | GET /api/partner/coupons/get | Использовать новый полный формат купона. |
| Купоны за период | GET /coupons/list | POST /api/partner/coupons/results | Передавать JSON с start_date и end_date. |
| Купоны по кодам | Не было отдельного режима | POST /api/partner/coupons/results | Передавать до 100 значений в coupon_ids. |
| Недавние расчеты | GET /coupons/calculated | GET /api/partner/coupons/calculated | Логика окна до 120 минут сохранена, формат купона расширен. |
| Активные купоны | Не были полноценно описаны | GET /api/partner/coupons/active | Можно получать все активные купоны клиента. |
| Баланс | Не было отдельного метода чтения. | GET /api/partner/balance | Добавлен read-only запрос своего клиентского баланса. Создание купона автоматически списывает средства с этого баланса. |
| Cashout quote | GET /coupons/cashout | Нового маршрута пока нет | Функция не протестирована и находится в разработке; не использовать в production до отдельного объявления. |
Авторизация и доступ
| Было | Стало |
|---|---|
Основное поле логина — login. | Основное поле — username, при этом login остается совместимым алиасом. |
Все отказы входа преобразовывались в error_code = 99, Wrong login or password. | Новый login различает неполный запрос (1002), неверные данные (1003), отключенный аккаунт (1004), истекший доступ (1006) и недостаточный баланс (1007). Все эти бизнес-ошибки приходят с HTTP 200 и code = 0. |
Неверный токен на старых маршрутах возвращает HTTP 200, code = 0, error_code = 1003. | Новые защищенные маршруты используют HTTP 401; неподходящая роль — HTTP 403. |
| Старый документ не описывал надежную изоляцию данных клиента. | Владелец определяется только по подписанному клиентскому JWT. Чужой и неизвестный купон неразличимы. |
Формат ответа
| Было | Стало |
|---|---|
Оболочка: code, body, error_code, error_message, date. | Добавлены диагностические поля time_ms и path. |
Успешное создание возвращало один купон непосредственно в body. | body.coupons всегда является массивом, потому что multi = true может создать несколько купонов. |
| Клиент часто ориентировался на наличие HTTP-успеха. | Бизнес-ошибка обычно по-прежнему приходит с HTTP 200; обязательно проверять code. |
Новый клиент должен считать создание успешным только при одновременном выполнении условий:
HTTP 200
code = 1
body.coupons содержит созданный купон или купоны
Нельзя сохранять содержимое корзины как принятый купон до этого ответа: исход мог исчезнуть, быть заблокирован или изменить коэффициент во время создания.
Код купона
| Было | Стало |
|---|---|
В примерах использовались коды разной длины: "0934412", "1009982318". | Публичный coupon_code — строка, обычно содержащая 12 цифр, например "000000000272". |
| Код можно было ошибочно хранить числом. | Код нужно хранить строкой, чтобы не потерять ведущие нули. |
| Разделение публичного кода и ID базы не было явно описано. | coupon_code не равен внутреннему ID записи. |
Указатель ставки
Старый документ:
<type_line>#<game_id>|<bet_group_id>|<bet_id>|<param>#<coefficient>
Новый канонический формат:
line_type#game_id#group_id#type_id#rate#coefficient[#player_id]
Точечные изменения:
- названия позиций унифицированы:
line_type,group_id,type_id,rate; - добавлен необязательный
player_idдля персональных рынков; - официально допускаются разделители
#и|, включая совместимый смешанный формат; - сервер проверяет формат, наличие, блокировку и актуальный коэффициент исхода;
- неверный формат имеет отдельный код
11.
Параметры создания
| Поле | Было | Стало |
|---|---|---|
list_bets | Один или несколько строковых указателей. | Сохранено; минимум один элемент. |
amount | float. | Десятичное положительное число; обязательное поле. |
currency | Валюта ставки. | Сохранено как необязательное строковое поле. Можно использовать любую обычную, виртуальную, внутреннюю или вымышленную валюту; код ISO 4217 не обязателен. |
callback_url | URL результата. | Сохраняется отдельно для каждого купона; пустое значение отключает callback этого купона. |
lang | В примерах использовались отдельные языковые коды. | Передается двухбуквенный код языка; API поддерживает около 50 языков. Язык фиксируется при создании, получить существующий купон в другом переводе сейчас нельзя. Полный перечень языков не публикуется. |
mode | accept или reject. | Сохранено; в новом API значение по умолчанию — reject. |
mode_type | 1, 2, 3. | Общая логика направлений сохранена. |
multi | Число 0/1, функция была отмечена как разрабатываемая. | Boolean false/true; при true каждый исход создает отдельный купон. |
При multi = true значение amount применяется к каждому созданному ординару. Например, два исхода и amount = 10 создают два отдельных купона с общей суммой списания 20.
Списание клиентского баланса
Успешное создание в новом API атомарно списывает общую сумму с баланса клиентского аккаунта SportAPI:
multi = false— одинamount;multi = true—amount × количество создаваемых купонов.
Если общей суммы недостаточно, API возвращает HTTP 200, code = 0, error_code = 507, Insufficient balance. Ни один купон не создается и клиентский баланс не изменяется. Частичный успех при multi = true невозможен.
Не путайте этот баланс с кошельком конечного пользователя партнера: SportAPI изменяет клиентский баланс автоматически, а партнер самостоятельно выполняет финансовую операцию в своей пользовательской системе.
При multi = false несколько исходов формируют один экспресс. В одном экспрессе допускается не более 15 событий. Также нельзя объединять несколько ставок из одного дерева матча: например, основной матч и угловые либо угловые и фолы. Такая комбинация возвращает error_code = 506.
Изменение и недоступность исхода
| Ситуация | Старое поведение | Новое поведение |
|---|---|---|
| Коэффициент изменился | Общая ошибка 501. | 501, сведения находятся в body.changes[]. |
| Исход отсутствует | 501, статус nodata. | Отдельная ошибка 502, статус no_data. |
| Исход заблокирован | 501, статус block. | Отдельная ошибка 503, статус block. |
| Проверка исхода завершилась ошибкой | Общая серверная ошибка. | Отдельная бизнес-ошибка 504, статус error. |
В новом API body.changes всегда является массивом. Клиенту больше не нужно поддерживать разный тип body для ординара и экспресса.
Поле change_type имеет только числовой формат:
1— коэффициент повысился;2— коэффициент понизился;null— исход заблокирован, отсутствует либо его проверка завершилась ошибкой.
Строковые значения increase и decrease не используются.
Модель купона
В новую модель добавлены или явно разделены:
- внутренний ID ставки
events_data[].id; potential_winиreal_win;original_coefиcalculate_coef;has_return;raw_pointer,line_type,is_live;main_game_id,is_sub_game,parent_game_id,sub_game_key;- счет на момент приема и счет расчета;
sport_name,tournament_id;team1_id,team2_id;opp_icon1,opp_icon2.settlement_reason_codeиsettlement_reasonдля причины расчета или возврата.
Старый ответ не содержал отдельного ID принятой ставки. В новом API партнер может хранить конкретную ставку по сочетанию:
coupon_code + events_data[].id
В callback этот ID ставки передается строкой в поле events_data[].uuid. Поле batchId имеет другое назначение: оно идентифицирует версию пакета callback и используется для дедупликации доставки.
Все клиентские даты должны трактоваться как Unix timestamp в миллисекундах. Старое исключение, где event_date описывался в секундах, больше не должно использоваться.
До расчета купона или отдельной ставки поле calculate_date равно null. Значение 0 больше не используется.
Денежные значения и коэффициенты являются десятичными числами без фиксированной точности. Правило округления и формат хранения партнер определяет в своей системе.
Поле currency не входит в полную модель купона и callback. Если оно требуется для финансового учета, партнер должен сохранить переданное значение у себя вместе с coupon_code.
Для программной обработки причины расчета используйте settlement_reason_code. Поле settlement_reason является поясняющим текстом и может меняться; неизвестные коды нужно принимать и сохранять.
Статусы
Старый документ описывал только основные статусы купона 0, 2, 4 и ставки 0, 1, 2, 3, 21, 22.
Новый контракт дополнительно фиксирует:
- купон
8— возврат; - купон
15— возвращен на перерасчет и ожидает нового результата; - ставка
4— ожидает перерасчета; - ставка
23— push; - расчетный множитель для возврата и половинных результатов;
- отдельные исходный, рабочий и расчетный коэффициенты.
При возврате на перерасчет сразу отправляется callback со статусом купона 15 и статусом исхода 4. После перерасчета отправляется новый callback с актуальными статусами.
Если предыдущий результат купона уже был обработан, при первом получении статуса 15 партнер должен повторно списать сумму ставки amount. После нового финального статуса необходимо начислить новое значение real_win. Повтор callback с тем же batchId не должен повторно изменять баланс. Поле amount в callback отсутствует, поэтому его нужно сохранить при создании купона или получить через endpoint чтения.
Получение результатов
| Было | Стало |
|---|---|
| Основной способ — периодический запрос рассчитанных купонов. | Добавлен необязательный подписанный callback. Партнер может оставить polling основным способом либо использовать его как резервную сверку. |
/coupons/list возвращал историю с ограниченной и не полностью определенной выборкой. | /api/partner/coupons/results имеет два точных режима: до 100 кодов или период создания до 24 часов. |
| Разница между временем создания и временем расчета была описана нечетко. | results фильтрует по времени создания, calculated — по времени окончательного расчета. |
Callback
Старый документ передавал callback_url, но не определял надежный публичный протокол доставки.
В новом API зафиксированы:
- событие
coupons.settled; - HMAC-SHA256 в
X-Coupon-Signature; - подпись точных байтов тела;
- пакетирование до 100 снимков;
- идентификатор версии доставки
batchId, который не является ID купона или ставки; - идемпотентная обработка;
- прогрессивные обновления экспресса;
- немедленное уведомление о первом проигрыше;
- финальный снимок после расчета всех ставок;
- повторы после временных ошибок через 1, 5, 15 и 60 минут;
- обязательный HTTP
200для подтверждения доставки. settlement_reason_codeиsettlement_reasonв каждой ставке расчетного снимка.
Callback подключается по желанию партнера. Партнер сообщает менеджеру, что хочет его использовать, после чего менеджер создает секретную фразу для подписи. URL задается самим партнером в callback_url при создании купона. В production следует использовать HTTPS; в тестовой среде допускается HTTP.
Публиковать постоянный IP отправителя в интеграционной документации не требуется. Если партнер дополнительно использует список разрешенных IP, актуальный адрес нужно получить у менеджера. Такая фильтрация является дополнительной мерой и не заменяет проверку HMAC.
Минимальный план миграции
- Начать хранить
coupon_codeстрокой. - Добавить поддержку новой оболочки ответа.
- Перейти на
POST /api/partner/login. - Перейти на
POST /api/partner/coupons/placeи читатьbody.coupons[]. - Перейти на
body.changes[]и отдельные ошибки501–504. - Добавить новые поля и статусы без удаления обработки старых.
- Выбрать получение результатов: polling, callback либо оба способа.
- Если выбран callback, согласовать его с менеджером, проверять HMAC и выполнять дедупликацию по
batchId. - Использовать
calculatedилиresultsдля получения результатов и сверки. - Проверить обработку статусов купона
8,15и ставок4,23. - Проверить, что
calculate_date = nullкорректно обрабатывается до расчета. - Учесть отдельное списание
amountдля каждого купона приmulti = true. - Запретить в корзине экспресса более 15 событий и связанные ставки одного матча.
- Сохранять нужные данные купона и ставок только после успешного ответа создания.
- Если нужна валюта купона, сохранять ее в своей системе при создании.
- Обработать
507как атомарный отказ без созданных купонов и без списания клиентского баланса. - Добавить хранение
settlement_reason_codeи не использовать текстsettlement_reasonкак программный ключ. - После проверки новой интеграции поэтапно отключить обращения к старым маршрутам.