Status pembayaran berubah
Paymenku mengirim HTTP POST ke callback_url merchant setiap kali
status pembayaran berubah. Inilah sumber status yang resmi —
polling check-status hanya untuk rekonsiliasi.
Verifikasi tanda tangan
Hitung HMAC-SHA256 atas timestamp + "." + raw_body memakai webhook
secret Anda, lalu bandingkan konstan-waktu dengan header
X-PaymenKu-Signature.
Yang di-hash adalah raw body persis seperti diterima. Jangan parse JSON lalu serialisasi ulang — urutan kunci dan spasi akan berubah dan tanda tangan jadi tidak cocok.
$raw = file_get_contents('php://input');$ts = $_SERVER['HTTP_X_PAYMENKU_TIMESTAMP'] ?? '';$sig = $_SERVER['HTTP_X_PAYMENKU_SIGNATURE'] ?? '';$mine = hash_hmac('sha256', $ts . '.' . $raw, $webhookSecret);if (! hash_equals($mine, $sig)) { http_response_code(401); exit;}import crypto from 'node:crypto';// Butuh raw body — di Express: express.raw({ type: 'application/json' })const mine = crypto .createHmac('sha256', webhookSecret) .update(`${req.get('X-PaymenKu-Timestamp')}.${req.body}`) .digest('hex');const sig = req.get('X-PaymenKu-Signature');const ok = mine.length === sig.length && crypto.timingSafeEqual(Buffer.from(mine), Buffer.from(sig));Aturan penanganan
- Balas 2xx secepatnya, lalu proses di belakang. Balasan lambat memicu pengiriman ulang.
- Idempoten per
trx_id. Pengiriman ulang itu normal; memproses dua kali dapat menggandakan pengiriman barang atau saldo. - Jangan percaya
amountdari webhook sebagai nilai pesanan. Cocokkan denganreference_iddi sistem Anda. - Periksa
is_sandbox. Webhook sandbox tidak boleh memicu pemenuhan pesanan sungguhan.
X-PaymenKu-Signature*stringHMAC-SHA256(timestamp + "." + raw_body, webhook_secret) dalam hex.
X-PaymenKu-Timestamp*stringUnix timestamp; bagian dari data yang ditandatangani.
application/json- body
event?stringtrx_id?stringreference_id?stringReferensi Anda sendiri — pakai ini untuk mencocokkan pesanan.
status?Status transaksi| Status | Arti |
|---|---|
pending | Dibuat, menunggu pembayaran |
paid | Terbayar; dana masuk setelah kliring |
expired | Lewat batas waktu pembayaran |
failed | Gagal di sisi penyedia |
cancelled | Dibatalkan dari dashboard |
refunded | Sudah di-refund |
Hanya paid yang boleh memicu pemenuhan pesanan.
"pending""paid""expired""failed""cancelled""refunded"amount?stringtotal_fee?string|nullamount_received?string|nullpayment_channel?stringcustomer_name?string|nullcustomer_email?string|nullpaid_at?|date-timecreated_at?|date-timeis_sandbox?booleanWebhook sandbox tidak boleh memicu pemenuhan pesanan sungguhan.
Diterima. Balas 2xx apa pun agar tidak dikirim ulang.
{ "event": "payment.status_updated", "trx_id": "IDP202610271040123456", "reference_id": "INV-20261027-002", "status": "paid", "amount": "250000.00", "total_fee": "4940.00", "amount_received": "245060.00", "payment_channel": "bca_va", "customer_name": "Budi Santoso", "customer_email": "budi@example.com", "paid_at": "2026-10-27T10:45:12+07:00", "created_at": "2026-10-27T10:40:00+07:00", "is_sandbox": false}{ "X-PaymenKu-Signature": "string", "X-PaymenKu-Timestamp": "string"}