Developer Guide

Dokumentasi Integrasi API

Panduan lengkap integrasi RouterPay dengan pemisahan Credential API dan Credential Webhook: HMAC request, create transaction, payment URL, status check, signed webhook, idempotency, contoh kode Laravel/PHP/Node.js, dan praktik produksi.

1 APIMulti provider
24/7Webhook & audit log
RealtimeStatus transaksi
Checkout, API, webhook, settlement, dan dashboard operasional dalam satu platform.
Didesain untuk merchant Indonesia: QRIS, VA, e-wallet, retail, dan routing provider.
Kontrol admin, audit trail, dan monitoring untuk membantu operasional tetap rapi.
01

Create Order

Merchant membuat order di sistem sendiri dan menentukan nominal pembayaran.

02

Sign Request

Backend merchant membuat HMAC signature dari timestamp dan raw JSON body memakai API Secret.

03

Create Transaction

Kirim request ke RouterPay API untuk mendapatkan payment URL.

04

Redirect Customer

Customer diarahkan ke payment page RouterPay untuk memilih channel.

05

Webhook Final

RouterPay mengirim status transaksi ke endpoint merchant; validasi memakai Webhook Secret.

06

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:

API

Credential API — untuk membuat transaksi

API Key dikirim di header X-RouterPay-Key. API Secret dipakai backend merchant untuk signature request API.

WH

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 reference RouterPay dan merchant_ref internal.
  • Gunakan Idempotency-Key saat 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.