RisaPay

RisaPay API Docs

Satu integrasi buat terima QRIS, VA, e-wallet, sampai retail. Cuma 3 endpoint + 1 callback, beres.

Base URL: https://risapay.xfazrin.my.id/
1 · Create→2 · Bayar→3 · Callback→4 · Verifikasi
Postman JSON Panduan untuk AI (.md)

1 Mulai Cepat

Lima langkah dari nol sampai menerima pembayaran.

① Daftar, terus ambil api_key, merchant_code (misal R39), private_key di dashboard.
② Hit POST api/transaction/create, simpan data.reference.
③ Tampilkan QR / nomor VA / link bayar ke pelanggan - atau arahkan ke {base}checkout/?page={reference}.
④ Siapin endpoint callback: verify signature → match nominal → mark paid → balas 200.
⑤ Polling/rekon berkala via GET api/transaction/detail.

Single source of truth buat AI: download risapay-api.md - satu file isi full flow + contoh valid & gagal.

2 Autentikasi

Satu header untuk semua request.

HEADERAuthorization: Bearer <api_key>

Regenerate key di dashboard = key lama auto mati. Key kosong/salah → JSON success:false (HTTP 200, bukan 401. Yang 429 cuma rate-limit).

3 Signature Request

HMAC-SHA256 dari string mentah yang dikirim.

RUMUSHMAC_SHA256(merchant_code + merchant_ref + amount, private_key)

amount adalah string persis seperti dikirim ("50000", bukan angka format). RisaPay match ke semua merchant milikmu buat nemuin merchant_code yang kepake.

hasil muncul di sini…

4 Buat Transaksi

Body form-encoded, bukan JSON.

POSThttps://risapay.xfazrin.my.id/api/transaction/create
ParameterWajibKeterangan
methodYaKode channel: QRIS, BRIVA, DANA, OVO, … (tabel channel)
merchant_refYaReferensi unik versimu per merchant
amountYaRupiah > 0, dalam batas min/max channel
signatureYaHMAC bagian 3
customer_nameTidakNama pelanggan
customer_emailTidakDefault email@example.com
customer_phoneTidakNo. HP pelanggan
return_urlTidakDefault https://example.com/
callback_urlTidakOverride callback per-transaksi
expired_timeTidakUnix timestamp; default VA 24 jam, lainnya 48 jam
order_itemsTidakRincian item belanja
PHP$merchantCode = 'R39';
$merchantRef  = 'INV-2026-0001';
$amount       = '50000';
$signature = hash_hmac('sha256', $merchantCode . $merchantRef . $amount, $privateKey);

$ch = curl_init('https://risapay.xfazrin.my.id/api/transaction/create');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
    CURLOPT_POSTFIELDS => http_build_query([
        'method' => 'QRIS', 'merchant_ref' => $merchantRef, 'amount' => $amount,
        'customer_name' => 'Budi', 'customer_email' => 'budi@mail.com',
        'customer_phone' => '081234567890', 'signature' => $signature,
    ]),
]);
$res = json_decode(curl_exec($ch), true);
curl_close($ch);
$reference = $res['data']['reference']; // SIMPAN - kunci segalanya
Node.jsconst crypto = require('crypto');
const merchantCode = 'R39', merchantRef = 'INV-2026-0001', amount = '50000';
const signature = crypto.createHmac('sha256', process.env.RISAPAY_PRIVATE_KEY)
  .update(merchantCode + merchantRef + amount).digest('hex');

const body = new URLSearchParams({ method: 'QRIS', merchant_ref: merchantRef,
  amount, customer_name: 'Budi', signature });
const r = await fetch('https://risapay.xfazrin.my.id/api/transaction/create', {
  method: 'POST',
  headers: { 'Authorization': 'Bearer ' + process.env.RISAPAY_API_KEY },
  body });
const res = await r.json();
const reference = res.data.reference; // SIMPAN
cURLcurl -X POST "https://risapay.xfazrin.my.id/api/transaction/create" \
  -H "Authorization: Bearer API_KEY_KAMU" \
  --data-urlencode "method=QRIS" \
  --data-urlencode "merchant_ref=INV-2026-0001" \
  --data-urlencode "amount=50000" \
  --data-urlencode "customer_name=Budi" \
  --data-urlencode "signature=HASH_HMAC_KAMU"
VALID - Respons QRIS - HTTP 200{
    "success": true,
    "message": "Successfully generate transaction",
    "data": {
        "reference": "R1700000000XXXXX",
        "merchant_ref": "INV-2026-0001",
        "payment_method": "QRIS",
        "amount": 50000,
        "fee_merchant": 70,
        "fee_customer": 0,
        "total_fee": 70,
        "amount_received": 49930,
        "pay_code": null,
        "pay_url": null,
        "status": "UNPAID",
        "expired_time": 1700172800,
        "qr_string": "00020101..."
    }
}

QRIS → render qr_string jadi QR · VA → tampilin pay_code · e-wallet → redirect ke pay_url · atau lempar semua ke {base}checkout/?page={reference}.

VALID - Respons VA - field yang beda{
    "success": true,
    "data": {
        "reference": "R1700000000XXXXX",
        "payment_method": "BRIVA",
        "payment_name": "BRI Virtual Account",
        "amount": 50000,
        "fee_merchant": 3250,
        "amount_received": 46750,
        "pay_code": "88810123456789",
        "status": "UNPAID",
        "expired_time": 1700086400
    }
}
GAGAL - HTTP 200{
    "success": false,
    "message": "Invalid signature"
}
Semua logic error = HTTP 200 + success:false. Satu-satunya HTTP non-200 itu 429 pas kena rate-limit (> 60 req/menit/IP). Full list di section Error.

5 Cek Status

Buat polling & rekon. Cuma transaksi milik api_key itu yang kebaca.

GEThttps://risapay.xfazrin.my.id/api/transaction/detail?reference={reference}
cURLcurl "https://risapay.xfazrin.my.id/api/transaction/detail?reference=R1700000000XXXXX" \
  -H "Authorization: Bearer API_KEY_KAMU"
VALID - HTTP 200{
    "success": true,
    "message": "Transaction found",
    "data": {
        "reference": "R1700000000XXXXX",
        "merchant_ref": "INV-2026-0001",
        "payment_method": "QRIS",
        "amount": "10000",
        "status": "UNPAID",
        "paid_at": null,
        "expired_time": "1700172800",
        "qr_string": "00020101...",
        "checkout_url": "https://..."
    }
}

paid_at = unix timestamp pas lunas, null kalau belum. checkout_url itu alias dari pay_url.

GAGAL{ "success": false, "message": "Transaction not found" }
{ "success": false, "message": "Invalid API Key" }

6 OVO Push (2 langkah)

Flow khusus OVO: create dulu, baru push bill ke HP user.

① POST api/transaction/create dengan method=OVO → dapet reference.
② Tanpa Authorization:

POSThttps://risapay.xfazrin.my.id/api/ovo-payment/process.php
Formreference=R1700000000XXXXX&ovo_number=0812xxxx
VALID{ "status": "PAID", "message": "Periksa aplikasi OVO Anda" }
GAGAL{ "status": "GAGAL", "message": "Gagal update ke database" }
{ "status": "GAGAL", "message": "Server Error 500 ..." }

7 Callback ke Merchant

Wajib implement. Auto-retry 3x kalau respons bukan 200.

POST{callback_url}  ·  Content-Type: application/json  ·  X-Callback-Signature  ·  X-Callback-Event: payment_status
VALID - Payload (14 field){
    "reference": "R1715094140S41FP",
    "merchant_ref": "Q3123660",
    "payment_method": "QRIS",
    "payment_method_code": "QRIS",
    "total_amount": 117,
    "fee_merchant": 0,
    "fee_customer": 0,
    "total_fee": 0,
    "amount_received": 117,
    "is_closed_payment": 1,
    "status": "PAID",
    "paid_at": 1715094192,
    "note": "Transaksi sukses"
}
Verifikasi - PHP$raw = file_get_contents('php://input');
$sig = $_SERVER['HTTP_X_CALLBACK_SIGNATURE'] ?? '';
$calc = hash_hmac('sha256', $raw, $privateKeyAnda);
if (!hash_equals($calc, $sig)) { http_response_code(403); exit; }
$data = json_decode($raw, true);
// cocokkan merchant_ref + total_amount, tandai lunas per $data['reference'] (idempoten!)
http_response_code(200);
Verifikasi - Node.js// butuh express.raw({ type: 'application/json' }) agar dapat Buffer mentah
const sig = req.headers['x-callback-signature'] || '';
const calc = crypto.createHmac('sha256', process.env.RISAPAY_PRIVATE_KEY)
  .update(req.body).digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(calc), Buffer.from(sig)))
  return res.sendStatus(403);
const data = JSON.parse(req.body.toString());
// ... tandai lunas per data.reference (idempoten)
res.sendStatus(200);
Verify dari raw body, jangan parse-encode ulang (urutan key bisa beda). Callback bisa double, jadi harus idempotent by reference. Non-200 = di-retry (maks 3x, timeout 10 dtk).

8 Referensi Error

Komplet, semua message diambil langsung dari code.

MessageHTTPBetulkan
Maintenance200Coba lagi nanti
Header Authorization tidak ada dalam permintaan200Header tidak terkirim (cek proxy)
Invalid Header Authorization/tidak sesuai format200Harus persis Bearer <key>
Rate limit terlampaui. Coba lagi sebentar.429> 60 req/menit/IP - kurangi frekuensi
Invalid API Key200Key salah / sudah regenerate
Invalid parameter permintaan200Keempatnya hilang: method+ref+amount+signature
method / merchant_ref / amount / signature tidak ada dalam permintaan200Parameter tsb tidak dikirim
Invalid method200Kode channel salah ketik
Invalid signature200Cek rumus, urutan, string mentah & private_key
merchant_ref sudah digunakan (ref: …, status: …)200Pakai merchant_ref baru yang unik
Invalid amount200Bukan angka / ≤ 0
Method tidak aktif200Channel dimatikan admin
Minimum payment amount is …200Di bawah minimum channel
Maximum payment amount is Rp …200Di atas maksimum - pecah transaksi
Server Error …200Provider hulu error - coba lagi
Error database, mohon melaporkan pada Admin200Hubungi RisaPay
Transaction not found200Reference bukan milik api_key ini

9 Status & Masa Berlaku

Lifecycle satu transaksi.

UNPAID→PAID/EXPIRED/FAILED/REFUND

expired_time default 24 jam (VA) / 48 jam (lainnya), bisa di-override manual. Jangan mark paid dari return page, cuma dari verified callback atau detail = PAID.

10 Channel & Biaya (live dari database)

22 channel aktif.

MethodNamaMinMaxFee
ASTRAPAY AstraPay 1 9.800.000 2%
linkaja LinkAja 100 10.000.000 2%
qris2x QRIS2X 100 20.000.000 1%
shopeepay ShopeePay 100 20.000.000 2%
ALFAMART Alfamart 10.000 10.000.000 Rp 3.000
AGVA Artha Graha Virtual Account 10.000 20.000.000 Rp 3.000
ATMBVA ATM Bersama Virtual Account 10.000 20.000.000 Rp 3.250
BNCVA BNC Virtual Account 10.000 20.000.000 Rp 3.250
BNIVA BNI Virtual Account 10.000 20.000.000 Rp 3.250
BRIVA BRI Virtual Account 10.000 20.000.000 Rp 3.250
CIMBVA CIMB Niaga Virtual Account 10.000 20.000.000 Rp 3.250
dana Dana 1 9.800.000 2%
MANDIRIVA Mandiri Virtual Account 10.000 20.000.000 Rp 4.250
MYBVA Maybank Virtual Account 10.000 20.000.000 Rp 3.250
ovo OVO 1 10.000.000 3%
PERMATAVA Permata Virtual Account 10.000 20.000.000 Rp 3.250
qris QRIS 1 10.000.000 0,7%
qris2 QRIS2 1 10.000.000 0,7%
qrisc QRISC 1 10.000.000 0,7%
qris_shopeepay QRIS_SHOPEEPAY 1 10.000.000 0,7%
BCAVA BCA Virtual Account 5.000 20.000.000 Rp 4.500
qrisi QRISI 1 10.000.000 0,7%

↓ Unduhan

Start tanpa ngetik dari nol.

Import Postman → isi environment base_url, api_key, merchant_code, private_key - signature & merchant_ref auto-generate. Paste risapay-api.md ke AI favoritmu, langsung paham full flow.