Skip to main content

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

HeaderRequiredDescription
X-API-KeyYesYour merchant API key
Content-TypeYesapplication/json
Idempotency-KeyRecommendedUnique key to prevent duplicate orders on retry
X-SignatureNoHMAC-SHA256 of the request body (if webhook_secret is configured)

Body

FieldTypeRequiredDescription
merchant_order_idstringYesYour unique order identifier (max 255 chars)
amount_minorintegerYesOrder amount in minor units (min: 1). IDR 10,000 = 1000000
payment_methodstringYesPayment channel: QRIS or BANK_TRANSFER
customer_namestringNoCustomer's full name
customer_emailstringNoCustomer's email address
customer_phonestringNoCustomer's phone number (normalized to 62xxxxxxxxx)
notify_urlstringNoWebhook URL for status updates (overrides merchant default)
return_urlstringNoRedirect URL after payment completion
expire_minutesintegerNoOrder TTL in minutes (default: 60). Use 15 for QRIS, up to 1440 for bank transfer
metadataobjectNoArbitrary 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

FieldDescription
ref_codePGA reference code — use this to poll status and in support requests
qris_stringRaw QRIS data string — render this as a QR code in your UI
qr_urlPre-rendered QR image URL (PNG)
expires_atISO 8601 timestamp when the order expires; null if no expiry
paid_atISO 8601 timestamp of payment; null until payment is confirmed

Error Codes

CodeHTTPDescription
INVALID_BODY400Malformed JSON or missing required field
INVALID_SIGNATURE401X-Signature does not match
DUPLICATE_ORDER409merchant_order_id already exists
NO_VENDOR503No payment gateway configured for payment_method
VENDOR_ERROR503All 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.