SportApi
Документація API · версія 1.2.0

Результати ставок, ставки та купони — технічна документація API

Цей файл містить мінімальний самостійний сценарій підключення до системи розрахунку купонів SportAPI. Подробиці та рідкісні випадки перебувають у повній документації.

Основний сценарій http
POST /api/partner/login
POST /api/partner/coupons/place
GET  /api/partner/coupons/calculated?time=10

1. Що потрібно отримати у менеджера

  • базова URL API;
  • логін та пароль клієнтського облікового запису;
  • при використанні callback - включення функції та секретну фразу callback_secret.

У прикладах використовується умовна адреса:

BASE_URL="https://coupon-api.example.com"

У production використовуйте HTTPS. Усі дати передаються як Unix timestamp у мілісекундах, а грошові значення – як десяткові числа без фіксованої точності.

2. Формат відповіді API

Успіх:

{
  "code": 1,
  "body": {},
  "error_code": null,
  "error_message": null,
  "date": 1784970000000,
  "time_ms": 5,
  "path": "/api/partner/example"
}

Бізнес-помилка зазвичай також надходить з HTTP 200:

{
  "code": 0,
  "body": null,
  "error_code": 1002,
  "error_message": "Not all params",
  "date": 1784970000000,
  "time_ms": 5,
  "path": "/api/partner/example"
}

Завжди перевіряйте код HTTP, потім code, потім error_code. Не використовуйте error_message як програмний ключ.

3. Авторизація

POST /api/partner/login
Content-Type: application/json
{
  "username": "partner-demo",
  "password": "strong-password"
}

Поле login підтримується як сумісний аліас username.

Успішна відповідь:

{
  "code": 1,
  "body": {
    "token": "<jwt-token>",
    "user_id": 17,
    "username": "partner-demo"
  },
  "error_code": null,
  "error_message": null
}

У всіх захищених запитах передавайте:

Authorization: Bearer <jwt-token>

Основні помилки входу:

КодПричина
1002Не надіслано логін або пароль.
1003Невідомий логін або пароль.
1004Клієнтський обліковий запис вимкнено.
1006Закінчилась дата доступу.
1007Клієнтський баланс дорівнює нулю чи негативний.

Ці помилки повертаються з HTTP 200, code = 0. HTTP 401 захищеного методу означає, що JWT відсутній, невірний, минув або відкликаний; виконайте вхід повторно. HTTP 403 означає невідповідну роль або заборону доступу.

4. Вказівник ставки

Кожен вибраний результат передається готовим рядком зі спортивної лінії:

line_type#game_id#group_id#type_id#rate#coefficient[#player_id]

Приклади:

line#737779544#1#1#0#1.85
live#738917381|119|5869|0.5#3.6#149439538
  • line_type: line або live;
  • rate: параметр тотала/фори або 0;
  • player_id: необов’язковий ID гравця;
  • роздільники # та | підтримуються.

Не збирайте та не виправляйте вказівник вручну – передавайте отримане з лінії значення без змін.

5. Створення купона

POST /api/partner/coupons/place
Authorization: Bearer <jwt-token>
Content-Type: application/json
{
  "list_bets": [
    "line#737779544#1#1#0#1.85"
  ],
  "amount": 10,
  "currency": "USD",
  "callback_url": "https://partner.example.com/api/coupon-result",
  "lang": "en",
  "mode": "reject",
  "mode_type": null,
  "multi": false
}
ПолеОбов’язковеПризначення
list_betsТакОдин чи кілька вказівників.
amountТакПозитивна сума одного створюваного купона.
currencyНіБудь-яке строкове позначення, включаючи віртуальну валюту.
callback_urlНіURL callback; без callback можна не передавати, передати null, порожній рядок чи домен сайту.
langНіДволітерний код однієї з приблизно 50 мов, що підтримуються. Мова назв фіксується при створенні.
modeНіreject або accept; за замовчуванням reject.
mode_typeДля acceptДопустимий напрямок зміни коефіцієнта.
multiНіОдин загальний купон чи окремі ординари; за замовчуванням false.

Коефіцієнти

НалаштуванняПоведінка
mode = rejectВідхилити створення за зміни коефіцієнта.
mode = accept, mode_type = 1Приймати лише підвищення.
mode = accept, mode_type = 2Приймати лише зниження.
mode = accept, mode_type = 3Приймати будь-яку зміну.

Ординар, експрес та multi

ЗапитРезультатСписання клієнтського балансу
Один результатОдин ординарamount
Декілька результатів, multi = falseОдин експресamount
Декілька результатів, multi = trueОкремий ординар на кожен результатamount × кількість створених купонів

Один експрес може містити трохи більше 15 подій. Не можна об’єднувати кілька ставок одного матчу, включаючи основний матч, тайми, періоди, кутові, фоли та інші пов’язані саб-події. Така комбінація повертає 506.

6. Підтвердження створення купона та ставки

Повна успішна відповідь з даними купона та прийнятої ставки всередині events_data:

{
  "code": 1,
  "body": {
    "coupons": [
      {
        "coupon_code": "000000000272",
        "amount": 10,
        "win": 18.5,
        "potential_win": 18.5,
        "real_win": null,
        "coef": 1.85,
        "original_coef": 1.85,
        "calculate_coef": null,
        "has_return": false,
        "date": 1784970000000,
        "status": 0,
        "asian": false,
        "calculate_date": null,
        "coupon_type": 1,
        "events_count": 1,
        "events_data": [
          {
            "id": 912,
            "game_id": 737779544,
            "main_game_id": 737779544,
            "is_sub_game": false,
            "parent_game_id": null,
            "sub_game_key": null,
            "raw_pointer": "line#737779544#1#1#0#1.85",
            "line_type": "line",
            "is_live": false,
            "bet_group_id": 1,
            "bet_group_name": "Match result",
            "bet_id": 1,
            "bet_name": "First team to win",
            "sport_id": 1,
            "sport_name": "Football",
            "tournament_id": 10001,
            "tournament": "National League",
            "event_date": 1784971800000,
            "status": 0,
            "opp1": "Team A",
            "opp2": "Team B",
            "coef": 1.85,
            "calc_coef": null,
            "bet_score": "line#737779544#1#1#0#1.85",
            "calculate_date": null,
            "calculate_score": null,
            "settlement_reason_code": null,
            "settlement_reason": null,
            "placement_score_full": null,
            "placement_score_periods": null,
            "calculation_score_full": null,
            "calculation_score_periods": null,
            "timer": null,
            "dop_name": null,
            "rate": "0",
            "sgame_id": null,
            "game_num": null,
            "stat_id": null,
            "team1_id": 101,
            "team2_id": 102,
            "opp_icon1": 101,
            "opp_icon2": 102
          }
        ]
      }
    ]
  },
  "error_code": null,
  "error_message": null,
  "date": 1784970000015,
  "time_ms": 45,
  "path": "/api/partner/coupons/place"
}

Поля купона

Кожен елемент body.coupons[] - окремий купон.

ПолеТипЗначення
coupon_codestringПублічний 12-значний код купона. Тримайте рядком, щоб не втратити провідні нулі.
amountnumberСума купона, передана під час створення.
winnumberПоточна сума виграшу, що відображається.
potential_winnumberМожливий виграш до остаточного розрахунку.
real_winnumber/nullФактична сума виплати після розрахунку; до розрахунку - null.
coefnumberПоточний чи підсумковий коефіцієнт купона.
original_coefnumberЗагальний коефіцієнт купона на момент створення.
calculate_coefnumber/nullПідсумковий розрахунковий коефіцієнт; до розрахунку - null.
has_returnbooleantrue, якщо у купоні є ставка зі статусом повернення.
dateintegerДата створення купона, Unix timestamp у мілісекундах.
statusintegerПоточний статус купона. Значення описані у розділі «Статуси купона та ставок».
asianbooleanОзнака наявності азіатського розрахунку, включаючи половинний виграш чи програш.
calculate_dateinteger/nullДата розрахунку купона у мілісекундах; до розрахунку - null.
coupon_typeintegerТип купона: 1 - ординар, 2 - експрес.
events_countintegerКількість ставок усередині купона.
events_dataarrayПовний масив ставок, які входять у купон.

Поля ставки

Кожен елемент events_data[] визначає конкретну прийняту ставку всередині купона.

ПолеТипЗначення
idinteger/nullВнутрішній ID прийнятої ставки. Використовується разом із coupon_code для пошуку ставки всередині купона.
game_idintegerID події або саб-події, на яку зроблено ставку.
main_game_idinteger/nullID основного матчу, до якого належить подія чи саб-подія.
is_sub_gamebooleantrue, якщо ставка стосується тайму, періоду, сету, кутової або іншої саб-події.
parent_game_idinteger/nullID безпосередньої батьківської події, якщо вона існує.
sub_game_keystring/nullТехнічний ключ саб-події чи періоду.
raw_pointerstringВихідний вказівник ставки, прийнятий API.
line_typestringТип лінії: line - прематч, live - подія в реальному часі.
is_livebooleantrue, якщо ставка була створена по live-лінії.
bet_group_idintegerID групи ставок чи ринку.
bet_group_namestring/nullЛокалізована назва групи ставок.
bet_idintegerID вибраного результату всередині групи ставок.
bet_namestring/nullЛокалізована повна назва вибраного результату.
sport_idinteger/nullID виду спорту.
sport_namestring/nullЛокалізована назва виду спорту.
tournament_idinteger/nullID турніру.
tournamentstring/nullЛокалізована назва турніру.
event_dateinteger/nullДата початку події, Unix timestamp у мілісекундах.
statusintegerПоточний статус обчислення ставки. Не плутайте зі статусом купона.
opp1string/nullНазва першої команди чи учасника.
opp2string/nullНазва другої команди чи учасника.
coefnumberКоефіцієнт ставки, з яким її було прийнято.
calc_coefnumber/nullРозрахунковий множник ставки; до розрахунку - null.
bet_scorestringСумісне поле старого API, що містить вказівник ставки, а не рахунок матчу.
calculate_dateinteger/nullДата розрахунку ставки у мілісекундах; до розрахунку - null.
calculate_scorestring/nullРахунок, використаний для розрахунку ставки.
settlement_reason_codestring/nullСтабільний машинний код причини розрахунку чи повернення; до розрахунку - null.
settlement_reasonstring/nullПояснюючий текст причини розрахунку чи повернення; до розрахунку - null.
placement_score_fullstring/nullЗагальний рахунок події на момент створення ставки, якщо доступний.
placement_score_periodsstring/nullРахунок за періодами на момент створення ставки, якщо доступний.
calculation_score_fullstring/nullЗагальний рахунок події на момент розрахунку ставки.
calculation_score_periodsstring/nullРахунок за періодами на момент розрахунку ставки.
timerinteger/nullТаймер події в момент збереження даних, якщо доступний.
dop_namestring/nullНазва саб-події: тайму, періоду, сету, іннінгу тощо.
ratestringПараметр результату, наприклад, значення тотала або фори; для результату без параметра - "0".
sgame_idstring/nullЗовнішній ключ подія.
game_numinteger/nullНомер гри, якщо він наданий джерелом.
stat_idstring/nullЗовнішній статистичний ID події.
team1_idinteger/nullID першої команди чи учасника.
team2_idinteger/nullID другої команди або учасника.
opp_icon1integer/nullСумісний ID іконки першої команди; збігається із team1_id.
opp_icon2integer/nullСумісний ID іконки другої команди; збігається із team2_id.

Значення null є нормальним для даних, що ще не розраховані або недоступні. Не замінюйте його автоматично на 0 або порожній рядок.

Вважайте купон прийнятим тільки при code = 1 та наявності об’єктів у body.coupons. До цього кошик є попереднім вибором: результат міг зникнути, заблокуватися чи змінити коефіцієнт.

Після успіху:

  1. збережіть усі об’єкти body.coupons, а не лише перший;
  2. збережіть coupon_code рядком із провідними нулями;
  3. збережіть потрібні дані із events_data;
  4. зіставте купон із кінцевим користувачем;
  5. зафіксуйте фінансову операцію користувача у системі партнера.

Ідентифікатори:

ПолеПризначення
coupon_codeПублічний код купона.
events_data[].idID конкретної прийнятої ставки всередині купона.
callback events_data[].uuidТой самий ID ставки, переданий рядком.
batchIdID версії пакета callback, а не купона чи ставки.

currency не повертається до повної моделі та callback. Якщо валюта потрібна, збережіть значення із запиту створення.

7. Помилки створення

КодПричинаДія
10Немає тіла запиту.Виправити запит.
11Неправильний покажчик.Отримати актуальний покажчик із лінії.
12Неправильний amount.Передати позитивне число.
501Коефіцієнт змінився.Показати нове значення або змінити mode.
502Вихід відсутній.Видалити/оновити ставку у кошику.
503Результат заблоковано.Повідомити про тимчасову недоступність.
504Помилка перевірки результату.Не вважати купон прийнятим; повторити пізніше.
506У експресі ставки одного матчу.Залишити один результат або використовувати окремі ординари.
507Недостатній баланс клієнта.Поповнити баланс чи зменшити загальну суму.
1002Неправильний набір параметрів.Виправити параметри.
10000Внутрішня помилкаЗафіксувати помилку та перевірити результат перед повтором.

Для 501504 новий API повертає проблемні ставки у body.changes[]. Поле change_type: 1 - коефіцієнт зріс, 2 - знизився, null - напрямок не застосовується.

Не повторюйте POST /coupons/place наосліп після timeout: перший запит міг бути прийнятий, і повтор створить дублікат.

8. Отримання купонів

ОпераціяEndpointРезультат
Один купонGET /api/partner/coupons/get?coupon_code={code}Купон у body.
АктивніGET /api/partner/coupons/activeМасив у body[].
Нещодавні розрахункиGET /api/partner/coupons/calculated?time=10Масив у body[]; максимум 120 хвилин.
За кодами/періодомPOST /api/partner/coupons/resultsМасив у body.coupons.
Клієнтський балансGET /api/partner/balancebody.balance.

За кодами можна передати до 100 значень:

{
  "coupon_ids": ["000000000272", "000000000273"]
}

Або передати період створення не більше 24 годин:

{
  "start_date": 1784880000000,
  "end_date": 1784966400000
}

Не поєднуйте coupon_ids і дати в одному запиті. results фільтрує за часом створення, а calculated - за часом остаточного розрахунку.

9. Статуси купона та ставок

Статуси купона:

КодЗначенняФінальний
0Активний чи частково розрахований.Ні
2Виграв.Так
4Програв.Так
8Повністю повернуто.Так
15Повернено на перерахунок; чекайте на новий результат.Ні

Статуси ставки:

КодЗначенняcalc_coef
0Чи не розрахована.null
1Виграш.Вихідний коефіцієнт
2Програш.0
3Повернення.1
4Чекає на перерахунок.null
21Половинний виграш.(coef + 1) / 2
22Половинний програш.0.5
23Push.1

Для фінансового нарахування кінцевому користувачу використовуйте готовий real_win. Не використовуйте potential_win та не перераховуйте виплату самостійно. До розрахунку real_win, calculate_coef, calc_coef та calculate_date рівні null, а не 0.

При першому статусі купона 15, якщо попередній результат вже був фінансово оброблений, партнер один раз повторно списує amount з кінцевого користувача, чекає на новий фінальний статус і нараховує нове real_win. Захистіть операції від повторної обробки.

10. Причина розрахунку

Кожна ставка в повній моделі і callback є:

ПолеПризначення
settlement_reason_codeСтабільний код причини розрахунку/повернення.
settlement_reasonПояснювальний текст.

До розрахунку обидва поля дорівнюють null. Для локалізованого повідомлення використовуйте код, наприклад:

  • MATCH_POSTPONED - матч перенесений;
  • MATCH_CANCELLED - матч скасований;
  • MARKET_PUSH - повернення за правилами ринку.

При невідомому коді збережіть його та використовуйте непустий settlement_reason як запасний текст. Не розраховуйте виплату з причини - використовуйте статуси і real_win.

Ці поля пояснюють вже виконаний розрахунок чи повернення і не є окремою реальноючасом-стрічкою стану матчу.

11. Callback

Callback необов’язковий. Партнер може працювати лише через polling. Для callback менеджер повинен увімкнути функцію та створити callback_secret; URL передається в кожному створюваному купоні.

URL callback партнер визначає самостійно. У виробництві він повинен використовувати https://; у тестовому оточенні допускається http://.

Система відправляє:

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

Скорочений payload:

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

Обов’язкові правила:

  1. обчислюйте sha256=<hex(HMAC-SHA256(raw_body, callback_secret))> за точними вихідними байтами тіла до розбору JSON і порівнюйте підписи безпечним способом;
  2. обробляйте всі елементи coupons, пакет може містити до 100 купонів;
  3. зберігайте batchId з унікальним індексом;
  4. повторний batchId не повинен повторювати списання чи нарахування;
  5. один coupon_code може приходити з різними batchId при прогресивному розрахунку та перерахунку;
  6. повертайте HTTP 200 лише після надійного збереження всього пакета.

Мінімальна успішна відповідь – порожня HTTP 200. Розширений:

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

processed повинен дорівнювати couponCount. Відповіді 201, 202 та 204 не вважаються успішними.

Повтори виконуються тільки при timeout, транспортній помилці або HTTP 500, 502, 503, 504: відразу, потім через 1, 5, 15 та 60 хвилин – не більше п’яти. На HTTP 200 із success: false або частковим processed автоматичного повтору немає.

12. Резервний polling

Навіть при callback періодично звіряйте результати:

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

Після перерви більше 120 хвилин використовуйте POST /api/partner/coupons/results за збереженими coupon_ids або періоди створення до 24 годин. Повторне отримання того ж таки стану не повинно повторювати фінансові операції.

13. Безпека та зберігання

  • зберігайте логін, пароль, JWT та callback_secret тільки на сервері;
  • не передавайте JWT URL і не записуйте повний токен в логи;
  • використовуйте десятковий тип для грошей;
  • зберігайте coupon_code рядком;
  • зберігайте amount, потрібні дані ставок та currency, якщо вона використовується;
  • розрізняйте статуси купона та ставки;
  • невідомі поля та коди причин приймайте без помилки;
  • усі фінансові операції кінцевого користувача робіть ідемпотентними.

14. Старий API та Cashout

Старі маршрути продовжують підтримуватись, але нові інтеграції повинні використовувати /api/partner/**. Формати старих відповідей та помилок відрізняються. Для оновлення існуючого клієнта використовуйте єдиний файл Перехід зі старого API.

Cashout знаходиться в розробці, повністю не протестований і не рекомендується для виробництва.

15. Фінальний чек-лист

  • Отримано BASE_URL, логін та пароль.
  • JWT передається як Bearer token.
  • Вказівники беруться з лінії без змін.
  • Кошик зберігається як прийнятий купон лише після code = 1.
  • Оброблено multi, обмеження експресу та помилки 501507.
  • Враховано автоматичне списання клієнтського балансу.
  • Збережено всі coupon_code та ID ставок.
  • Фінальна виплата береться із real_win.
  • Callback перевіряється за вихідними байтами та дедуплікується за batchId.
  • Настроєний резервний polling.
  • баланс користувача відокремлений від клієнтського балансу SportAPI.

Детальна документація починається з огляду API. Повна карта endpoint знаходиться в довіднику.

Потрібні додаткові матеріали або допомога з підключенням?