Webhooklar
API ni so'ramasdan to'lov holati haqida xabarlar
SplitPay kassa to'lovlari haqidagi hodisalarni manzilingizga o'zi yuboradi, shuning uchun GET /v1/charges/{id} ni
so'rab turish shart emas. Manzil admin panelda belgilanadi: Kassalar → Webhooklar. U yerda imzo kaliti (bir marta
ko'rsatiladi), sinov hodisasi va qo'lda qayta yuborish imkoni bilan yetkazilishlar jurnali ham bor.
Hodisalar
type | Qachon |
|---|---|
charge.created | To'lov yaratildi |
charge.succeeded | Pul yechildi |
charge.failed | Bank rad etdi |
charge.reversed | To'lov bekor qilindi |
charge.split_completed / charge.split_failed | Taqsimot bajarildi / bajarilmadi |
charge.fiscal_registered / charge.fiscal_failed | OFD cheki chiqdi / chiqmadi |
webhook.test | Admin paneldan sinov hodisasi |
So'rov
Manzilingizga JSON tanali POST:
{
"id": "0f8d3c1e-…",
"type": "charge.split_completed",
"createdAt": "2026-09-27T10:00:00.000Z",
"data": { "object": { "id": "…", "externalId": "order-777", "status": "SUCCEEDED", "split": { "status": "COMPLETED" } } }
}data.object GET /v1/charges/{id} javobi bilan bir xil formatda. Sarlavhalar:
SplitPay-Event-Id, SplitPay-Event-Type va SplitPay-Signature.
Imzoni tekshirish
SplitPay-Signature: t=<unix vaqt>,v1=<imzo>, bu yerda imzo whsec_… kaliti bilan t.tana satridan olingan
HMAC-SHA256. JSON ni tahlil qilishdan oldin xom tanani tekshiring va 5 daqiqadan eski hodisalarni rad eting.
import { createHmac, timingSafeEqual } from 'node:crypto';
app.post('/hooks/splitpay', express.text({ type: 'application/json' }), (req, res) => {
const header = req.header('splitpay-signature') ?? '';
const { t, v1 } = Object.fromEntries(header.split(',').map((part) => part.split('=')));
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) {
return res.sendStatus(400); // hodisa 5 daqiqadan eski
}
const expected = createHmac('sha256', process.env.SPLITPAY_WEBHOOK_SECRET)
.update(`${t}.${req.body}`)
.digest('hex');
// doimiy vaqtda solishtirish, imzo vaqt bo'yicha sizib chiqmasligi uchun
const ok = v1?.length === expected.length && timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
if (!ok) {
return res.sendStatus(401);
}
const event = JSON.parse(req.body);
if (event.type === 'charge.split_completed') {
// event.data.object.externalId buyurtmasi to'landi va taqsimlandi
}
res.sendStatus(200);
});Javob va takrorlar
- 10 soniya ichida istalgan
2xxkod bilan javob bering; uzoq ishlovni javobdan keyin bajaring. - Aks holda yetkazish 1 daq, 5 daq, 15 daq, 1 soat, 3 soat, 6 soat va 12 soatdan keyin takrorlanadi, so'ng xato deb belgilanadi. Uni admin paneldan qayta yuborish mumkin.
- Bitta hodisa ikki marta kelishi mumkin: takrorlardan himoyalanish uchun
iddan foydalaning. - Kassa hodisalari tartib bilan yuboriladi, lekin takrorlardan keyin tartib kafolatlanmaydi:
createdAtvadata.objectdagi holatga tayaning. - Manzil
httpsbo'lishi va internetdan ochiq bo'lishi kerak.