Create Order
Create a new payment order. The response includes a QRIS string and QR image URL for QRIS payments.
Endpoint
POST /v1/orders
Request
Headers
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Your merchant API key |
Content-Type | Yes | application/json |
Idempotency-Key | Recommended | Unique key to prevent duplicate orders on retry |
X-Signature | No | HMAC-SHA256 of the request body (if webhook_secret is configured) |
Body
| Field | Type | Required | Description |
|---|---|---|---|
merchant_order_id | string | Yes | Your unique order identifier (max 255 chars) |
amount_minor | integer | Yes | Order amount in minor units (min: 1). IDR 10,000 = 1000000 |
payment_method | string | Yes | Payment channel: QRIS or BANK_TRANSFER |
customer_name | string | No | Customer's full name |
customer_email | string | No | Customer's email address |
customer_phone | string | No | Customer's phone number (normalized to 62xxxxxxxxx) |
notify_url | string | No | Webhook URL for status updates (overrides merchant default) |
return_url | string | No | Redirect URL after payment completion |
expire_minutes | integer | No | Order TTL in minutes (default: 60). Use 15 for QRIS, up to 1440 for bank transfer |
metadata | object | No | Arbitrary JSON object stored and returned as-is |
Example Request
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-2026060100123" \
-d '{
"merchant_order_id": "INV-2026-00123",
"amount_minor": 5000000,
"payment_method": "QRIS",
"customer_name": "Budi Santoso",
"customer_phone": "08123456789",
"notify_url": "https://your-site.com/webhooks/payment",
"expire_minutes": 15,
"metadata": { "product_id": "SKU-001", "cart_id": "cart-xyz" }
}'
PHP
$payload = [
'merchant_order_id' => 'INV-2026-00123',
'amount_minor' => 5000000,
'payment_method' => 'QRIS',
'customer_name' => 'Budi Santoso',
'customer_phone' => '08123456789',
'notify_url' => 'https://your-site.com/webhooks/payment',
'expire_minutes' => 15,
];
$ch = curl_init('https://api.nusio-saka.com/v1/orders');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-API-Key: ' . $apiKey,
'Content-Type: application/json',
'Idempotency-Key: order-2026060100123',
],
CURLOPT_POSTFIELDS => json_encode($payload),
]);
$response = json_decode(curl_exec($ch), true);
Node.js
const response = await fetch('https://api.nusio-saka.com/v1/orders', {
method: 'POST',
headers: {
'X-API-Key': apiKey,
'Content-Type': 'application/json',
'Idempotency-Key': 'order-2026060100123',
},
body: JSON.stringify({
merchant_order_id: 'INV-2026-00123',
amount_minor: 5000000,
payment_method: 'QRIS',
customer_name: 'Budi Santoso',
customer_phone: '08123456789',
notify_url: 'https://your-site.com/webhooks/payment',
expire_minutes: 15,
}),
});
const data = await response.json();
Response
HTTP 201 Created
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"ref_code": "ORD-260601103045-A1B2",
"merchant_order_id": "INV-2026-00123",
"amount_minor": 5000000,
"currency_code": "IDR",
"status": "PENDING",
"qris_string": "00020101021226...",
"qr_url": "https://cdn.nusio-saka.com/qr/ORD-260601103045-A1B2.png",
"expires_at": "2026-06-01T10:45:45Z",
"paid_at": null,
"is_settled": false,
"vendor_rrn": null,
"customer_name": "Budi Santoso",
"customer_phone": "6281234567890",
"created_at": "2026-06-01T10:30:45Z"
}
}
Response Fields
| Field | Description |
|---|---|
ref_code | PGA reference code — use this to poll status and in support requests |
qris_string | Raw QRIS data string — render this as a QR code in your UI |
qr_url | Pre-rendered QR image URL (PNG) |
expires_at | ISO 8601 timestamp when the order expires; null if no expiry |
paid_at | ISO 8601 timestamp of payment; null until payment is confirmed |
Error Codes
| Code | HTTP | Description |
|---|---|---|
INVALID_BODY | 400 | Malformed JSON or missing required field |
INVALID_SIGNATURE | 401 | X-Signature does not match |
DUPLICATE_ORDER | 409 | merchant_order_id already exists |
NO_VENDOR | 503 | No payment gateway configured for payment_method |
VENDOR_ERROR | 503 | All configured gateways failed |
Handling DUPLICATE_ORDER
DUPLICATE_ORDER is safe to treat as a success — the response contains the existing order. Your Idempotency-Key header prevents this entirely on retries.