Quick Start (5 Minutes)
This guide walks you through accepting your first QRIS payment using the V1 API.
Prerequisites
- An active merchant account (Nusio Saka or Flypay)
- Your API key from the merchant dashboard: Settings → API Credentials
- A server that can receive HTTP POST requests (for webhooks)
Step 1: Create an Order
Send a POST to /v1/orders with your item amount and customer details.
cURL
curl -X POST https://api.nusio-saka.com/v1/orders \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-$(date +%s)" \
-d '{
"merchant_order_id": "INV-001",
"amount_minor": 5000000,
"payment_method": "QRIS",
"customer_name": "Budi Santoso",
"notify_url": "https://your-site.com/webhooks/payment",
"expire_minutes": 15
}'
amount_minor: 5000000 = IDR 50,000 (100 minor units per 1 IDR).
Response:
{
"success": true,
"data": {
"ref_code": "ORD-260601103045-A1B2",
"status": "PENDING",
"qris_string": "00020101021226...",
"qr_url": "https://cdn.nusio-saka.com/qr/ORD-260601103045-A1B2.png",
"expires_at": "2026-06-01T10:45:45Z"
}
}
Step 2: Display the QR Code
Render qris_string as a QR code in your checkout UI, or display qr_url as an image:
<!-- Simple: use the pre-rendered image -->
<img src="https://cdn.nusio-saka.com/qr/ORD-260601103045-A1B2.png" alt="Scan to Pay" width="300" />
JavaScript — render QRIS string with a library
import QRCode from 'qrcode';
const canvas = document.getElementById('qr-canvas');
await QRCode.toCanvas(canvas, data.qris_string, { width: 300 });
The QR code is valid until expires_at. Show a countdown timer and disable payment after expiry.
Step 3: Receive the Payment Webhook
When the customer pays, the system POSTs to your notify_url:
{
"event": "order.PAID",
"ref_code": "ORD-260601103045-A1B2",
"merchant_order_id": "INV-001",
"amount_minor": 5000000,
"currency": "IDR",
"status": "PAID",
"paid_at": "2026-06-01T10:38:12Z"
}
Your handler must return HTTP 200. Process the event asynchronously:
PHP — webhook handler
<?php
$rawBody = file_get_contents('php://input');
// Optional: verify signature
$webhookSecret = getenv('WEBHOOK_SECRET');
if ($webhookSecret) {
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $webhookSecret);
if (!hash_equals($expected, $_SERVER['HTTP_X_SIGNATURE'] ?? '')) {
http_response_code(401);
exit;
}
}
// Acknowledge immediately
http_response_code(200);
echo json_encode(['received' => true]);
if (function_exists('fastcgi_finish_request')) fastcgi_finish_request();
$payload = json_decode($rawBody, true);
if ($payload['status'] === 'PAID') {
$orderId = $payload['merchant_order_id']; // your INV-001
// mark order as paid in your database
// trigger fulfillment
}
Step 4: Poll for Status (Optional Fallback)
If your webhook endpoint was unavailable, poll the order:
cURL
curl https://api.nusio-saka.com/v1/orders/ORD-260601103045-A1B2 \
-H "X-API-Key: YOUR_API_KEY"
Check data.status: PAID = success, EXPIRED/FAILED = unsuccessful.