Обратный вызов (Callbacks / Webhooks)
Получение и проверка подлинности серверных уведомлений о статусах платежей и выплат в Syncra V2
Серверные уведомления (Callbacks / Webhooks)
Для информирования вашей системы о смене статусов транзакций (например, об успешном завершении оплаты клиентом или о завершении перевода выплаты трейдером) шлюз Syncra V2 отправляет асинхронные HTTP POST-запросы на указанный вами адрес обратного вызова (Callback URL).
Формат уведомления V2
Тело уведомления передается в формате JSON и содержит подробную информацию о событии и сделке:
{
"event": "deal.completed",
"deal_id": "7ac148fe-19a3-45bb-b992-019fac55b721",
"merchant_id": "8f870a31-b88d-4cb0-a882-628d08cbda88",
"tenant_id": "550e8400-e29b-41d4-a716-446655440000",
"amount": 250050,
"currency": "RUB",
"status": "COMPLETED",
"timestamp": "2026-07-12T17:24:12Z"
}Типы событий (event)
| Имя события | Описание события |
|---|---|
deal.completed | Успешное завершение входящего платежа (PayIn) или выплаты (PayOut). |
deal.failed | Ошибка проведения платежа или выплаты (переход в финальный неуспешный статус). |
dispute.created | По транзакции мерчанта был открыт спор (диспут). |
dispute.resolved | Спор по транзакции был успешно урегулирован. |
withdrawal.completed | Заявка на криптографический вывод средств (USDT) выполнена в блокчейне. |
Типы уведомлений в адаптере (V1 Compatibility)
Если вы используете legacy-интеграцию V1 через Compatibility Adapter, формат уведомлений будет соответствовать спецификации V1:
{
"failures": [],
"value": {
"type": 1,
"paymentId": "7ac148fe-19a3-45bb-b992-019fac55b721",
"status": 11,
"amount": "2500.50",
"currency": 643,
"salt": 4729103
},
"isSuccess": true,
"isFailure": false
}Маппинг типов уведомлений V1 (type)
1— Входящий платеж (PayIn Callback)2— Исходящий платеж (PayOut Callback)10— Криптографический вывод средств (Withdrawal Callback)
Верификация подписи Webhook
Чтобы злоумышленники не могли отправить фальшивые уведомления на ваш сервер, шлюз подписывает каждый запрос. Сигнатура передается в HTTP-заголовке:
- В V2 API:
X-Syncra-Signature: t={timestamp},v1={hmac_sha256_hex} - В legacy V1 API:
SIGNATURE(содержит HMAC-SHA512 от строки{startOfDayUTC};{salt})
КРИТИЧЕСКАЯ ОСОБЕННОСТЬ V1 CALLBACK:
В legacy-вебхуках V1 временная метка подписи формируется строго как начало текущих суток в UTC (полночь, 00:00:00). Формула подписи:
timestamp = DateTime.UtcNow.Date.ToUnixTimestamp()
signature = HMACSHA512(timestamp + ";" + salt, merchantSecret)
Если вы обрабатываете вебхуки через V1 адаптер, проверяйте подпись строго по этой формуле с округлением времени до начала дня.
Пример верификации подписи V2 (Node.js)
const crypto = require('crypto');
function verifyV2Webhook(rawBody, signatureHeader, webhookSecret) {
// 1. Парсинг заголовка
const parts = signatureHeader.split(',');
const timestampPart = parts.find(p => p.startsWith('t='));
const signaturePart = parts.find(p => p.startsWith('v1='));
if (!timestampPart || !signaturePart) return false;
const timestamp = timestampPart.substring(2);
const providedSignature = signaturePart.substring(3);
// 2. Проверка возраста метки времени (защита от replay-атак)
const now = Math.floor(Date.now() / 1000);
if (Math.abs(now - parseInt(timestamp, 10)) > 300) {
return false; // Запрос старше 5 минут
}
// 3. Вычисление ожидаемой сигнатуры
const payload = `${timestamp}.${rawBody}`;
const expectedSignature = crypto
.createHmac('sha256', webhookSecret)
.update(payload)
.digest('hex');
// 4. Безопасное сравнение строк во избежание timing attacks
return crypto.timingSafeEqual(
Buffer.from(providedSignature, 'utf-8'),
Buffer.from(expectedSignature, 'utf-8')
);
}Правила обработки вебхуков (Best Practices)
- Возвращайте HTTP 200 быстро: Ваш обработчик должен сразу возвращать статус
200 OKс телом{"status":"success"}. Не выполняйте тяжелую бизнес-логику внутри HTTP-потока вебхука. Сначала сохраните событие в очередь задач (очередь сообщений или базу данных), верните ответ200, а затем обрабатывайте задачу асинхронно. - Используйте идемпотентность: Всегда проверяйте, не обрабатывали ли вы транзакцию с данным
deal_id(илиpaymentIdв V1) ранее. Одно и то же уведомление может прийти повторно из-за сбоев сети. - Политика повторных попыток (Retry Policy): Если ваш сервер возвращает ошибку (статус отличный от 2xx) или не отвечает в течение 10 секунд, Syncra запускает повторную отправку уведомления.
- Попытки повторяются с экспоненциальной задержкой (Exponential Backoff): через 10 секунд, 1 минуту, 5 минут, 15 минут, 1 час.
- Максимальное число попыток по умолчанию — 5.
- IP Whitelisting: Для дополнительного уровня защиты вы можете ограничить прием вебхуков только со списков IP-адресов шлюза Syncra. Актуальный список адресов можно получить в панели управления.