API Интеграции Мерчанта
Обзор
Данный документ описывает API для интеграции мерчантов с платежной платформой Route. API позволяет создавать платежные заявки (pay-in), получать обновления статусов через вебхуки, проверять статусы платежей и управлять аккаунтом.
Базовый URL: https://route.black
Авторизация
Получение доступов
Для начала интеграции необходимо:
- Запросить доступ к панели мерчанта у вашего менеджера.
- Для вас будет создан аккаунт мерчанта. У каждого мерчанта может быть один или несколько магазинов.
- Учётные данные выдаются для каждого магазина отдельно, а не для мерчанта в целом. У каждого магазина свой API-ключ и Секретный ключ.
- Получите API-ключ (
sk_live_...) и Секретный ключ (64-символьная hex-строка) в настройках магазина. - Убедитесь, что для магазина настроена группа трафика — она определяет, какой пул трейдеров обрабатывает ваши платежи.
- Предоставьте вашему менеджеру статические публичные IP-адрес(а) сервера(-ов), которые будут обращаться к API и принимать колбэки, чтобы мы добавили их в список разрешённых адресов (см. раздел «Разрешённые IP-адреса» ниже).
Заголовки аутентификации
Все запросы к Merchant API должны содержать следующие заголовки:
| Заголовок | Описание |
|---|---|
X-API-Key |
Ваш API-ключ мерчанта (формат: sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) |
X-Signature |
Подпись запроса HMAC-SHA256 (см. ниже) |
Content-Type |
application/json для JSON-запросов |
Генерация подписи
Заголовок X-Signature представляет собой HMAC-SHA256 подпись, закодированную в Base64, вычисленную из конкатенации:
- HTTP-метод (GET, POST и т.д.)
- Полный URL запроса (включая query-параметры)
- Тело запроса (только для
application/jsonзапросов; пустая строка для GET-запросов)
Формула подписи:
X-Signature = Base64(HMAC-SHA256(secret_key, METHOD + URL + BODY))
Примеры кода
PHP:
<?php
$method = 'POST';
$url = 'https://route.black/api/v1/payments';
$body = json_encode(['currency' => 'RUB', 'amount' => 5000]);
$secretKey = 'your_secret_key';
$stringToSign = $method . $url . $body;
$signature = base64_encode(hash_hmac('sha256', $stringToSign, $secretKey, true));
// Установите заголовок: X-Signature: $signature
JavaScript (Node.js):
const crypto = require('crypto');
const method = 'POST';
const url = 'https://route.black/api/v1/payments';
const body = JSON.stringify({ currency: 'RUB', amount: 5000 });
const secretKey = 'your_secret_key';
const stringToSign = method + url + body;
const signature = crypto
.createHmac('sha256', secretKey)
.update(stringToSign)
.digest('base64');
// Установите заголовок: X-Signature: <signature>
Python:
import hmac
import hashlib
import base64
import json
method = 'POST'
url = 'https://route.black/api/v1/payments'
# Используйте separators=(',', ':') для компактного JSON — тело должно совпадать байт-в-байт с тем, что отправляется
body = json.dumps({'currency': 'RUB', 'amount': 5000}, separators=(',', ':'))
secret_key = 'your_secret_key'
string_to_sign = method + url + body
signature = base64.b64encode(
hmac.new(
secret_key.encode(),
string_to_sign.encode(),
hashlib.sha256
).digest()
).decode()
# Установите заголовок: X-Signature: <signature>
Важно: Подпись вычисляется по точным байтам тела запроса. Убедитесь, что JSON, который вы подписываете, и JSON, который вы отправляете, совпадают побайтово. Используйте компактную сериализацию (без лишних пробелов), чтобы избежать несовместимости между языками.
Формат ответа об ошибке
Все ошибки API возвращаются в едином формате:
{
"success": false,
"error": "<token>"
}
Поле error — стабильный snake_case токен, никогда не свободный английский/русский текст. Интеграторы мерчантов должны переключаться по этому токену для локализации сообщений или для ветвления retry/escalation-логики. HTTP-статус несёт класс (400 / 401 / 404 / 409 / 410 / 500), токен — точную причину.
Соглашения
-
Токены 4xx стабильны. Опубликованный здесь токен не меняет формат. Новые токены могут быть добавлены.
-
5xx маскируются. Любая внутренняя ошибка (БД недоступна, RabbitMQ упал, сбой провайдера и т.д.) возвращается одним обобщённым токеном:
HTTP 500 { "success": false, "error": "internal_error" }Оригинальная причина пишется в серверные логи. Любой ответ 5xx считайте временным сбоем и применяйте политику повтора.
-
Отсутствие capacity — НЕ ошибка, и причина никогда не раскрывается. Если платформа по любой причине не может выдать реквизит для корректного аутентифицированного запроса, возвращается HTTP 200 с пустым
data:HTTP 200 { "success": true, "data": null }Мерчанту не сообщается о причине. В этот класс входят (но не ограничиваются): нет подходящего трейдера, нет доступного реквизита, недостаточный USDT-баланс у трейдера, блокировка на уровне магазина, лимит одновременных сделок, превышен per-requisite лимит, магазин не добавлен в группу маршрутизации, каскад исчерпан, ошибка интеграции провайдера. Все эти случаи сворачиваются в один и тот же пустой 200-ответ.
Мерчант должен воспринимать пустой 200 как временный сигнал «сейчас нельзя»: повторить с backoff или предложить клиенту альтернативный способ оплаты. Реальная причина пишется в pre-deal-error лог на сервере для админ-диагностики — никогда в ответе.
Канонический список токенов
| Статус | Токен | Когда |
|---|---|---|
| 400 | currency_mismatch |
currency в запросе не совпадает с разрешённой валютой магазина |
| 400 | amount_below_minimum |
amount < min_amount_in магазина |
| 400 | amount_above_maximum |
amount > max_amount_in магазина |
| 400 | duplicate_external_id |
external_id уже использован этим мерчантом (когда у магазина allow_duplicate_invoices=false) |
| 400 | callback_url_required |
В запросе нет callback_url и в настройках магазина тоже не задан |
| 401 | unauthorized |
Отсутствует/неверный X-API-Key или X-Signature |
| 404 | payment_not_found |
GET /api/v1/payments/{id} для несуществующего ID или ID, не принадлежащего вызывающему |
| 409 | payment_not_pending |
Операция требует статуса waiting_sms/created, но платёж уже confirmed/failed/expired |
| 410 | payment_expired |
Прошло expires_at платежа (RFC 7231 §6.5.9 Gone) |
| 500 | internal_error |
Маскированная внутренняя ошибка сервера |
Чего в таблице НЕТ. Условия, связанные с маршрутизацией («нет трейдера», «магазин не настроен», «низкий баланс», «нет каскадной группы» и т.д.) сознательно отсутствуют. Мерчант их никогда не видит как 4xx — они все сворачиваются в один и тот же пустой
200 OK. См. пункт о no-capacity выше.
Host-to-Host интеграция
Host-to-Host интеграция обеспечивает прямой межсерверный обмен данными между бэкендом мерчанта и API платежной платформы, позволяя полностью автоматизировать обработку платежей.
Разрешённые IP-адреса
В целях безопасности доступ к API мерчанта ограничен утверждённым списком исходящих IP-адресов. Перед запуском в бой предоставьте вашему менеджеру статические публичные IP-адреса или CIDR-диапазоны всех серверов, которые будут:
- отправлять запросы к платформе (приём, выплаты и запросы статуса), и
- принимать колбэки (вебхуки) на вашем эндпоинте.
Запросы с IP-адресов, которых нет в списке разрешённых, могут быть отклонены ещё до того, как достигнут API. Если ваша инфраструктура масштабируется или ваши исходящие IP-адреса меняются, сообщите нам об этом заранее, чтобы мы обновили список и избежали перебоев в вашей интеграции.
Приём колбэков: колбэки платформы отправляются с фиксированного набора исходящих IP-адресов. Если ваш эндпоинт для колбэков находится за фаерволом, запросите у вашего менеджера актуальные диапазоны наших исходящих IP-адресов и разрешите их на своей стороне.
Создание заявки на приём (Pay-In)
Процесс pay-in позволяет мерчантам принимать платежи от своих клиентов.
Общая схема
1. Сервер мерчанта -> POST /api/v1/payments -> Создание платежа, получение реквизитов
2. Мерчант -> Показывает реквизиты клиенту -> Клиент переводит средства
3. Платформа -> Обнаруживает перевод -> Подтверждает платеж
4. Платформа -> POST на callback мерчанта -> Уведомление о смене статуса
5. Мерчант -> GET /api/v1/payments/{id} -> (Опционально) Проверка финального статуса
Шаг 1: Создание платежа
Мерчант отправляет запрос на создание платежа. Система маршрутизирует платеж к доступному трейдеру, выбирает подходящие реквизиты (номер карты или телефон СБП) и возвращает их в ответе.
Важно — три класса ответа:
201 Created+ заполненноеdata— реквизиты выданы, покажите их клиенту.200 OK+data: null— платформа сейчас не может выдать реквизиты. Причина никогда не раскрывается: нет трейдера, нет реквизита, проблемы с балансом, блокировка магазина, дыра в каскаде, ошибка провайдера — всё сводится к одному и тому же пустому ответу. Повторите с backoff или предложите клиенту альтернативный метод.4xx+{ "error": "<token>" }— отказ из-за самого запроса, исправимый вызывающей стороной (битая валюта, сумма вне диапазона магазина, дубликатexternal_id, отсутствиеcallback_urlи т.д.). См. Формат ответа об ошибке.Всё остальное (
5xx) — временный сбой платформы — тело маскируется вinternal_error, повторите запрос.
Запрос:
POST /api/v1/payments
Content-Type: application/json
X-API-Key: sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
X-Signature: <вычисленная_подпись>
{
"currency": "RUB",
"amount": 5000.00,
"external_id": "order-12345",
"callback_url": "https://merchant.example.com/webhooks/payments",
"payment_method": "sbp"
}
Обязательны
currency,amountиpayment_method. Поляexternal_idиcallback_urlопциональны (см. таблицу тела запроса в разделе Создание платежа).
Ответ (201 Created):
{
"success": true,
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "waiting_sms",
"currency": "RUB",
"amount": 5000.00,
"amount_usdt": 52.63,
"external_id": "ext-unique-id",
"requisite": {
"type": "card",
"card_number": "2200 1234 5678 9012",
"card_holder": "IVAN IVANOV",
"bank_name": "Sberbank",
"bank_code": "sberbank",
"timer_seconds": 900
},
"expires_at": "2026-02-15T15:15:00Z",
"created_at": "2026-02-15T15:00:00Z"
}
}
Мерчант должен отобразить полученные реквизиты клиенту и указать точную сумму для перевода. Платеж истекает по прошествии timer_seconds (по умолчанию 15 минут).
Возможные типы реквизитов:
card— Перевод на банковскую карту / C2C (card_number + card_holder)sbp— Перевод через СБП (phone_number + bank_name)transgran— Трансгран, перевод на зарубежную карту (card_number + card_holder)
Шаг 2: Подтверждение платежа
После того как клиент выполнит перевод, платформа автоматически обнаруживает входящий платеж. Ручное подтверждение со стороны мерчанта не требуется — система обрабатывает обнаружение автоматически через свою внутреннюю сеть.
Шаг 3: Уведомление через вебхук
При подтверждении платежа платформа отправляет вебхук на настроенный callback_url мерчанта. Подробности в разделе Обратные вызовы (Вебхуки).
Создание заявки на выплату (Pay-Out)
Примечание: Функциональность выплат находится в разработке. Обратитесь к вашему менеджеру для уточнения сроков и раннего доступа.
Процесс pay-out позволит мерчантам отправлять средства на банковские счета или карты клиентов.
Обратные вызовы (Вебхуки)
Обзор
Платформа отправляет HTTP POST-уведомления на callback_url мерчанта при каждом изменении статуса платежа. URL для обратных вызовов настраивается в профиле мерчанта (не для каждого запроса отдельно).
Аутентификация
Каждый запрос вебхука содержит заголовок X-Signature, вычисленный с использованием секретного ключа мерчанта:
X-Signature = Base64(HMAC-SHA256(secret_key, "POST" + webhook_url + body))
Мерчант обязан проверять эту подпись, чтобы убедиться в подлинности вебхука и отсутствии подмены данных.
Формат данных вебхука
{
"payment_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"external_id": "ext-unique-id",
"status": "confirmed",
"currency": "RUB",
"amount": 5000.00,
"amount_usdt": 52.63,
"tx_id": "",
"confirmed_at": "2026-02-15T15:05:30Z",
"timestamp": "2026-02-15T15:05:31Z"
}
Описание полей вебхука
| Поле | Тип | Описание |
|---|---|---|
payment_id |
string (UUID) | Уникальный идентификатор платежа в системе |
external_id |
string | Внешний идентификатор |
status |
string | Новый статус платежа (см. PaymentStatus) |
currency |
string | Валюта платежа (например, RUB) |
amount |
number | Сумма платежа в исходной валюте |
amount_usdt |
number | Сумма платежа в пересчёте на USDT |
tx_id |
string | ID транзакции в блокчейне (при завершении) |
confirmed_at |
string (ISO 8601) | Временная метка подтверждения |
timestamp |
string (ISO 8601) | Временная метка генерации вебхука |
Ожидаемый ответ
Мерчант должен ответить HTTP-кодом 200 OK. Любой другой код считается ошибкой, и вебхук будет повторно отправлен.
Политика повторных попыток
Если сервер мерчанта не ответил кодом 200, платформа повторяет отправку с экспоненциальной задержкой:
| Попытка | Задержка |
|---|---|
| 1 | 5 минут |
| 2 | 15 минут |
| 3 | 1 час |
| 4 | 6 часов |
| 5-10 | 24 часа |
Максимум 10 попыток. После исчерпания лимита вебхук помечается как неудачный и может быть повторно отправлен вручную через панель управления или API.
Пример проверки подписи
PHP:
<?php
$secretKey = 'your_secret_key';
$webhookUrl = 'https://yoursite.com/webhook';
$body = file_get_contents('php://input');
$receivedSignature = $_SERVER['HTTP_X_SIGNATURE'];
$stringToSign = 'POST' . $webhookUrl . $body;
$expectedSignature = base64_encode(
hash_hmac('sha256', $stringToSign, $secretKey, true)
);
if (!hash_equals($expectedSignature, $receivedSignature)) {
http_response_code(403);
exit('Invalid signature');
}
// Обработка вебхука...
http_response_code(200);
Python:
import hmac
import hashlib
import base64
secret_key = 'your_secret_key'
webhook_url = 'https://yoursite.com/webhook'
body = request.get_data(as_text=True)
received_signature = request.headers.get('X-Signature')
string_to_sign = 'POST' + webhook_url + body
expected_signature = base64.b64encode(
hmac.new(
secret_key.encode(),
string_to_sign.encode(),
hashlib.sha256
).digest()
).decode()
if not hmac.compare_digest(expected_signature, received_signature):
return 'Invalid signature', 403
# Обработка вебхука...
return 'OK', 200
Споры (апелляции)
Спор (апелляция) открывается, когда клиент утверждает, что выполнил перевод, но платёж не был ему зачтён — например, оплата пришла после истечения срока инвойса или на реквизит, который система автоматически не сопоставила.
Важно: у мерчанта нет отдельного API для споров. Приём апелляции и её разрешение полностью на стороне платформы — мерчант наблюдает только итог.
Как это работает
- Приём. Клиент инициирует апелляцию через поддержку платформы, указывая сумму, реквизит (последние 4 цифры карты или номер телефона), время оплаты и при необходимости подтверждающий документ (чек/скриншот).
- Сопоставление. Платформа ищет соответствующий платёж по реквизиту, точной сумме и времени (±2 часа). Если найден ровно один — платёж переводится в статус
dispute, и апелляция привязывается к нему. - Модерация. Оператор платформы изучает доказательства и принимает решение.
Итог и влияние на мерчанта
| Решение | Что происходит с платежом | Уведомление мерчанту |
|---|---|---|
| Одобрено | Платёж рассчитывается и переходит в confirmed |
Стандартный вебхук со статусом confirmed — в том числе для платежа, который ранее был помечен expired |
| Отклонено | Платёж возвращается в expired |
Дополнительного вебхука нет |
Важно для интеграции — позднее подтверждение. Из-за апелляций платёж, который вы уже получили как
expired, может позже прийти какconfirmed. Не считайтеexpiredбезусловно окончательным: обрабатывайте вебхукconfirmedидемпотентно, даже если он приходит послеexpired, и сверяйте поpayment_id/external_id.
Сам переход в статус dispute отдельным вебхуком не уведомляется — его можно увидеть, опросив GET /api/v1/payments/{id}.
Справочник API
Создание платежа
Создает новую заявку на приём платежа и возвращает реквизиты для перевода.
Эндпоинт: POST /api/v1/payments
Аутентификация: API-ключ + Подпись
Заголовки запроса:
| Заголовок | Обязательный | Описание |
|---|---|---|
X-API-Key |
Да | API-ключ мерчанта |
X-Signature |
Да | Подпись запроса |
Content-Type |
Да | application/json |
Тело запроса:
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
currency |
string | Да | Код валюты, 3 символа (например, RUB, KZT, USD, EUR) |
amount |
number | Да | Сумма платежа (минимум: 100) |
external_id |
string | Нет | Ваш идентификатор заказа/счёта для сверки. Если не передан — генерируется UUID автоматически. Должен быть уникальным для каждого мерчанта. |
callback_url |
string | Нет | URL для получения уведомлений о статусе данного платежа. Переопределяет callback_url из профиля мерчанта. |
payment_method |
string | Да | Способ оплаты — определяет роутинг (группу трафика). Одно из: card (C2C), sbp (СБП), transgran (зарубежные карты). |
shop_id |
string (UUID) | Нет | Целевой магазин. Не обязателен: если не передан, система сама подберёт магазин мерчанта по currency (+ payment_method). Передавайте shop_id (см. GET /api/v1/shops), только если под запрос подходит несколько магазинов — иначе вернётся shop_ambiguous. Должен принадлежать вашему мерчанту, иначе shop_not_owned. |
customer_id |
string | Да | Стабильный идентификатор вашего клиента (плательщика), одинаковый для всех его пополнений. Используется антифродом для истории по пользователю и блокировок. Если не передан — customer_id is required. Если пользователь заблокирован у вас — создание вернёт user_blocked. |
customer_phone |
string | Нет | Телефон плательщика (опц.). |
customer_email |
string | Нет | Email плательщика (опц.). |
device_id |
string | Нет | Идентификатор устройства плательщика (опц.). |
Пример запроса:
{
"currency": "RUB",
"amount": 5000.00,
"external_id": "order-12345",
"callback_url": "https://merchant.example.com/webhooks/payments",
"payment_method": "sbp"
}
Ответ (201 Created):
{
"success": true,
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "waiting_sms",
"currency": "RUB",
"amount": 5000.00,
"amount_usdt": 52.63,
"external_id": "generated-uuid",
"requisite": {
"type": "card",
"card_number": "2200 1234 5678 9012",
"card_holder": "IVAN IVANOV",
"bank_name": "Sberbank",
"bank_code": "sberbank",
"timer_seconds": 900
},
"expires_at": "2026-02-15T15:15:00Z",
"created_at": "2026-02-15T15:00:00Z"
}
}
Ответы с ошибками:
Тело ответа: {"success": false, "error": "<token>"} — см. Формат ответа об ошибке. Наиболее релевантные токены для этого endpoint'а:
| Статус | Токен | Условие |
|---|---|---|
| 400 | currency_mismatch |
currency не совпадает с разрешённой валютой магазина |
| 400 | amount_below_minimum |
amount < min_amount_in магазина |
| 400 | amount_above_maximum |
amount > max_amount_in магазина |
| 400 | duplicate_external_id |
external_id уже использован этим мерчантом |
| 400 | callback_url_required |
В запросе нет callback_url и в магазине тоже не задан |
| 400 | shop_ambiguous |
shop_id не передан, но под currency+payment_method подходит несколько магазинов — укажите shop_id |
| 400 | invalid_shop_id |
shop_id имеет неверный формат или магазин не найден |
| 400 | shop_not_owned |
Указанный shop_id не принадлежит вашему мерчанту |
| 400 | shop_id_conflict |
Ключ привязан к магазину, а в теле передан другой shop_id |
| 401 | unauthorized |
Отсутствует/неверный X-API-Key или X-Signature |
| 500 | internal_error |
Временный серверный сбой — повторите |
No-capacity — не ошибка, причина не раскрывается. Если платформа не может выдать реквизит по любой причине (нет трейдера, нет реквизита, баланс, блок магазина, дыра в каскаде, ошибка провайдера, …) — ответ HTTP 200 с
data: null. Список 4xx токенов выше ограничен синтаксическими / исправимыми ошибками. См. Формат ответа об ошибке.
Получение списка магазинов
Возвращает магазины вашего мерчанта. Используйте, чтобы узнать shop_id для поля shop_id в создании платежа.
Эндпоинт: GET /api/v1/shops
Аутентификация: API-ключ (X-API-Key) — заголовок X-Signature для этого GET-запроса не требуется. Подходит как единый ключ мерчанта, так и ключ, привязанный к магазину (в обоих случаях возвращаются все магазины мерчанта).
Ответ (200 OK):
{
"success": true,
"data": [
{
"shop_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "My Shop",
"currency": "RUB",
"methods": ["sbp"],
"payment_types": ["card", "sbp"],
"active": true
}
]
}
| Поле | Описание |
|---|---|
shop_id |
UUID магазина — подставляется в тело POST /api/v1/payments |
name |
Название магазина |
currency |
Валюта магазина (может быть пустой, если не задана) |
methods |
Разрешённые методы приёма (например sbp, card) |
payment_types |
Разрешённые типы оплаты |
active |
true, если магазин активен и приём не заблокирован |
Ответы с ошибками:
| Статус | Токен | Условие |
|---|---|---|
| 401 | unauthorized |
Отсутствует/неверный X-API-Key |
| 500 | internal_error |
Временный серверный сбой — повторите |
Получение платежа по ID
Возвращает текущий статус и детали платежа.
Эндпоинт: GET /api/v1/payments/{id}
Аутентификация: API-ключ (X-API-Key) или JWT Bearer Token — заголовок X-Signature для GET-запросов не требуется
Параметры URL:
| Параметр | Тип | Описание |
|---|---|---|
id |
string (UUID) | Идентификатор платежа |
Ответ (200 OK):
{
"success": true,
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "confirmed",
"currency": "RUB",
"amount": 5000.00,
"amount_usdt": 52.63,
"external_id": "generated-uuid",
"created_at": "2026-02-15T15:00:00Z",
"updated_at": "2026-02-15T15:05:30Z"
}
}
Ответы с ошибками:
| Статус | Токен | Условие |
|---|---|---|
| 400 | invalid_id |
Path-параметр не является валидным UUID |
| 401 | unauthorized |
Отсутствует/неверный X-API-Key |
| 404 | payment_not_found |
Платежа с таким ID/external_id у этого мерчанта нет |
| 500 | internal_error |
Временный серверный сбой — повторите |
| 404 | Платеж не найден |
Получение платежей мерчанта
Возвращает постраничный список платежей мерчанта.
Эндпоинт: GET /api/v1/merchants/{merchant_id}/payments
Аутентификация: JWT Bearer Token
Параметры URL:
| Параметр | Тип | Описание |
|---|---|---|
merchant_id |
string (UUID) | Идентификатор мерчанта |
Query-параметры:
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
page |
integer | 1 | Номер страницы |
page_size |
integer | 20 | Элементов на странице (максимум: 100) |
Ответ (200 OK):
{
"success": true,
"data": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "confirmed",
"currency": "RUB",
"amount": 5000.00,
"amount_usdt": 52.63,
"external_id": "generated-uuid",
"created_at": "2026-02-15T15:00:00Z"
}
],
"pagination": {
"total": 150,
"page": 1,
"page_size": 20,
"total_pages": 8
}
}
Управление вебхуками
Эндпоинты для мониторинга и управления доставкой вебхуков.
Аутентификация: JWT Bearer Token
Статистика вебхуков
Эндпоинт: GET /api/v1/merchant/webhooks/stats
Ответ:
{
"success": true,
"data": {
"pending": 2,
"processing": 0,
"completed": 145,
"failed": 3
}
}
Список неудачных вебхуков
Эндпоинт: GET /api/v1/merchant/webhooks/failed
Повторная отправка вебхука
Эндпоинт: POST /api/v1/merchant/webhooks/{id}/retry
Детали вебхука
Эндпоинт: GET /api/v1/merchant/webhooks/{id}
Описание объектов API
PaymentStatus
| Статус | Описание |
|---|---|
created |
Платеж создан, идёт назначение трейдера |
waiting_sms |
Реквизиты назначены, ожидание перевода от клиента |
confirmed |
Платеж подтверждён — средства получены и проверены |
completed |
Платеж полностью завершён — расчёт произведён |
failed |
Платеж не удался на любом этапе обработки |
expired |
Платеж не завершён в установленный срок (по умолчанию: 15 мин) |
dispute |
По платежу открыт спор (апелляция) — идёт проверка. См. Споры (апелляции) |
PaymentResponse
| Поле | Тип | Описание |
|---|---|---|
id |
string (UUID) | Уникальный идентификатор платежа |
status |
PaymentStatus | Текущий статус платежа |
currency |
string | Код валюты платежа (например, RUB) |
amount |
number | Сумма платежа в исходной валюте |
amount_usdt |
number | Сумма платежа в пересчёте на USDT |
external_id |
string | Внешний идентификатор |
requisite |
RequisiteDTO | Реквизиты для перевода (при статусе waiting_sms) |
expires_at |
string (ISO 8601) | Время истечения платежа |
created_at |
string (ISO 8601) | Время создания платежа |
RequisiteDTO
| Поле | Тип | Описание |
|---|---|---|
type |
string | Тип реквизитов: card, sbp или transgran |
phone_number |
string | Номер телефона СБП (для типа sbp) |
card_number |
string | Номер банковской карты (для типа card / transgran) |
card_holder |
string | Имя держателя карты (для типа card) |
bank_name |
string | Название банка |
bank_code |
string | Код банка |
timer_seconds |
integer | Время в секундах до истечения платежа |
WebhookPayload
| Поле | Тип | Описание |
|---|---|---|
payment_id |
string (UUID) | Идентификатор платежа |
external_id |
string | Внешний идентификатор |
status |
PaymentStatus | Обновлённый статус платежа |
currency |
string | Валюта платежа |
amount |
number | Сумма в исходной валюте |
amount_usdt |
number | Сумма в USDT |
tx_id |
string | Хеш транзакции в блокчейне (при завершении) |
confirmed_at |
string (ISO 8601) | Время подтверждения |
timestamp |
string (ISO 8601) | Время генерации вебхука |
Обработка ошибок
Формат ответа
Все ответы с ошибками имеют единый формат:
{
"success": false,
"error": "Описание ошибки"
}
HTTP-коды статуса
| Код | Описание |
|---|---|
| 200 | Успех |
| 201 | Успешно создано |
| 400 | Некорректный запрос — неверные параметры или нарушение бизнес-логики |
| 401 | Не авторизован — неверный или отсутствующий API-ключ / подпись |
| 404 | Не найдено — запрошенный ресурс не существует |
| 409 | Конфликт — дублирующий запрос (идемпотентность) |
| 500 | Внутренняя ошибка сервера |
Типичные сообщения об ошибках
| Ошибка | Причина |
|---|---|
Invalid request body |
Некорректный JSON или отсутствуют обязательные поля |
currency must be 3 characters |
Код валюты не в формате ISO 4217 |
Merchant not authenticated |
Отсутствующий или неверный заголовок X-API-Key |
Invalid signature |
X-Signature не совпадает с вычисленным значением |
Merchant has no callback URL configured |
В профиле мерчанта не указан callback_url |
Payment not found or already processed |
Платеж не найден или находится в терминальном статусе |
Payment is not waiting for SMS confirmation |
Платеж в неожиданном статусе |
Поддерживаемые валюты
| Код | Валюта |
|---|---|
| RUB | Российский рубль |
| USD | Доллар США |
| EUR | Евро |
| THB | Тайский бат |
Примечание: Доступные валюты зависят от конфигурации трафик-группы мерчанта. Обратитесь к вашему менеджеру для активации.
Лимиты запросов
API-запросы ограничены по частоте для каждого мерчанта. Лимиты по умолчанию:
| Эндпоинт | Лимит |
|---|---|
POST /payments |
60 запросов/минута |
GET /payments/* |
120 запросов/минута |
При превышении лимитов возвращается HTTP 429 (Too Many Requests).
Тестирование и Sandbox
Для тестирования интеграции используйте sandbox-окружение, предоставленное вашим менеджером. Тестовые API-ключи имеют префикс sk_test_.
Все процессы работают идентично продуктивной среде, но реальное движение средств не происходит.