Paymenku Docs
Referensi APIWebhook

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 amount dari webhook sebagai nilai pesanan. Cocokkan dengan reference_id di sistem Anda.
  • Periksa is_sandbox. Webhook sandbox tidak boleh memicu pemenuhan pesanan sungguhan.

Header Parameters

X-PaymenKu-Signature*string

HMAC-SHA256(timestamp + "." + raw_body, webhook_secret) dalam hex.

X-PaymenKu-Timestamp*string

Unix timestamp; bagian dari data yang ditandatangani.

Request Body

application/json
  1. body
event?string
trx_id?string
reference_id?string

Referensi Anda sendiri — pakai ini untuk mencocokkan pesanan.

status?Status transaksi
StatusArti
pendingDibuat, menunggu pembayaran
paidTerbayar; dana masuk setelah kliring
expiredLewat batas waktu pembayaran
failedGagal di sisi penyedia
cancelledDibatalkan dari dashboard
refundedSudah di-refund

Hanya paid yang boleh memicu pemenuhan pesanan.

Value in"pending""paid""expired""failed""cancelled""refunded"
amount?string
total_fee?string|null
amount_received?string|null
payment_channel?string
customer_name?string|null
customer_email?string|null
paid_at?|
Formatdate-time
created_at?|
Formatdate-time
is_sandbox?boolean

Webhook sandbox tidak boleh memicu pemenuhan pesanan sungguhan.

Response Body

Diterima. Balas 2xx apa pun agar tidak dikirim ulang.

Example Requests
POST/payment.status_updated
Request Body
application/json
{  "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}
Header Parameters
{  "X-PaymenKu-Signature": "string",  "X-PaymenKu-Timestamp": "string"}