Результати ставок, ставки та купони — технічна документація API
Цей файл містить мінімальний самостійний сценарій підключення до системи розрахунку купонів SportAPI. Подробиці та рідкісні випадки перебувають у повній документації.
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_code | string | Публічний 12-значний код купона. Тримайте рядком, щоб не втратити провідні нулі. |
amount | number | Сума купона, передана під час створення. |
win | number | Поточна сума виграшу, що відображається. |
potential_win | number | Можливий виграш до остаточного розрахунку. |
real_win | number/null | Фактична сума виплати після розрахунку; до розрахунку - null. |
coef | number | Поточний чи підсумковий коефіцієнт купона. |
original_coef | number | Загальний коефіцієнт купона на момент створення. |
calculate_coef | number/null | Підсумковий розрахунковий коефіцієнт; до розрахунку - null. |
has_return | boolean | true, якщо у купоні є ставка зі статусом повернення. |
date | integer | Дата створення купона, Unix timestamp у мілісекундах. |
status | integer | Поточний статус купона. Значення описані у розділі «Статуси купона та ставок». |
asian | boolean | Ознака наявності азіатського розрахунку, включаючи половинний виграш чи програш. |
calculate_date | integer/null | Дата розрахунку купона у мілісекундах; до розрахунку - null. |
coupon_type | integer | Тип купона: 1 - ординар, 2 - експрес. |
events_count | integer | Кількість ставок усередині купона. |
events_data | array | Повний масив ставок, які входять у купон. |
Поля ставки
Кожен елемент events_data[] визначає конкретну прийняту ставку всередині купона.
| Поле | Тип | Значення |
|---|---|---|
id | integer/null | Внутрішній ID прийнятої ставки. Використовується разом із coupon_code для пошуку ставки всередині купона. |
game_id | integer | ID події або саб-події, на яку зроблено ставку. |
main_game_id | integer/null | ID основного матчу, до якого належить подія чи саб-подія. |
is_sub_game | boolean | true, якщо ставка стосується тайму, періоду, сету, кутової або іншої саб-події. |
parent_game_id | integer/null | ID безпосередньої батьківської події, якщо вона існує. |
sub_game_key | string/null | Технічний ключ саб-події чи періоду. |
raw_pointer | string | Вихідний вказівник ставки, прийнятий API. |
line_type | string | Тип лінії: line - прематч, live - подія в реальному часі. |
is_live | boolean | true, якщо ставка була створена по live-лінії. |
bet_group_id | integer | ID групи ставок чи ринку. |
bet_group_name | string/null | Локалізована назва групи ставок. |
bet_id | integer | ID вибраного результату всередині групи ставок. |
bet_name | string/null | Локалізована повна назва вибраного результату. |
sport_id | integer/null | ID виду спорту. |
sport_name | string/null | Локалізована назва виду спорту. |
tournament_id | integer/null | ID турніру. |
tournament | string/null | Локалізована назва турніру. |
event_date | integer/null | Дата початку події, Unix timestamp у мілісекундах. |
status | integer | Поточний статус обчислення ставки. Не плутайте зі статусом купона. |
opp1 | string/null | Назва першої команди чи учасника. |
opp2 | string/null | Назва другої команди чи учасника. |
coef | number | Коефіцієнт ставки, з яким її було прийнято. |
calc_coef | number/null | Розрахунковий множник ставки; до розрахунку - null. |
bet_score | string | Сумісне поле старого API, що містить вказівник ставки, а не рахунок матчу. |
calculate_date | integer/null | Дата розрахунку ставки у мілісекундах; до розрахунку - null. |
calculate_score | string/null | Рахунок, використаний для розрахунку ставки. |
settlement_reason_code | string/null | Стабільний машинний код причини розрахунку чи повернення; до розрахунку - null. |
settlement_reason | string/null | Пояснюючий текст причини розрахунку чи повернення; до розрахунку - null. |
placement_score_full | string/null | Загальний рахунок події на момент створення ставки, якщо доступний. |
placement_score_periods | string/null | Рахунок за періодами на момент створення ставки, якщо доступний. |
calculation_score_full | string/null | Загальний рахунок події на момент розрахунку ставки. |
calculation_score_periods | string/null | Рахунок за періодами на момент розрахунку ставки. |
timer | integer/null | Таймер події в момент збереження даних, якщо доступний. |
dop_name | string/null | Назва саб-події: тайму, періоду, сету, іннінгу тощо. |
rate | string | Параметр результату, наприклад, значення тотала або фори; для результату без параметра - "0". |
sgame_id | string/null | Зовнішній ключ подія. |
game_num | integer/null | Номер гри, якщо він наданий джерелом. |
stat_id | string/null | Зовнішній статистичний ID події. |
team1_id | integer/null | ID першої команди чи учасника. |
team2_id | integer/null | ID другої команди або учасника. |
opp_icon1 | integer/null | Сумісний ID іконки першої команди; збігається із team1_id. |
opp_icon2 | integer/null | Сумісний ID іконки другої команди; збігається із team2_id. |
Значення null є нормальним для даних, що ще не розраховані або недоступні. Не замінюйте його автоматично на 0 або порожній рядок.
Вважайте купон прийнятим тільки при code = 1 та наявності об’єктів у body.coupons. До цього кошик є попереднім вибором: результат міг зникнути, заблокуватися чи змінити коефіцієнт.
Після успіху:
- збережіть усі об’єкти
body.coupons, а не лише перший; - збережіть
coupon_codeрядком із провідними нулями; - збережіть потрібні дані із
events_data; - зіставте купон із кінцевим користувачем;
- зафіксуйте фінансову операцію користувача у системі партнера.
Ідентифікатори:
| Поле | Призначення |
|---|---|
coupon_code | Публічний код купона. |
events_data[].id | ID конкретної прийнятої ставки всередині купона. |
callback events_data[].uuid | Той самий ID ставки, переданий рядком. |
batchId | ID версії пакета callback, а не купона чи ставки. |
currency не повертається до повної моделі та callback. Якщо валюта потрібна, збережіть значення із запиту створення.
7. Помилки створення
| Код | Причина | Дія |
|---|---|---|
10 | Немає тіла запиту. | Виправити запит. |
11 | Неправильний покажчик. | Отримати актуальний покажчик із лінії. |
12 | Неправильний amount. | Передати позитивне число. |
501 | Коефіцієнт змінився. | Показати нове значення або змінити mode. |
502 | Вихід відсутній. | Видалити/оновити ставку у кошику. |
503 | Результат заблоковано. | Повідомити про тимчасову недоступність. |
504 | Помилка перевірки результату. | Не вважати купон прийнятим; повторити пізніше. |
506 | У експресі ставки одного матчу. | Залишити один результат або використовувати окремі ординари. |
507 | Недостатній баланс клієнта. | Поповнити баланс чи зменшити загальну суму. |
1002 | Неправильний набір параметрів. | Виправити параметри. |
10000 | Внутрішня помилка | Зафіксувати помилку та перевірити результат перед повтором. |
Для 501–504 новий 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/balance | body.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 |
23 | Push. | 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
}
]
}
]
}
Обов’язкові правила:
- обчислюйте
sha256=<hex(HMAC-SHA256(raw_body, callback_secret))>за точними вихідними байтами тіла до розбору JSON і порівнюйте підписи безпечним способом; - обробляйте всі елементи
coupons, пакет може містити до 100 купонів; - зберігайте
batchIdз унікальним індексом; - повторний
batchIdне повинен повторювати списання чи нарахування; - один
coupon_codeможе приходити з різнимиbatchIdпри прогресивному розрахунку та перерахунку; - повертайте 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, обмеження експресу та помилки501–507. - Враховано автоматичне списання клієнтського балансу.
- Збережено всі
coupon_codeта ID ставок. - Фінальна виплата береться із
real_win. - Callback перевіряється за вихідними байтами та дедуплікується за
batchId. - Настроєний резервний polling.
- баланс користувача відокремлений від клієнтського балансу SportAPI.
Детальна документація починається з огляду API. Повна карта endpoint знаходиться в довіднику.