Qut Pay Сайт Кабинет База знаний Инструкции Документация API ҚАЗРУС
ГлавнаяБаза знаний → Справочник

Настройка вебхуков

Обновлено: 2026-09-14 · Версия в Markdown

Коротко

Вебхук — это HTTP-запрос, который мы отправляем на ваш сервер при смене статуса счёта. Чтобы его подключить, зайдите в раздел Интеграции кабинета и добавьте свой адрес: https://qut.kz/app

В боевом режиме адрес должен быть только https и на настоящем домене. IP-адрес, localhost и адреса временных туннелей не принимаются. Секрет показывается один раз — скопируйте его сразу.

Ваш адрес должен быть открыт без авторизации: мы приходим как обычный внешний клиент и не передаём ни логинов, ни паролей.

Как добавить адрес

  1. Войдите в кабинет: https://qut.kz/app
  2. Откройте раздел Интеграции.
  3. Добавьте адрес вебхука — полный путь, например https://site.kz/qutpay-webhook.
  4. Отметьте нужные события.
  5. Скопируйте показанный секрет в секретную переменную сервера (например, QUTPAY_WEBHOOK_SECRET).
  6. Нажмите кнопку проверки и убедитесь, что запрос доходит.

Повторно секрет не показывается. Если потеряли — создайте новый; он начинает действовать с момента создания, поэтому обновите сервер одновременно.

Требования к адресу

ТребованиеБоевой режимПесочница
ПротоколТолько httpsМожно http
ДоменНужен настоящий доменМожно localhost
IP-адресНе принимаетсяМожно
Адрес туннеляНе принимаетсяМожно
АвторизацияНе должно бытьНе должно быть

Если адрес не проходит требования, ошибка появится сразу при сохранении:

КодЧто случилось
invalid_urlАдрес некорректен
webhook_url_requires_httpsHTTP-адрес не принимается
webhook_url_requires_domainIP или адрес без домена
webhook_url_tunnel_forbiddenАдрес временного туннеля
too_many_endpointsПревышено число вебхуков

Выбор событий

Включать все события не нужно. Чаще всего достаточно двух: invoice.paid и invoice.refunded.

ГруппаСобытия
Счётinvoice.created, invoice.pending, invoice.paid, invoice.cancelled, invoice.expired, invoice.failed, invoice.lost
Возвратыinvoice.refunded, invoice.partially_refunded, refund.done, refund.failed, refund.unknown
Общееinvoice.status — один канал на любую смену статуса
Ошибкиinvoice.create_failed, invoice.cancel_failed, invoice.bulk
Подпискиsubscription.created, subscription.status

Какое событие в какой момент приходит: Жизненный цикл счёта.

Заголовки

В каждом запросе приходят четыре заголовка:

ЗаголовокЧто это
X-Webhook-EventНазвание события, например invoice.paid
X-Webhook-TimestampВремя отправки, Unix-секунды
X-Webhook-SignatureПрефикс sha256= и подпись в hex
X-Webhook-DeliveryНомер доставки, удобно сверять с журналом

Подпись обязательно проверяйте: Безопасность вебхуков.

Пример тела

POST /qutpay-webhook HTTP/1.1
Host: site.kz
Content-Type: application/json
X-Webhook-Event: invoice.paid
X-Webhook-Timestamp: 1757167000
X-Webhook-Signature: sha256=3f1a…
X-Webhook-Delivery: 17

{
  "event": "invoice.paid",
  "invoice": {
    "id": "inv_…",
    "externalOrderId": "1001",
    "status": "paid",
    "amount": 2500,
    "metadata": { "branch": "almaty-1" },
    "receiptUrl": "…",
    "paidAt": "…"
  },
  "sentAt": "…"
}

externalOrderId и metadata — это значения, которые вы передали при создании счёта; они возвращаются без изменений.

Расписание повторов

Если ваш сервер отвечает не 2xx или не отвечает вовсе, мы повторяем запрос 11 раз. Интервал начинается с 10 секунд и растёт до часа.

Из этого следуют два правила:

  1. Сначала верните 200, работу делайте после. Долгая обработка приводит к таймауту, а таймаут — к повтору.
  2. Обработка должна быть идемпотентной. Один и тот же статус по счёту может прийти несколько раз. Выполняйте её один раз по паре (invoice.id, status): Идемпотентность.
app.post('/qutpay-webhook', express.raw({ type: '*/*' }), async (req, res) => {
  if (!verify(req)) return res.sendStatus(401);
  res.sendStatus(200);                  // сначала ответ
  await enqueue(JSON.parse(req.body));  // потом работа
});

Журнал

В разделе Интеграции кабинета записывается каждая отправка: тип события, время, HTTP-ответ вашего сервера. Любая диагностика начинается отсюда.

Что в журналеЗначение
Нет ни одной записиМы не отправляли: адрес не добавлен, событие не выбрано или статус ещё не менялся
«Отправлено», ответ 401/403Адрес закрыт авторизацией
Ответ 404Неверный путь или маршрут не зарегистрирован
Ответ 301/302Редирект — мы его не следуем
Ответ 500Падает ваш обработчик
ТаймаутОбработка слишком долгая

Полная диагностика: Вебхук не приходит.

Правило редиректов

Редиректы 307 и 308 мы следуем только на сам этот адрес: httphttps и вариант со слешем на конце. Редирект, ведущий в другое место, мы не следуем.

Причина простая: слепое следование редиректу может отправить запрос на чужой адрес. Поэтому указывайте в кабинете конечный адрес, а не промежуточный.

Как протестировать

  1. Отправьте пробный запрос кнопкой проверки в кабинете — так вы увидите, что ваш код проверки подписи работает.
  2. Перейдите в песочницу, создайте счёт и симулируйте оплату через POST /api/v1/invoices/{id}/simulate {"status":"paid"}. Вебхуки при этом отправляются по-настоящему.
  3. Чтобы проверить повторы, временно заставьте обработчик отвечать 500 и посмотрите в журнале, как приходят повторные попытки.

Полный сценарий: Как протестировать интеграцию.

Вопросы и ответы

Можно добавить несколько адресов? Да. Например, один на сайт, другой на внутренний мониторинг. У каждого свой набор событий.

Достаточно ли одного вебхука? В большинстве случаев да. Если покупатель стоит у устройства и ждёт результата, опрашивайте статус параллельно: Вебхук или опрос статуса.

Потерял секрет. Создайте новый в кабинете и одновременно замените значение на сервере.

Я сменил адрес — что будет со старыми событиями? События, стоящие в очереди на повтор, уйдут на новый адрес.

В песочнице вебхуки приходят? Да, отправляются по-настоящему. Разница лишь в том, что адрес может быть http и localhost.

Связанные статьи

Безопасность вебхуков и проверка подписиКак устроена подпись, почему обязателен raw body, как проверять timestamp, примеры кода для Express, Laravel, Django и чистого Node, идемпотентная обработка и разбор частых ошибок.Вебхук не приходит — как найти причинуСчёт оплачен, а на ваш сервер уведомление не пришло. С чего начать диагностику, какая причина встречается чаще всего и как проверить её одним запросом.Жизненный цикл счётаВсе статусы счёта и переходы между ними, какое событие вебхука приходит в какой момент, какие статусы считаются открытыми и оплаченными, и как обработать поздно пришедшую оплату.Вебхук или опрос статуса: что когдаВебхук — основной способ узнать об оплате, но гарантия доставки не абсолютна. В сценариях, чувствительных к задержке, нужны оба механизма сразу: как их совместить, с какой частотой опрашивать и почему это не лишняя работа.Как протестировать интеграциюСценарии, которые нужно прогнать в песочнице: успешная оплата, отмена, истечение срока, полный и частичный возврат, поздняя оплата. Как тестировать вебхуки, какие граничные случаи проверить и как оформить всё это в автотесты.

Остались вопросы? WhatsApp +77788813333 · kazprose@gmail.com
Написать можно и из кабинета: Поддержка.

Qut Pay — независимый сервис, не аффилирован с АО «Kaspi Bank». Kaspi и Kaspi Pay — товарные знаки их правообладателя.