Pengaturan
Isi URL webhook di dasbor (Profil → Webhook). URL wajib https dan alamat internal seperti localhost atau IP privat ditolak. Secret untuk verifikasi tersedia di halaman yang sama dan bisa diputar ulang kapan saja.
Permintaan
POST /hooks/nigana HTTP/1.1
Content-Type: application/json
x-signature: 3c1f…e9a0
{"event":"invoice.paid","invoice_id":"9f2c1a7b3e5d8a41c0b2","order_id":"INV-1001",
"amount":25000,"fee":175,"net_amount":24825,"status":"paid","paid_at":1767225210}
| Field | Keterangan |
|---|---|
event | invoice.paid untuk pembayaran, webhook.test untuk tombol tes |
invoice_id, order_id | Identitas invoice |
amount | Nominal invoice |
fee | Biaya layanan |
net_amount | Yang masuk ke saldo (amount − fee) |
paid_at | Unix timestamp pelunasan |
Verifikasi tanda tangan
Header x-signature berisi HMAC-SHA256 heksadesimal huruf kecil dari body mentah dengan kunci secret webhook. Hitung dari byte mentah sebelum di-parse JSON, lalu bandingkan secara constant-time.
import crypto from 'node:crypto';
import express from 'express';
const app = express();
app.post('/hooks/nigana', express.raw({ type: 'application/json' }), (req, res) => {
const mine = crypto.createHmac('sha256', process.env.NIGANA_WEBHOOK_SECRET).update(req.body).digest('hex');
const theirs = String(req.get('x-signature') || '');
const ok = mine.length === theirs.length && crypto.timingSafeEqual(Buffer.from(mine), Buffer.from(theirs));
if (!ok) return res.sendStatus(401);
const evt = JSON.parse(req.body);
if (evt.event === 'invoice.paid') { /* tandai pesanan evt.order_id lunas (idempoten) */ }
res.sendStatus(200);
});
Perilaku pengiriman
- Dikirim satu kali per invoice lunas, dengan batas waktu 8 detik. Redirect tidak diikuti.
- Balas kode
2xxbila berhasil diterima. - Tidak ada pengiriman ulang otomatis. Bila servermu sedang mati, gunakan
GET /api/invoices/{id}atauGET /api/invoices?status=paiduntuk menyusul. - Buat penanganan idempoten: proses
order_idyang sama berkali-kali tidak boleh menggandakan pesanan.
Webhook hanya pemberitahuan. Sebelum mengirim barang bernilai, konfirmasi status lewat API dengan API key milikmu.
Tombol kirim tes
Dasbor memiliki tombol Kirim tes yang mengirim event webhook.test dan menampilkan hasilnya (kode HTTP atau galat koneksi). Dibatasi 5 kali per menit.