API Интеграции Мерчанта
Обзор
Данный документ описывает API для интеграции мерчантов с платежной платформой Kotleta. API позволяет создавать платежные заявки (pay-in), получать обновления статусов через вебхуки, проверять статусы платежей и управлять аккаунтом.
Продуктивный сервер: https://kotleta.best
Тестовый сервер (Sandbox): https://deora2.tech
Авторизация
Получение доступов
Для начала интеграции необходимо:
- Запросить доступ к панели мерчанта у вашего менеджера.
- Создать магазин (если он не был создан для вас заранее).
- Получить API-ключ и Секретный ключ в настройках магазина.
Заголовки аутентификации
Все запросы к 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://kotleta.best/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://kotleta.best/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://kotleta.best/api/v1/payments'
body = json.dumps({'currency': 'RUB', 'amount': 5000})
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>
Host-to-Host интеграция
Host-to-Host интеграция обеспечивает прямой межсерверный обмен данными между бэкендом мерчанта и API платежной платформы, позволяя полностью автоматизировать обработку платежей.
Создание заявки на приём (Pay-In)
Процесс pay-in позволяет мерчантам принимать платежи от своих клиентов.
Общая схема
1. Сервер мерчанта -> POST /api/v1/payments -> Создание платежа, получение реквизитов
2. Мерчант -> Показывает реквизиты клиенту -> Клиент переводит средства
3. Платформа -> Обнаруживает перевод -> Подтверждает платеж
4. Платформа -> POST на callback мерчанта -> Уведомление о смене статуса
5. Мерчант -> GET /api/v1/payments/{id} -> (Опционально) Проверка финального статуса
Шаг 1: Создание платежа
Мерчант отправляет запрос на создание платежа. Система маршрутизирует платеж к доступному трейдеру, выбирает подходящие реквизиты (номер карты или телефон СБП) и возвращает их в ответе.
Запрос:
POST /api/v1/payments
Content-Type: application/json
X-API-Key: sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
X-Signature: <вычисленная_подпись>
{
"currency": "RUB",
"amount": 5000.00
}
Ответ (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— Перевод на банковскую карту (card_number + card_holder)sbp— Перевод через СБП (phone_number + bank_name)
Шаг 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
Создание платежа
Создает новую заявку на приём платежа и возвращает реквизиты для перевода.
Эндпоинт: POST /api/v1/payments
Аутентификация: API-ключ + Подпись
Заголовки запроса:
| Заголовок | Обязательный | Описание |
|---|---|---|
X-API-Key |
Да | API-ключ мерчанта |
X-Signature |
Да | Подпись запроса |
Content-Type |
Да | application/json |
Тело запроса:
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
currency |
string | Да | Код валюты, 3 символа (например, RUB, USD, EUR, THB) |
amount |
number | Да | Сумма платежа (минимум: 100) |
Пример запроса:
{
"currency": "RUB",
"amount": 5000.00
}
Ответ (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"
}
}
Ответы с ошибками:
| Код | Описание |
|---|---|
| 400 | Некорректное тело запроса, отсутствуют обязательные поля или не настроен callback URL |
| 401 | Неверный или отсутствующий API-ключ, или неверная подпись |
| 500 | Внутренняя ошибка сервера (нет доступных трейдеров/реквизитов) |
Получение платежа по ID
Возвращает текущий статус и детали платежа.
Эндпоинт: GET /api/v1/payments/{id}
Аутентификация: API-ключ + Подпись
Параметры 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 | Некорректный формат ID платежа |
| 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 мин) |
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 |
phone_number |
string | Номер телефона СБП (для типа sbp) |
card_number |
string | Номер банковской карты (для типа card) |
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-окружение по адресу https://deora2.tech. Тестовые API-ключи имеют префикс sk_test_.
Все процессы работают идентично продуктивной среде, но реальное движение средств не происходит.