PAYWISE
id
← Semua artikel

Developer

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

Tersedia juga dalam: English, 简体中文

Memverifikasi tanda tangan webhook PAYWISE

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.

Memverifikasi webhook: body mentah ditambah secret, HMAC-SHA256, lalu dibandingkan dengan header X-PAYWISE-Signature

Dua hal penting:

  1. 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.
  2. Bandingkan dengan fungsi constant-time (hash_equals di PHP, crypto.timingSafeEqual di 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.expired untuk transaksi,
  • withdrawal.completed, withdrawal.failed, withdrawal.rejected untuk penarikan dana Anda.

Jawab secepatnya dengan status 2xx, dan kerjakan proses yang lama (email, update stok) di latar belakang.

Artikel lainnya

Mulai dengan key sandbox hari ini.

Daftar, buat key sandbox, dan kirim transaksi pertama dari playground dalam beberapa menit.