Қысқаша
Webhook — счёттың күйі өзгергенде біз сіздің серверіңізге жіберетін HTTP сұрау. Оны қосу үшін кабинеттің Интеграциялар бөліміне барып, өз адресіңізді қосасыз: https://qut.kz/app
Продакшенде адрес тек https және нақты домен болуы керек. IP адрес, localhost және уақытша туннель адрестері қабылданбайды. Құпия (secret) бір рет көрсетіледі — сол сәтте көшіріп алыңыз.
Адресіңіз авторизациясыз ашық болуы тиіс: біз қарапайым сыртқы клиент ретінде келеміз, логин мен пароль жібермейміз.
Адрес қосу
- Кабинетке кіріңіз: https://qut.kz/app
- Интеграциялар бөліміне өтіңіз.
- Webhook адресін қосыңыз — толық жол, мысалы
https://site.kz/qutpay-webhook. - Керекті оқиғаларды белгілеңіз.
- Көрсетілген құпияны көшіріп, серверіңіздің құпия айнымалысына салыңыз (
QUTPAY_WEBHOOK_SECRETсияқты). - Сынау батырмасымен тексеріп көріңіз.
Құпия қайта көрсетілмейді. Жоғалтсаңыз жаңасын жасайсыз, ал жаңа құпия қосылған сәттен бастап қолданылады — серверіңізді бір мезетте жаңартыңыз.
Адреске қойылатын талаптар
| Талап | Продакшен | Sandbox |
|---|---|---|
| Хаттама | Тек https | http да болады |
| Домен | Нақты домен керек | localhost да болады |
| IP адрес | Қабылданбайды | Болады |
| Туннель адресі | Қабылданбайды | Болады |
| Авторизация | Болмауы керек | Болмауы керек |
Талапқа сай келмесе, адресті сақтағанда бірден қате көресіз:
| Код | Не болды |
|---|---|
invalid_url | Адрес дұрыс емес |
webhook_url_requires_https | HTTP адрес қабылданбайды |
webhook_url_requires_domain | IP немесе домені жоқ адрес |
webhook_url_tunnel_forbidden | Уақытша туннель адресі |
too_many_endpoints | Webhook саны шектен асты |
Оқиғаларды таңдау
Барлық оқиғаны қосудың қажеті жоқ. Көбіне екеуі жеткілікті: 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 | Жеткізу нөмірі, журналмен салыстыруға ыңғайлы |
Қолтаңбаны міндетті түрде тексеріңіз: Webhook қауіпсіздігі.
Дене мысалы
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 секундтан басталып, бір сағатқа дейін өседі.
Бұдан екі қорытынды шығады:
- Алдымен 200 қайтарыңыз, жұмысты содан кейін істеңіз. Ұзақ өңдеу таймаутқа әкеледі, ал таймаут — қайталау.
- Өңдеуіңіз идемпотентті болсын. Бір счёт бойынша бір күй бірнеше рет келуі мүмкін.
(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 | Сіздің өңдеушіңіз құлап жатыр |
| Таймаут | Өңдеу тым ұзақ |
Толық диагностика: Webhook келмей жатыр.
Қайта бағыттау ережесі
307 және 308 қайта бағыттауларын біз тек сол адрестің өзіне ұстаймыз: http → https және қиғаш сызық қосылған нұсқа. Басқа жерге апаратын қайта бағыттауды ұстамаймыз.
Себебі қарапайым: қайта бағыттауды соқыр ұстау сұрауды бөтен адреске жіберіп қоюы мүмкін. Сондықтан кабинетке соңғы адресті жазыңыз, аралық адресті емес.
Сынау
- Кабинеттегі сынау батырмасымен сынама сұрау жіберіңіз — қолтаңбаны тексеретін кодыңыз жұмыс істеп тұрғанын осыдан көресіз.
- Sandbox-қа ауысып, счёт жасаңыз да,
POST /api/v1/invoices/{id}/simulate {"status":"paid"}арқылы төлемді симуляциялаңыз. Webhook шынайы жіберіледі. - Қайталауды сынау үшін өңдеушіңізді әдейі 500 қайтаратын етіп қойып, журналда қайталаудың келгенін қараңыз.
Толық сценарий: Интеграцияны қалай сынау керек.
Жиі қойылатын сұрақтар
Бірнеше адрес қосуға бола ма? Иә. Мысалы бір адрес сайтқа, екіншісі ішкі мониторингке. Әрқайсысының өз оқиға тізімі болады.
Webhook жалғыз жеткілікті ме? Көп жағдайда иә. Клиент құрылғының алдында тұрып нәтиже күтетін болса, қатар күйді де сұраңыз: Webhook пен күйді сұрау.
Құпияны жоғалттым. Кабинеттен жаңасын жасаңыз және серверіңіздегі мәнді сол сәтте ауыстырыңыз.
Адресімді өзгерттім, ескі оқиғалар не болады? Қайталау кезегінде тұрған оқиғалар жаңа адреске жіберіледі.
Sandbox-та да webhook келе ме? Иә, шынайы жіберіледі. Айырмашылығы — адрес http және localhost болуына рұқсат.