Dokumentasi API
Base URL: https://qrpay.biz.id/api/v1 · Format JSON · Nominal dalam rupiah bulat.
Autentikasi
Buat API key di Dashboard → API & Webhook (perlu langganan aktif). Kirim di setiap request:
x-api-key: qrp_live_xxxxxxxxxxxxxxxx
Alternatif: Authorization: Bearer qrp_live_.... Batas 120 request/menit per akun.
Buat order
curl -X POST https://qrpay.biz.id/api/v1/orders \
-H "x-api-key: qrp_live_xxx" \
-H "content-type: application/json" \
-d '{"base_amount":100000,"reference":"INV-001","description":"Donasi","callback_url":"https://situsanda.com/qrpay-webhook"}'
Field: base_amount (wajib, 1.000–10.000.000), reference (unik per order aktif), qris_id, customer_name, description, callback_url (menimpa webhook akun), redirect_url (tujuan setelah lunas di halaman bayar), expires_minutes (5–1440).
Respons 201:
{
"success": true,
"data": {
"id": "QRP261015A1B2C3D4E5",
"reference": "INV-001",
"status": "PENDING",
"base_amount": 100000,
"unique_code": 327,
"amount": 100327,
"qris_string": "000201010212...6304ABCD",
"payment_url": "https://qrpay.biz.id/pay/QRP261015A1B2C3D4E5",
"expires_at": "2026-10-15T21:00:00+07:00",
...
}
}
Tampilkan qris_string sebagai QR di aplikasi Anda, atau arahkan pembeli ke payment_url. Pembeli harus membayar tepat sebesar amount.
Cek order
GET /api/v1/orders/{id atau reference}
Daftar order
GET /api/v1/orders?status=PAID&limit=20
Batalkan order
POST /api/v1/orders/{id}/cancel
Status order: PENDING → PAID | EXPIRED | CANCELLED.
Webhook
Saat order berubah, QRPay mengirim POST JSON ke URL webhook. Event: order.paid, order.expired, webhook.test. Balas HTTP 2xx dalam 10 detik; bila gagal, dikirim ulang hingga 6 kali (1 mnt, 5 mnt, 15 mnt, 1 jam, 6 jam).
X-QRPay-Event: order.paid
X-QRPay-Timestamp: 1760536800
X-QRPay-Signature: sha256=5f2c...
X-QRPay-Delivery: 42
{"event":"order.paid","data":{ ...objek order... },"sent_at":"2026-10-15T20:40:00+07:00"}
Gunakan data.id atau data.reference agar pemrosesan idempoten (abaikan jika order sudah ditandai lunas di sistem Anda).
Verifikasi signature
Signature = HMAC-SHA256 dari timestamp + "." + body mentah dengan webhook secret Anda (whsec_...).
<?php
$secret = 'whsec_xxx';
$body = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_QRPAY_TIMESTAMP'] ?? '';
$sig = $_SERVER['HTTP_X_QRPAY_SIGNATURE'] ?? '';
$expect = 'sha256=' . hash_hmac('sha256', $ts . '.' . $body, $secret);
if (!hash_equals($expect, $sig) || abs(time() - (int) $ts) > 300) {
http_response_code(401); exit;
}
$event = json_decode($body, true);
if ($event['event'] === 'order.paid') {
// tandai invoice $event['data']['reference'] lunas
}
http_response_code(200);
// Node.js (Express, body mentah)
const crypto = require('crypto');
const expect = 'sha256=' + crypto.createHmac('sha256', SECRET).update(ts + '.' + rawBody).digest('hex');
const ok = crypto.timingSafeEqual(Buffer.from(expect), Buffer.from(sig));
Ingest URL (listener & callback)
Koneksi tipe Ingest URL memberi URL rahasia. Kirim POST setiap ada dana masuk, dari aplikasi listener notifikasi Android, MacroDroid/Tasker, atau callback bank:
POST /api/ingest/ing_xxxxxxxx
{"amount": 100327, "external_id": "ID-transaksi-unik-opsional", "payer": "opsional"}
// atau kirim teks notifikasi apa adanya, nominal diambil otomatis:
{"text": "Pembayaran QRIS Rp100.327 diterima dari BUDI"}
Respons result: matched (order ditandai lunas), unmatched (tercatat di Dana Masuk), atau duplicate.
Kode error
| HTTP | error | Arti |
|---|---|---|
| 401 | invalid_api_key | Key salah/dicabut |
| 402 | credit_empty | Saldo kredit API habis — perlu top up |
| 404 | not_found | Order tidak ada |
| 409 | not_pending | Order bukan PENDING |
| 422 | invalid_amount, duplicate_reference, no_qris, amount_exhausted, invalid_url | Input tidak valid |
| 429 | rate_limited | Lebih dari 120 req/menit |