Dokumentasi API WaroengPay
Buat tagihan QRIS dari sistem tokomu, arahkan pembeli ke halaman bayar, lalu terima webhook saat pembayaran masuk. Semua endpoint memakai JSON dan API key milik akunmu. Data antar akun terpisah: kamu hanya bisa melihat tagihanmu sendiri.
Kredensial
API key untuk memanggil API, dan secret untuk memverifikasi webhook yang kami kirim ke tokomu.
API key live (wp_live_), API key uji (wp_test_), dan secret webhook dibuat di dashboard setelah akunmu aktif.
Mulai cepat
Empat langkah dari nol sampai pembayaran pertama tercatat otomatis di sistem tokomu.
Autentikasi
Setiap request API wajib membawa API key di header Authorization. Key wp_test_ untuk mode uji (lihat Sandbox).
Authorization: Bearer wp_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxContent-Type: application/json
401 invalid_api_key.Buat tagihan
Membuat tagihan QRIS dinamis dengan nominal unik. Balasan 201 berisi tagihan baru.
Nominal dalam rupiah, Rp1.000 sampai Rp10.000.000. Kode unik ditambahkan otomatis.
Nomor pesanan di sistemmu (maks 100 karakter). Ikut dikirim di webhook. Tidak unik: cocokkan pembayaran lewat id, bukan reference.
Keterangan yang tampil di halaman bayar (maks 200 karakter).
Penerima webhook tagihan ini. Kosong = pakai URL webhook default akunmu (tagihan uji: kosong = tanpa webhook).
Pembeli diarahkan ke sini 6 detik setelah pembayaran diterima.
Masa berlaku dalam menit, 5 sampai 60. Default 15.
Opsional. Kirim ulang request dengan key yang sama = tagihan yang sama (200), bukan tagihan baru. Pakai nomor pesanan.
curl -X POST https://waroengpay.com/api/payments \-H "Authorization: Bearer $WAROENGPAY_API_KEY" \-H "Content-Type: application/json" \-H "Idempotency-Key: INV-2041" \-d '{"amount": 50000,"reference": "INV-2041","description": "Paket Premium 1 bulan","callback_url": "https://tokoku.id/webhook/waroengpay","redirect_url": "https://tokoku.id/pesanan/INV-2041"}'
{"id": "WRG-7K2M9QX4BD1PZ","reference": "INV-2041","description": "Paket Premium 1 bulan","status": "pending","base_amount": 50000,"unique_code": 137,"amount": 50137,"qris": "000201010212265...6304A1B2","pay_url": "https://waroengpay.com/pay/WRG-7K2M9QX4BD1PZ","callback_url": "https://tokoku.id/webhook/waroengpay","redirect_url": "https://tokoku.id/pesanan/INV-2041","created_at": "2026-09-24T03:00:00.000Z","expires_at": "2026-09-24T03:15:00.000Z","paid_at": null,"late": false,"livemode": true,"link_id": null,"payment": null}
amount (sudah termasuk kode unik) ke pembeli. Pembayaran dengan nominal berbeda tidak bisa dicocokkan otomatis.Ambil tagihan
Status terbaru satu tagihan, termasuk detail pembayaran dan riwayat webhook-nya.
curl https://waroengpay.com/api/payments/WRG-7K2M9QX4BD1PZ \-H "Authorization: Bearer $WAROENGPAY_API_KEY"
Setelah lunas, objek payment berisi issuer (bank atau e-wallet pembayar), payer (nama yang sudah disamarkan bank), bca_ref (nomor referensi transaksi), dan transaction_at. Field webhooks berisi 20 pengiriman terakhir.
Struk gambar (PNG) untuk dikirim ke pembeli: GET /api/payments/:id/receipt.png. Hanya tagihan lunas, selain itu 409 not_paid.
Daftar tagihan
Tagihan milikmu, terbaru lebih dulu, dengan paginasi berbasis waktu.
Saring: pending, paid, expired, atau cancelled.
Rentang waktu. from ikut, to tidak ikut.
paid = rentang dan urutan memakai waktu bayar. Default waktu dibuat.
Cari di referensi, keterangan, ID, ref bank, nama pembayar, atau nominal persis.
Bank atau e-wallet pembayar, mis. DANA.
Tambahkan ringkasan: jumlah dan total seluruh hasil filter, per status, dan per sumber.
Jumlah per halaman, 1 sampai 200. Default 50.
Halaman berikutnya: isi dengan next_before dan next_before_id dari respons sebelumnya.
curl "https://waroengpay.com/api/payments?status=paid&limit=50" \-H "Authorization: Bearer $WAROENGPAY_API_KEY"# halaman berikutnya: tambahkan &before=<next_before>&before_id=<next_before_id> dari respons sebelumnya
{"data": [ { "id": "WRG-7K2M9QX4BD1PZ", "status": "paid", "amount": 50137, ... } ],"has_more": true,"next_before": "2026-09-24T03:00:00.000Z","next_before_id": "WRG-7K2M9QX4BD1PZ"}
Batalkan tagihan
Menutup tagihan yang masih menunggu. Pembayaran yang masuk setelah dibatalkan tidak akan dicocokkan.
curl -X POST https://waroengpay.com/api/payments/WRG-7K2M9QX4BD1PZ/cancel \-H "Authorization: Bearer $WAROENGPAY_API_KEY"
Tagihan yang sudah lunas, kedaluwarsa, atau batal dijawab 409 not_pending. Kalau tagihan punya callback_url, event payment.cancelled ikut dikirim.
Siklus status
Setiap tagihan dimulai dari pending dan berakhir di salah satu dari tiga status final.
pendingQR aktif dan bisa dibayar. Mutasi rekening dicek tiap 8 detik.
paidKredit dengan nominal persis ditemukan di mutasi rekening dalam jendela waktu tagihan.
expiredLewat batas waktu + 5 menit masa tenggang tanpa pembayaran yang cocok.
cancelledDibatalkan lewat dashboard atau API sebelum dibayar.
Webhook
Kami mengirim POST JSON ke callback_url setiap kali status tagihan berubah jadi final.
Penjelasan lengkap cara kerja dan verifikasinya: panduan webhook pembayaran. Contoh integrasi dari awal: tutorial PHP & Laravel.
| Event | Dikirim saat |
|---|---|
payment.paid | Pembayaran cocok ditemukan, tagihan lunas. Bisa datang setelah payment.expired / payment.cancelled bila admin mencocokkan pembayaran telat (data.late = true). |
payment.expired | Tagihan lewat batas waktu tanpa pembayaran. |
payment.cancelled | Tagihan dibatalkan. |
ping | Tombol "Kirim tes" di bagian Kredensial. |
// HeaderX-WaroengPay-Event: payment.paidX-WaroengPay-Delivery: 1842X-WaroengPay-Timestamp: 1790218992X-Signature: 5f2b0c...e91a // hex HMAC-SHA256(secret, "<timestamp>.<body>")// Body{"id": "evt_Qm2vK8sPz1Lx0aB7","event": "payment.paid","created_at": "2026-09-24T03:03:12.000Z","livemode": true, // false = event tagihan mode uji (sandbox)"data": {"id": "WRG-7K2M9QX4BD1PZ","reference": "INV-2041","status": "paid","base_amount": 50000,"amount": 50137,"pay_url": "https://waroengpay.com/pay/WRG-7K2M9QX4BD1PZ","paid_at": "2026-09-24T03:03:12.000Z","late": false, // true = pembayaran telat yang dicocokkan admin (bisa setelah payment.expired)"livemode": true,"link_id": null, // angka = dibuat pembeli lewat link pembayaran /l/<slug>"payment": {"issuer": "DANA","payer": "BU**I SAN**SO","bca_ref": "236433285","transaction_at": "2026-09-24T03:03:00.000Z"}}}
Verifikasi tanda tangan
Hitung HMAC-SHA256(secret, timestamp + "." + body) dari body mentah, bandingkan dengan header X-Signature memakai perbandingan waktu-konstan, dan tolak timestamp yang lebih tua dari 5 menit supaya kiriman lama tidak bisa diputar ulang.
import crypto from "node:crypto";import express from "express";const app = express();const SECRET = process.env.WAROENGPAY_WEBHOOK_SECRET; // whsec_...// pakai body mentah: tanda tangan dihitung dari teks persis yang dikirimapp.post("/webhook/waroengpay", express.raw({ type: "application/json" }), async (req, res) => {const ts = req.get("x-waroengpay-timestamp") || "";const sig = req.get("x-signature") || "";const expected = crypto.createHmac("sha256", SECRET).update(`${ts}.${req.body}`).digest("hex");const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300; // tolak kiriman ulang > 5 menitif (!fresh || sig.length !== expected.length || !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {return res.sendStatus(401);}const event = JSON.parse(req.body);if (event.livemode === false) return res.sendStatus(200); // event mode uji: jangan pernah menandai pesanan asliif (event.event === "payment.paid") {// cari pesanan lewat id tagihan yang disimpan saat membuat tagihan, BUKAN reference (tidak unik, bebas diisi)const order = await db.orders.findByWaroengpayId(event.data.id);if (!order || event.data.base_amount !== order.total) return res.sendStatus(200); // nominal beda: jangan tandai lunasawait db.orders.markPaid(order.id, event.id); // lewati kalau event.id sudah pernah diproses}res.sendStatus(200);});
id event yang sudah diproses dan lewati duplikatnya.id tagihan saat membuatnya, cari pesanan lewat data.id (bukan reference: siapa pun yang memegang API key-mu bisa memakai reference yang sama), pastikan data.base_amount sama dengan total pesanan, dan abaikan livemode: false.Halaman bayar
Setiap tagihan punya halaman bayar siap pakai di pay_url.
redirect_url, pembeli diarahkan ke sana 6 detik setelah lunas. Tagihan mode uji tidak dialihkan otomatis: alamatnya ditampilkan dan harus diklik.qris dengan library QR apa pun./l/slug) punya link_id, reference kosong, dan webhook-nya dikirim ke URL webhook default akunmu. Bila link meminta data pembeli, isiannya ada di customer (name, phone WhatsApp 62…, note).Error & batasan
Semua error berbentuk { "error": "pesan untuk manusia", "code": "kode_mesin" }.
| HTTP | code | Artinya |
|---|---|---|
| 400 | invalid_amount, invalid_url, invalid_expires_in, invalid_json, invalid_action | Input tidak valid. Baca pesan error-nya. |
| 401 | unauthorized, invalid_api_key | API key tidak ada, salah, atau sudah dibuat ulang. |
| 403 | account_not_active, forbidden, live_invoice | Akun belum disetujui/nonaktif, tidak punya akses, atau simulasi pada tagihan live. |
| 404 | not_found | Tagihan tidak ada atau bukan milikmu. |
| 409 | not_pending, not_final | Aksi tidak cocok dengan status tagihan saat ini. |
| 413 | payload_too_large | Body lebih dari 20 KB. |
| 429 | rate_limited, too_many_pending | Terlalu banyak request. Lihat header Retry-After. |
| 503 | amount_busy | Kode unik untuk nominal itu habis sementara. Coba lagi sebentar. |
Coba langsung
Kirim request POST /api/payments sungguhan memakai sesi dashboard, lalu lihat respons mentahnya.
Setelah masuk, bagian ini mengirim request sungguhan dari dashboard dan menampilkan respons mentahnya.
Sandbox (mode uji)
Uji integrasi dari buat tagihan sampai webhook tanpa uang sungguhan. Data uji terpisah total dari data live.
wp_test_ dari bagian Kredensial. Endpoint-nya sama persis; tagihan uji punya livemode: false.callback_url yang diisi saat membuat tagihan uji (bukan URL default), ditandatangani secret mode uji. Server produksi yang memakai secret live otomatis menolaknya; tetap abaikan livemode: false.pay = lunas (issuer SANDBOX, bca_ref palsu), expire = kedaluwarsa. Default pay. Hanya untuk tagihan uji yang masih pending.
curl -X POST https://waroengpay.com/api/payments/WRG-7K2M9QX4BD1PZ/simulate \-H "Authorization: Bearer $WAROENGPAY_TEST_KEY" \-H "Content-Type: application/json" \-d '{"action":"pay"}' # atau "expire"
Tagihan live dijawab 403 live_invoice, tagihan uji yang sudah final 409 not_pending. Tagihan uji yang tidak disimulasikan kedaluwarsa sendiri seperti tagihan live.