Коротко
Для n8n есть два готовых workflow: один создаёт счёт, второй принимает события Qut Pay и проверяет их подпись. Оба собраны только из стандартных узлов (Webhook, Set, HTTP Request, Code, IF, Respond to Webhook) — ставить в n8n дополнительные пакеты не нужно.
Скачать: api.qut.kz/downloads/qutpay-n8n.zip. Ссылка есть и в кабинете: Интеграции → список загрузок.
Понадобится: n8n 1.x (self-hosted или Cloud), API-ключ Qut Pay и секрет вебхука.
Что внутри
| Файл | Что делает |
|---|---|
qutpay-create-invoice.json | Приходит POST /webhook/qutpay-order → создаётся счёт в Qut Pay → в ответ { id, payUrl, qrUrl, deepLink, expiresAt } |
qutpay-webhook-receiver.json | Приходит POST /webhook/qutpay-events ← события Qut Pay; проверяется HMAC-подпись, ветвление по invoice.paid, ответ 200 |
Импорт: n8n → Workflows → Add workflow → ⋯ → Import from File → выбрать JSON. Повторить для второго файла. После импорта workflow неактивны — сначала настройте credential и секрет, потом включите переключатель Active.
1. Credential для API-ключа
Ключ создаётся в кабинете: Интеграции → API-ключи → создать. Для проверки возьмите ключ песочницы (qp_test_…), для продакшена — qp_live_….
n8n → Credentials → Add credential → Header Auth:
| Поле | Значение |
|---|---|
| Credential name | Qut Pay API key — ровно так, узел ссылается на это имя |
| Name | X-API-Key |
| Value | qp_live_… или qp_test_… |
Затем откройте workflow «Qut Pay — создать счёт», узел «Qut Pay: создать счёт» → в поле Credential for Header Auth выберите созданный credential. Пока он не выбран, узел подсвечен красным.
Ключ должен оставаться внутри n8n. Не переносите его в код, который выполняется в браузере, и не встраивайте в саму форму.
2. Секрет вебхука
Секрет показывается один раз — в момент, когда вы добавляете адрес вебхука в кабинете. Узел «Проверка подписи» ищет его в таком порядке:
- переменная окружения
QUTPAY_WEBHOOK_SECRET($env) — self-hosted; - n8n Variables с тем же именем (
$vars) — Cloud или если доступ к$envзакрыт.
В .env self-hosted n8n:
QUTPAY_WEBHOOK_SECRET=whsec_…
N8N_BLOCK_ENV_ACCESS_IN_NODE=false
NODE_FUNCTION_ALLOW_BUILTIN=crypto
После изменения переменных n8n нужно перезапустить. В n8n Cloud модуль crypto разрешён изначально, а секрет задаётся через Settings → Variables.
3. Регистрация адреса в кабинете
- Включите workflow «Qut Pay — приём webhook» (Active).
- Откройте узел «Webhook: события Qut Pay» и скопируйте Production URL, например
https://n8n.example.kz/webhook/qutpay-events. - Кабинет → Интеграции → добавить адрес вебхука → вставьте URL → сохраните секрет, он показывается один раз.
- Кнопка отправки тестового события в кабинете шлёт
webhook.test. В n8n оно пройдёт проверку подписи, попадёт в ветку «Другие события» и получит ответ 200.
Test URL (/webhook-test/…) работает только пока нажата кнопка «Listen for test event» — для кабинета он не подходит, нужен именно Production URL.
В боевом режиме адрес должен быть https с реальным доменом: IP-адреса и временные туннели не принимаются.
Как проверяется подпись
Узел «Проверка подписи» делает всю работу за вас:
X-Webhook-Signature=sha256=+ HMAC-SHA256(секрет,timestamp + "." + rawBody), hex;X-Webhook-Timestamp— unix-время в секундах, допуск ±300 секунд (защита от повторной отправки);- сравнение выполняется за постоянное время;
- при несовпадении — ответ 401, и Qut Pay повторит доставку.
Одна деталь решает всё: в узле Webhook должна быть включена опция Options → Raw Body. Подпись считается по исходным байтам тела, а не по разобранному JSON. Подробнее: Подпись вебхука не сходится.
Сценарий: форма → счёт → оплата → уведомление
Самая частая цепочка выглядит так:
- Форма на сайте (Tilda, собственная вёрстка, CRM) отправляет
POST /webhook/qutpay-orderс суммой и данными клиента. - Узел «Поля счёта» читает поля:
amount,description,externalOrderId,customer.name/phone/email,successUrl,failUrl,metadata. Если ваш источник присылает другие имена — поменяйте выражения в этом узле. - Узел «Qut Pay: создать счёт» вызывает
POST https://api.qut.kz/api/v1/invoicesи передаёт заголовокIdempotency-Key(по умолчаниюn8n-<externalOrderId>). Повторный запрос с тем же номером заказа вернёт тот же счёт, а не создаст новый. - Ответ отдаёт
payUrl— отправьте покупателя на эту страницу. - Когда клиент оплатит, Qut Pay пришлёт
invoice.paidво второй workflow, и сработает ветка «Оплачено: ваше действие».
«Оплачено: ваше действие» — пустой узел NoOp, его заменяют своим: строка в Google Sheets, письмо, HTTP-запрос в CRM или 1С, сообщение в Telegram (пример-заглушка лежит рядом, отключён). В ветке доступны $json.externalOrderId, $json.amount, $json.invoice.receiptUrl, $json.invoice.paidAt, $json.late.
Чтобы счёт уходил прямо в приложение Kaspi покупателя, добавьте kind: "phone" в JSON-тело узла «Qut Pay: создать счёт». Тогда customer.phone обязателен, а сумма должна быть целой.
Повторные события
Одно и то же событие может прийти дважды: если вы ответили не-2xx, доставка повторяется до 11 раз. Поэтому обработчик должен быть идемпотентным — ключ дедупликации это пара (invoice.id, status).
Оплата может прийти и после expired или cancelled — в таком событии стоит late: true. Выдайте товар или верните деньги.
Проверка в песочнице
Переведите организацию в режим песочницы и используйте ключ qp_test_…. Создайте счёт, затем имитируйте оплату:
curl -X POST https://api.qut.kz/api/v1/invoices/inv_…/simulate \
-H 'X-API-Key: qp_test_…' -H 'Content-Type: application/json' \
-d '{"status": "paid"}'
Через несколько секунд invoice.paid придёт в n8n — проверьте раздел Executions у workflow «Qut Pay — приём webhook». Можно и без curl: откройте payUrl в браузере и нажмите кнопку оплаты песочницы. Подробнее: Симуляция оплаты в песочнице.
Частые проблемы
| Симптом | Причина и решение |
|---|---|
QUTPAY_WEBHOOK_SECRET не задан | Нет секрета в $env/$vars либо стоит N8N_BLOCK_ENV_ACCESS_IN_NODE=true |
Модуль crypto недоступен | Добавьте NODE_FUNCTION_ALLOW_BUILTIN=crypto и перезапустите n8n |
В узле Webhook включите опцию «Raw Body» | Включите Webhook → Options → Raw Body |
X-Webhook-Timestamp вне допуска | Часы сервера n8n разошлись более чем на 5 минут — настройте NTP |
Подпись webhook неверна | Секрет от другого адреса или организации, либо тело изменено прокси |
В кабинете доставка HTTP 404 | Workflow не активирован или указан Test URL вместо Production URL |
401 unauthorized при создании счёта | Неверный ключ или credential не выбран в узле HTTP Request |
429 request_rate_limited | Слишком частые запросы — соблюдайте Retry-After |
Если вебхук не доходит вовсе, причина обычно не в подписи: Вебхук не приходит.
Вопросы и ответы
Работает ли это в n8n Cloud? Да. Оба workflow используют только стандартные узлы, секрет задаётся через Settings → Variables.
Нужен ли отдельный community node для Qut Pay? Нет. Узел HTTP Request работает с API напрямую, ничего доустанавливать не требуется.
Можно ли обслуживать в одном n8n несколько организаций? Можно, но у каждой организации свой ключ и свой секрет вебхука. Делайте отдельный credential и отдельный адрес (или отдельный workflow) на каждую.
Как передать покупателю payUrl из ответа? Перенаправьте его на этот адрес со страницы формы. Есть и готовый путь с редиректом прямо на оплату: Tilda и любые формы.
Где посмотреть коды ошибок? Все коды собраны по группам: Каталог ошибок.