Create Order
Merchant membuat order di sistem sendiri dan menentukan nominal pembayaran.
Sign Request
Backend merchant membuat HMAC signature dari timestamp dan raw JSON body memakai API Secret.
Create Transaction
Kirim request ke RouterPay API untuk mendapatkan payment URL.
Redirect Customer
Customer diarahkan ke payment page RouterPay untuk memilih channel.
Webhook Final
RouterPay mengirim status transaksi ke endpoint merchant; validasi memakai Webhook Secret.
Reconcile
Merchant mencocokkan status order, transaksi, settlement, dan audit log.
Ambil credential dari detail merchant.
Di dashboard member, buka Merchant → Detail → API Keys & Webhook. Tampilan baru memisahkan credential agar integrasi tidak rancu:
Credential API — untuk membuat transaksi
API Key dikirim di header X-RouterPay-Key. API Secret dipakai backend merchant untuk signature request API.
Credential Webhook — untuk menerima callback
Webhook Secret dipakai untuk memvalidasi callback RouterPay. Secret ini berbeda fungsi dari API Secret.
Semua request API wajib ditandatangani.
RouterPay menggunakan kombinasi Merchant Code, API Key, timestamp, dan HMAC SHA-256 signature. API Key dikirim di header X-RouterPay-Key. API Secret tidak dikirim dalam request; secret hanya dipakai di server merchant untuk membuat signature request API.
- ✓Gunakan HTTPS dan simpan credential di environment variable.
- ✓Timestamp request berlaku terbatas untuk mengurangi risiko replay.
- ✓Gunakan Idempotency-Key saat retry create transaction.
X-RouterPay-Merchant: {merchant_code}
X-RouterPay-Key: {api_key}
X-RouterPay-Timestamp: {unix_timestamp}
X-RouterPay-Signature: {hmac_sha256}
Idempotency-Key: {unique_retry_key_optional}
Content-Type: application/json
Signature request API: hash_hmac('sha256', timestamp + '.' + raw_json_body, api_secret). Ambil API Key dan API Secret dari kartu Credential API di detail merchant.
Buat invoice pembayaran dan dapatkan payment URL.
Endpoint ini membuat transaksi RouterPay. Setelah response berhasil, arahkan customer ke payment_url. Jangan mengandalkan redirect browser sebagai status final; gunakan webhook atau status check.
POST https://api.routerpay.co.id/api/v1/transactions
{
"merchant_ref": "INV-001",
"amount": 150000,
"currency": "IDR",
"payment_method": "qris",
"auto_provider": true,
"customer_name": "Budi",
"customer_email": "budi@example.com",
"customer_phone": "081234567890",
"return_url": "https://merchant.example/orders/INV-001",
"success_url": "https://merchant.example/orders/INV-001/success",
"failed_url": "https://merchant.example/orders/INV-001/failed",
"metadata": {"cart_id":"CART-001"}
}
Data penting yang perlu disimpan merchant.
{
"ok": true,
"data": {
"reference": "RP260518ABC123",
"merchant_ref": "INV-001",
"status": "pending",
"amount": 150000,
"fee_amount": 0,
"payable_amount": 150000,
"net_amount": 150000,
"payment_url": "https://routerpay.co.id/pay/{uuid}",
"expires_at": "2026-05-18T07:00:00+08:00"
}
}
Cek transaksi saat webhook terlambat.
GET https://api.routerpay.co.id/api/v1/transactions/{reference}
GET https://api.routerpay.co.id/api/v1/transactions/{merchant_ref}
Gunakan status check untuk rekonsiliasi, halaman order, atau fallback bila webhook merchant gagal sementara.
Catatan fee: amount adalah nominal invoice merchant, fee_amount adalah fee channel yang dibayar pembeli, payable_amount adalah total bayar pembeli, dan net_amount adalah nominal diterima merchant. Merchant tidak menanggung fee channel.
Contoh create transaction dari backend merchant.
$merchantCode = env('ROUTERPAY_MERCHANT_CODE');
$apiKey = env('ROUTERPAY_API_KEY');
$apiSecret = env('ROUTERPAY_API_SECRET');
$payload = [
'merchant_ref' => 'INV-'.time(),
'amount' => 150000,
'customer_name' => 'Budi',
'customer_email' => 'budi@example.com',
'return_url' => 'https://merchant.example/orders/INV-001',
];
$body = json_encode($payload, JSON_UNESCAPED_SLASHES);
$timestamp = (string) time();
$signature = hash_hmac('sha256', $timestamp.'.'.$body, $apiSecret);
$response = Http::withHeaders([
'X-RouterPay-Merchant' => $merchantCode,
'X-RouterPay-Key' => $apiKey,
'X-RouterPay-Timestamp' => $timestamp,
'X-RouterPay-Signature' => $signature,
'Idempotency-Key' => $payload['merchant_ref'],
'Content-Type' => 'application/json',
])->withBody($body, 'application/json')
->post('https://api.routerpay.co.id/api/v1/transactions')
->throw()
->json();
return redirect()->away($response['data']['payment_url']);
import crypto from 'crypto';
const payload = {
merchant_ref: `INV-${Date.now()}`,
amount: 150000,
customer_name: 'Budi',
};
const body = JSON.stringify(payload);
const timestamp = Math.floor(Date.now() / 1000).toString();
const signature = crypto
.createHmac('sha256', process.env.ROUTERPAY_API_SECRET)
.update(`${timestamp}.${body}`)
.digest('hex');
const res = await fetch('https://api.routerpay.co.id/api/v1/transactions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-RouterPay-Merchant': process.env.ROUTERPAY_MERCHANT_CODE,
'X-RouterPay-Key': process.env.ROUTERPAY_API_KEY,
'X-RouterPay-Timestamp': timestamp,
'X-RouterPay-Signature': signature,
'Idempotency-Key': payload.merchant_ref,
},
body,
});
$body = json_encode($payload, JSON_UNESCAPED_SLASHES);
$timestamp = (string) time();
$signature = hash_hmac('sha256', $timestamp.'.'.$body, $apiSecret);
$ch = curl_init('https://api.routerpay.co.id/api/v1/transactions');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'X-RouterPay-Merchant: '.$merchantCode,
'X-RouterPay-Key: '.$apiKey,
'X-RouterPay-Timestamp: '.$timestamp,
'X-RouterPay-Signature: '.$signature,
'Idempotency-Key: '.$payload['merchant_ref'],
],
]);
$response = json_decode(curl_exec($ch), true);
Update order dari webhook, bukan dari redirect browser.
Webhook dikirim saat status transaksi berubah. Merchant wajib memverifikasi signature dan timestamp sebelum memproses payload. Gunakan Webhook Secret dari kartu Credential Webhook, bukan API Secret.
Header Webhook
X-RouterPay-Webhook-Timestamp: {unix_timestamp}
X-RouterPay-Webhook-Signature: {hmac_sha256}Signature webhook: hash_hmac('sha256', timestamp + '.' + raw_body, webhook_secret).
Payload
{
"event": "transaction.paid",
"reference": "RP260518ABC123",
"merchant_ref": "INV-001",
"status": "paid",
"amount": 150000,
"fee_amount": 570,
"payable_amount": 150570,
"net_amount": 150000,
"payment_method": "qris"
}Route::post('/webhook/routerpay', function (Request $request) {
$secret = env('ROUTERPAY_WEBHOOK_SECRET');
$timestamp = $request->header('X-RouterPay-Webhook-Timestamp');
$signature = $request->header('X-RouterPay-Webhook-Signature');
$raw = $request->getContent();
if (! $timestamp || abs(time() - (int) $timestamp) > 300) abort(401);
$expected = hash_hmac('sha256', $timestamp.'.'.$raw, $secret);
if (! hash_equals($expected, (string) $signature)) abort(401);
$payload = json_decode($raw, true);
// update order by merchant_ref + status
return response()->json(['ok' => true]);
});
- ✓Simpan
referenceRouterPay danmerchant_refinternal. - ✓Gunakan
Idempotency-Keysaat retry create transaction. - ✓Jangan expose API Secret maupun Webhook Secret di frontend/mobile app.
- ✓Verifikasi webhook memakai signature, timestamp, dan Webhook Secret.
- ✓Pastikan update order idempotent agar webhook dobel tetap aman.
Coba alur end-to-end tanpa coding dulu.
Demo merchant membuat order, memanggil API RouterPay, redirect ke payment page, dan menerima webhook status transaksi.