Memverifikasi tanda tangan webhook PAYWISE
Setiap webhook ditandatangani dengan HMAC-SHA256. Begini cara mengecek tanda tangannya di PHP dan Node.js, serta menangani pengiriman ulang dengan aman.
Terbit 03 Oktober 2026 2 menit baca
Saat pembayaran berhasil, gagal, atau kedaluwarsa, PAYWISE mengirim webhook ke server Anda. Karena URL webhook Anda bersifat publik, siapa pun bisa mengirim pesan "lunas" palsu ke sana. Karena itu setiap webhook PAYWISE ditandatangani, dan server Anda sebaiknya mengecek tanda tangan itu sebelum melakukan apa pun.
Cara kerja tanda tangan
Setiap pengiriman adalah POST dengan body JSON dan header X-PAYWISE-Signature. Header tersebut adalah HMAC-SHA256 (dalam format hex) dari body mentah request, dengan webhook secret Anda sebagai kuncinya. Secret bisa dilihat di halaman Webhook pada dashboard.

Dua hal penting:
- Gunakan body mentah, persis seperti yang diterima. Jika JSON di-parse lalu di-encode ulang, spasi atau urutan key bisa berubah dan tanda tangan tidak akan cocok.
- Bandingkan dengan fungsi constant-time (
hash_equalsdi PHP,crypto.timingSafeEqualdi Node.js).
PHP
$payload = file_get_contents('php://input');
$expected = hash_hmac('sha256', $payload, getenv('PAYWISE_WEBHOOK_SECRET'));
$received = $_SERVER['HTTP_X_PAYWISE_SIGNATURE'] ?? '';
if (! hash_equals($expected, $received)) {
http_response_code(401);
exit;
}
$event = json_decode($payload, true);
if ($event['event'] === 'payment.paid') {
// Tandai $event['data']['merchant_reference'] sebagai lunas (sekali saja).
}
http_response_code(200);
Node.js (Express)
app.post('/webhooks/paywise', express.raw({ type: 'application/json' }), (req, res) => {
const expected = crypto.createHmac('sha256', process.env.PAYWISE_WEBHOOK_SECRET)
.update(req.body).digest('hex');
const received = req.get('X-PAYWISE-Signature') || '';
const ok = received.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received));
if (!ok) return res.sendStatus(401);
const event = JSON.parse(req.body);
// tangani event.event: payment.paid, payment.failed, payment.expired
res.sendStatus(200);
});
SDK PHP dan Node.js sudah menyediakan fungsi verifikasi siap pakai.
Pengiriman ulang dan duplikat
Jika server Anda tidak menjawab dengan status 2xx, PAYWISE mengirim ulang webhook secara otomatis. Setiap percobaan, beserta status yang dijawab server Anda, tercatat di halaman Webhook, dan Anda bisa mengirim ulang dari halaman transaksi. Artinya event yang sama bisa datang lebih dari sekali: buat handler Anda idempoten, misalnya abaikan payment.paid untuk pesanan yang sudah lunas.
Event yang bisa diterima
payment.paid,payment.failed,payment.expireduntuk transaksi,withdrawal.completed,withdrawal.failed,withdrawal.rejecteduntuk penarikan dana Anda.
Jawab secepatnya dengan status 2xx, dan kerjakan proses yang lama (email, update stok) di latar belakang.

