Гайд
Kaspi вебхуки: событие «оплачено» автоматически
2 мин чтения
У Kaspi нет вебхуков — приложение не умеет уведомлять ваш сервер об оплате. Опрашивать статус в цикле дорого и медленно. AgentPay добавляет подписанные вебхуки поверх Kaspi: как только клиент платит, на ваш endpoint прилетает событие invoice.paid. Ниже — формат, проверка подписи и доставка.
Подключение
Добавьте endpoint в настройках вебхуков. При создании вы получите секрет whsec_* — он показывается один раз, храните в .env. На каждое событие AgentPay шлёт POST на ваш URL.
Формат запроса
POST /your-webhook-handler Content-Type: application/json X-AgentPay-Signature: t=1735689600,v1=5257a86... X-AgentPay-Event-Type: invoice.paid X-AgentPay-Event-Id: 8e9d2b4a-1f5c-4a3d-9b8a-c7e1f0d3a5b6
Тело — объект события:
{
"id": "evt_...",
"object": "event",
"type": "invoice.paid",
"resource_type": "invoice",
"resource_id": "8e9d2b4a-1f5c-4a3d-9b8a-c7e1f0d3a5b6",
"mode": "live",
"data": { "kaspiStatus": "Confirmed", "kaspiInvoiceId": "1234567" },
"created_at": "2026-05-12T18:35:18.000Z"
}Проверка подписи
Подпись — HMAC-SHA256 от строки <timestamp>.<raw_body> с вашим whsec_* в качестве ключа. Сравнивайте constant-time и отвергайте запросы старше 5 минут (защита от повторов):
import crypto from 'node:crypto';
function verifyAgentPayWebhook(rawBody, header, secret) {
const parts = Object.fromEntries(
header.split(',').map((p) => p.trim().split('=', 2)),
);
const t = Number(parts.t);
const sig = parts.v1;
if (!t || !sig) return false;
if (Math.abs(Date.now() / 1000 - t) > 300) return false; // 5 мин
const expected = crypto
.createHmac('sha256', secret)
.update(`${t}.${rawBody}`)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected, 'hex'),
Buffer.from(sig, 'hex'),
);
}Проверяйте подпись по сырому телу запроса (raw body), до JSON-парсинга. Любая перекодировка тела сломает HMAC.
Доставка и ретраи
- Успех — это HTTP 2xx; таймаут 15 секунд.
- Повторы по графику: 1 мин → 5 мин → 30 мин → 2 ч → 12 ч → 1 день → 2 дня → dead-letter (8 попыток, ~3 дня).
- Доставка at-least-once — приёмник обязан быть идемпотентным (используйте
X-AgentPay-Event-Id).
Какие события приходят
Полный жизненный цикл счёта и подписки: invoice.created, invoice.sent, invoice.paid, invoice.expired, invoice.cancelled, invoice.refunded, а также subscription.* и cashier.*. Подписаться на конкретный тип можно в настройках endpoint.
Локальная отладка
Чтобы не поднимать публичный URL, слушайте события через CLI — он форвардит их на localhost:
agentpay listen --forward-to http://localhost:3000/webhooks/agentpay
Подключите приём оплаты через Kaspi за 5 минут. 0% комиссии, деньги напрямую на ваш счёт.
Создать аккаунтЧастые вопросы
Есть ли у Kaspi собственные вебхуки?
Нет. Kaspi не уведомляет сторонние серверы об оплате. Вебхуки добавляет AgentPay поверх вашего кассира: событие invoice.paid приходит автоматически, опрашивать статус не нужно.
Как проверить, что вебхук действительно от AgentPay?
По заголовку X-AgentPay-Signature: это HMAC-SHA256 от строки «timestamp.raw_body» с вашим секретом whsec_*. Сравнивайте constant-time и отклоняйте запросы старше 5 минут.
Что будет, если мой сервер недоступен?
AgentPay повторит доставку по нарастающему графику до 8 раз в течение ~3 дней, затем отправит событие в dead-letter. Доставка at-least-once, поэтому обработчик должен быть идемпотентным.