Формат ответа API
Методы нового клиентского API используют общую JSON-оболочку.
Ключевое правило:
HTTP
200подтверждает обработку HTTP-запроса, но не всегда означает успешную бизнес-операцию. Всегда проверяйте полеcode.
Успешный ответ
{
"code": 1,
"body": {},
"error_code": null,
"error_message": null,
"date": 1784970000000,
"time_ms": 12,
"path": "/api/partner/coupons/get"
}
Бизнес-ошибка
{
"code": 0,
"body": null,
"error_code": 471,
"error_message": "Coupon not found",
"date": 1784970000000,
"time_ms": 5,
"path": "/api/partner/coupons/get"
}
Бизнес-ошибка обычно также возвращается с HTTP 200.
Поля оболочки
| Поле | Тип | Описание |
|---|---|---|
code | integer | Результат бизнес-операции: 1 — успех, 0 — ошибка. |
body | any/null | Результат операции либо дополнительные сведения. Структура зависит от endpoint. |
error_code | integer/null | Машиночитаемый код бизнес-ошибки. При успехе обычно null. |
error_message | string/null | Текстовое описание ошибки. При успехе обычно null. |
date | integer | Время формирования ответа, Unix-миллисекунды. |
time_ms | integer | Время обработки запроса сервером в миллисекундах. |
path | string | Путь метода, который обработал запрос. |
code и error_code
Эти поля имеют разное назначение:
code → успешна ли бизнес-операция
error_code → почему операция завершилась ошибкой
Пример:
{
"code": 0,
"error_code": 503,
"error_message": "Bet outcome is blocked"
}
Здесь:
- HTTP API доступен;
- запрос обработан;
- купон не создан;
- причина — заблокированный исход.
В программной логике используйте error_code. Текст error_message предназначен для диагностики и может уточняться, поэтому не сравнивайте его как стабильный идентификатор ошибки.
Форма body зависит от метода
body не имеет одного типа для всего API.
| Метод | Тип body | Где находятся данные |
|---|---|---|
GET /api/partner/health | string | Непосредственно в body. |
POST /api/partner/login | object | Токен в body.token. |
POST /api/partner/coupons/place | object | Купоны в body.coupons[]. |
GET /api/partner/coupons/get | object | Один купон непосредственно в body. |
POST /api/partner/coupons/results | object | body.query_type и body.coupons[]. |
GET /api/partner/coupons/calculated | array | Купоны непосредственно в body[]. |
GET /api/partner/coupons/active | array | Купоны непосредственно в body[]. |
GET /api/partner/balance | object | Баланс в body.balance. |
Не используйте один универсальный путь вроде body.coupons[0] для всех endpoint.
Создание купона
{
"code": 1,
"body": {
"coupons": [
{
"coupon_code": "000000000272"
}
]
}
}
Получение одного купона
{
"code": 1,
"body": {
"coupon_code": "000000000272"
}
}
Активные или рассчитанные купоны
{
"code": 1,
"body": [
{
"coupon_code": "000000000272"
}
]
}
Пустой успешный результат
Пустой массив не является ошибкой:
{
"code": 1,
"body": [],
"error_code": null,
"error_message": null
}
Такой ответ возможен, например, если:
- активных купонов нет;
- в выбранном окне нет рассчитанных купонов;
- ни один из переданных кодов не найден в доступных данных.
Для /coupons/results пустой массив находится внутри объекта:
{
"code": 1,
"body": {
"query_type": "ids",
"coupons": []
}
}
body при бизнес-ошибке
При ошибке body может быть:
null;- объектом с дополнительными сведениями;
- массивом в старом совместимом контракте.
Например, при изменении коэффициента новый API возвращает причины в body.changes:
{
"code": 0,
"body": {
"changes": [
{
"game_id": 737779544,
"bet_coefficient": 2.19,
"actual_coefficient": 2.09,
"change_type": 2,
"status": "rejected"
}
]
},
"error_code": 501,
"error_message": "Coefficient is change",
"date": 1784970000000,
"time_ms": 20,
"path": "/api/partner/coupons/place"
}
Поэтому при code = 0 сначала прочитайте error_code, затем обработайте структуру body, описанную для этой ошибки.
HTTP-статус и бизнес-результат
| HTTP-результат | Значение | Действие клиента |
|---|---|---|
2xx, code = 1 | Операция выполнена. | Обработать данные из body. |
2xx, code = 0 | Бизнес-ошибка. | Прочитать error_code, error_message и дополнительные данные. |
400 | Неверный JSON или формат параметров. | Исправить запрос. |
401 | JWT отсутствует, неверен, истек или отозван. | Выполнить вход повторно и использовать новый JWT. |
403 | Токен не имеет нужной роли или доступ запрещен. | Проверить тип токена и состояние аккаунта. |
5xx | Серверная или временная ошибка. | Зафиксировать ошибку и применить безопасную стратегию повтора. |
Для бизнес-ошибки проверка только HTTP-статуса приведет к неверному результату:
HTTP 200 + code 0 ≠ успех
Рекомендуемый алгоритм клиента
1. Выполнить HTTP-запрос.
2. Проверить транспортный результат.
3. Если HTTP 401 — получить новый JWT.
4. Если HTTP 403 — проверить доступ.
5. Если HTTP 5xx — применить стратегию временной ошибки.
6. Для JSON-ответа проверить code.
7. Если code = 0 — обработать error_code.
8. Если code = 1 — разобрать body по контракту конкретного endpoint.
Псевдокод:
response = send_request()
if response.status == 401:
refresh_login()
stop
if response.status == 403:
report_access_error()
stop
if response.status >= 500:
handle_server_error()
stop
payload = parse_json(response.body)
if payload.code != 1:
handle_business_error(payload.error_code, payload.body)
stop
handle_success(payload.body)
Повтор запросов
Стратегия повтора зависит от операции.
Методы чтения можно безопасно повторять после временной сетевой или серверной ошибки:
/coupons/get;/coupons/results;/coupons/calculated;/coupons/active;/balance.
Не повторяйте автоматически POST /api/partner/coupons/place после неопределенной сетевой или серверной ошибки, пока не исключена возможность, что первый запрос был обработан. Иначе один выбор пользователя может создать несколько купонов.
Бизнес-ошибки создания 501–504 являются результатом проверки исхода, а не транспортной ошибкой. Их нельзя обрабатывать как обычный автоматический повтор неизмененного запроса.
Диагностические поля
date
date на верхнем уровне — время формирования ответа:
{
"date": 1784970000000
}
Это Unix timestamp в миллисекундах.
Не путайте его с:
body.date— временем создания купона;event_date— временем начала события;calculate_date— временем расчета.
time_ms
{
"time_ms": 12
}
Показывает время обработки запроса сервером в миллисекундах. Поле полезно для мониторинга, но не включает всю сетевую задержку на стороне партнера.
path
{
"path": "/api/partner/coupons/get"
}
Помогает определить, какой маршрут сформировал ответ. Не используйте path как бизнес-идентификатор купона или операции.
Даты и null
Даты API передаются в Unix-миллисекундах:
{
"date": 1784970000000,
"calculate_date": null
}
До расчета calculate_date всегда равен null. Значение 0 для нерассчитанного купона или ставки не используется.
Не заменяйте null числом 0: эти значения имеют разный смысл.
Десятичные числа
Суммы, коэффициенты и выплаты передаются как JSON-числа без фиксированного количества знаков после запятой:
{
"amount": 10,
"coef": 1.5,
"real_win": 15
}
Интеграция не должна зависеть от текстового количества знаков:
10 = 10.0 = 10.00
Партнер самостоятельно определяет правила отображения и округления. Для хранения денег рекомендуется десятичный тип данных.
Необязательные и отсутствующие поля
В зависимости от endpoint и результата отдельные необязательные поля оболочки могут быть null или отсутствовать.
Клиент должен:
- проверять наличие необязательного поля;
- корректно обрабатывать
null; - не подменять отсутствующее поле произвольным значением;
- не считать пустой массив ошибкой;
- не зависеть от порядка JSON-полей.
Формат старого API
Старые маршруты используют прежнюю оболочку из пяти полей:
{
"code": 1,
"body": {},
"error_code": null,
"error_message": null,
"date": 1784970000000
}
В ней отсутствуют:
time_ms;path.
Для старого защищенного маршрута неверный JWT может возвращаться как бизнес-ошибка с HTTP 200:
{
"code": 0,
"body": false,
"error_code": 1003,
"error_message": "Wrong token",
"date": 1784970000000
}
Не применяйте обработчик старой структуры к новому API без учета дополнительных полей и нового поведения HTTP 401/403.
Подробнее:
Callback использует другой контракт
Входящий callback не оборачивается в code, body, error_code и другие поля клиентского API.
Payload callback начинается с:
{
"event": "coupons.settled",
"batchId": "...",
"couponCount": 1,
"coupons": []
}
Ответ партнера на callback также имеет отдельный контракт:
{
"success": true,
"processed": 1
}
Не используйте общую оболочку клиентского API для обработки callback.
Подробнее: «Callback результатов».
Контрольный список
- Сначала проверяется HTTP-статус.
- Затем проверяется
code. - При
code = 0читаетсяerror_code. error_messageне используется как программный идентификатор.- Форма
bodyопределяется по endpoint. - Пустой массив при
code = 1считается успехом. dateчитается как Unix-миллисекунды.time_msиспользуется только для диагностики.calculate_dateдо расчета равенnull, а не0.- Десятичные значения не зависят от количества знаков.
- Создание купона не повторяется вслепую.
- Callback обрабатывается по отдельному контракту.
Следующий раздел: «Коды ошибок».