Webhooks
Webhooks позволяют получать уведомления об изменении статуса платежей в реальном времени.
Настройка
При создании платежа укажите:
notify_url— URL для получения уведомленийnotification_token— токен для валидации (опционально)
Заголовки webhook
| Заголовок | Описание |
|---|---|
Content-Type | application/json |
X-Webhook-Event | Тип события (payment.status_changed) |
X-Signature | HMAC-SHA256 подпись тела запроса |
X-Notification-Token | Ваш токен из notification_token (если был передан) |
Валидация через Notification Token
Если при создании платежа вы передали notification_token, он вернётся в заголовке X-Notification-Token. Сравните его с ожидаемым значением для быстрой валидации без вычисления подписи.
Формат webhook
{
"event": "payment.status_changed",
"paymentId": "550e8400-e29b-41d4-a716-446655440000",
"ext_id": "order_12345",
"status": "COMPLETED",
"amount": 5000,
"currency": "RUB",
"timestamp": "2026-01-30T12:22:00Z"
}
События
| Событие | Статус | Описание |
|---|---|---|
payment.status_changed | COMPLETED | Платёж успешно завершён |
payment.status_changed | CANCELLED | Платёж отменён |
payment.status_changed | COMPLETED_APPEAL | Апелляция одобрена |
payment.status_changed | CANCELLED_APPEAL | Апелляция отклонена |
payment.status_changed | DISPUTE | Открыт спор по платежу |
Проверка подписи
Заголовок X-Signature содержит HMAC-SHA256 подпись тела запроса (hex).
JavaScript
const crypto = require('crypto');
function verifyWebhook(body, signature, secretKey) {
const expectedSignature = crypto
.createHmac('sha256', secretKey)
.update(JSON.stringify(body))
.digest('hex');
return signature === expectedSignature;
}
app.post('/webhook', (req, res) => {
// Способ 1: Проверка через notification_token (быстро)
const token = req.headers['x-notification-token'];
if (token && token === expectedToken) {
// Валидация пройдена
}
// Способ 2: Проверка через подпись (надёжно)
const signature = req.headers['x-signature'];
if (!verifyWebhook(req.body, signature, secretKey)) {
return res.status(401).send('Invalid signature');
}
const { event, paymentId, status } = req.body;
console.log(`${event}: Payment ${paymentId} is ${status}`);
res.status(200).send('OK');
});
Python
import hmac
import hashlib
import json
def verify_webhook(body, signature, secret_key):
expected_signature = hmac.new(
secret_key.encode(),
json.dumps(body).encode(),
hashlib.sha256
).hexdigest()
return signature == expected_signature
PHP
function verifyWebhook($body, $signature, $secretKey) {
$expectedSignature = hash_hmac(
'sha256',
json_encode($body),
$secretKey
);
return hash_equals($expectedSignature, $signature);
}
Требования к серверу
- HTTP 200 OK — webhook считается доставленным при получении HTTP 200
- Таймаут — ответ должен быть получен в течение 10 секунд
- Идемпотентность — корректно обрабатывайте повторные доставки
Политика повторных попыток
При неудачной доставке система повторит отправку:
| Попытка | Задержка |
|---|---|
| 1 | Сразу |
| 2 | 60 секунд |
| 3 | 60 секунд |
После 3 неудачных попыток webhook помечается как недоставленный.