KiPaydocs
Dokumentasi/Panduan

PANDUAN

Biarkan perubahan status datang ke backend Anda

Terima event KiPay pada endpoint HTTPS, kirim response dengan cepat, dan proses pemenuhan order secara idempotent.

PENGIRIMAN IDEMPOTENTPengiriman berulang tetap menghasilkan satu pemenuhan order.
Pengiriman webhook yang idempotentPengiriman pertama dan duplikat masuk ke dedupe gate yang menggunakan trx_id. Handler memberi response dengan cepat. Satu verifikasi di background menghasilkan satu pemenuhan order. Duplikat tidak menghasilkan pemenuhan kedua.PENGIRIMAN 01transaction.paidtrx_id: VG57V5PENGIRIMAN 02event yang samatrx_id: VG57V5DEDUPEberdasarkan trx_idcatat sekalipertama diterimasudah diprosesPENUHI SEKALIsetelah verifikasi APIBalas cepat. Verifikasi dan penuhi order di background.
01

Event yang tersedia

EventDikirim ketikaTindakan
transaction.paidPembayaran cocok dengan transaksiVerifikasi lalu penuhi order
transaction.expiredWaktu pembayaran berakhirTutup checkout
webhook.testTes dikirim dari dashboardValidasi koneksi
02

Dapatkan webhook secret

Setiap project punya satu webhook secret sendiri, format whsec_ diikuti 48 karakter acak. Secret dibuat otomatis saat pertama kali Anda mengisi Webhook URL di /dashboard/projects, dan ditampilkan hanya SATU KALI saat itu — salin dan simpan di secret manager Anda sebelum meninggalkan halaman. Kalau lupa atau dicurigai bocor, klik "Buat Ulang Secret" untuk membuat yang baru (yang lama langsung berhenti berlaku).

  • Simpan sebagai environment variable, bukan di source code
  • Beda project berarti beda secret — jangan pakai ulang antar project
  • Rotasi secret tidak mengubah Webhook URL, jadi tidak ada downtime saat mengganti
03

Header yang dikirim di setiap webhook

HeaderIsi
X-Webhook-EventNama event, sama dengan field event pada body
X-Webhook-DeliveryID delivery unik dan stabil — dipakai ulang persis sama kalau KiPay mencoba mengirim ulang event yang sama
X-Webhook-TimestampWaktu pengiriman, ikut ditandatangani untuk mencegah replay
X-Webhook-SignatureHMAC-SHA256, format sha256=<hex>
04

Verifikasi signature sebelum memproses payload

Signature dihitung dari HMAC-SHA256 atas string "{timestamp}.{deliveryId}.{rawBody}" memakai webhook secret Anda. Pakai raw body mentah persis seperti yang diterima — body yang sudah di-parse lalu di-serialize ulang bisa mengubah urutan key atau whitespace dan membuat signature tidak cocok.

verify-signature.ts
TypeScript
import { verifyWebhookSignature } from 'kipay-node';

app.post(
  '/webhooks/kipay',
  express.raw({ type: 'application/json' }), // JANGAN express.json() di route ini
  async (req, res) => {
    const rawBody = req.body.toString('utf8');
    const ok = verifyWebhookSignature({
      rawBody,
      secret: process.env.KIPAY_WEBHOOK_SECRET!,
      timestamp: req.header('X-Webhook-Timestamp') ?? '',
      deliveryId: req.header('X-Webhook-Delivery') ?? '',
      signature: req.header('X-Webhook-Signature') ?? '',
    });
    if (!ok) return res.status(401).send('invalid signature');

    res.status(200).send('ok'); // ack dulu, proses berat lewat queue

    const { event, transaction } = JSON.parse(rawBody);
    if (event === 'transaction.paid') {
      await queuePaymentVerification(transaction.trx_id);
    }
  }
);
Bukan bahasa Node.js?

Algoritmanya sederhana: HMAC-SHA256(secret, `${timestamp}.${deliveryId}.${rawBody}`), lalu bandingkan hasilnya (hex, diawali "sha256=") dengan header X-Webhook-Signature memakai constant-time comparison. Tolak juga timestamp yang terlalu lama (mis. lebih dari 5 menit) untuk membatasi replay.

05

Verifikasi status sebelum memenuhi order

Signature yang valid membuktikan payload memang dari KiPay dan tidak diubah di tengah jalan — itu belum cukup untuk memenuhi order.

  1. 01
    Cari trx_id

    Pastikan transaksi terhubung ke satu order yang Anda kenali.

  2. 02
    Baca status dari KiPay

    Kirim request server-to-server dan pastikan status transaksi adalah paid.

  3. 03
    Bandingkan amount

    Pastikan nominal final sesuai dengan order.

  4. 04
    Penuhi order satu kali

    Gunakan trx_id sebagai idempotency boundary internal.

06

Kalau endpoint Anda gagal merespons

KiPay mencoba ulang pengiriman yang gagal (bukan 2xx, atau timeout) hingga 6 kali dengan jeda meningkat — sekitar 10 detik, lalu 20, 40, 80, dan 160 detik. Setiap percobaan ulang memakai X-Webhook-Delivery yang sama persis, jadi jadikan itu (bukan hanya trx_id) sebagai kunci idempotency kalau Anda ingin mendeteksi pengiriman duplikat secara eksplisit. Setelah 6 kali gagal, KiPay berhenti mencoba untuk event tersebut.