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-SignatureConditionalRequired if your merchant has a webhook secret configured; HMAC-SHA256 of the exact raw request body

Body​

FieldTypeRequiredDescription
merchant_order_idstringYesYour unique order identifier (max 255 chars)
amountintegerYesWhole-Rupiah order amount (min: 1). IDR 10,000 = 10000
payment_methodstringYesQRIS only. Bank-transfer order creation is not supported by V1.
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); 15 is a practical QRIS choice
metadataobjectNoArbitrary JSON object stored and returned as-is

Example Request​

cURL
curl -X POST https://api.flypay.asia/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": 50000,
"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' => 50000,
'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.flypay.asia/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.flypay.asia/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: 50000,
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": 50000,
"status": "PENDING",
"qris_string": "00020101021226...",
"qr_url": "https://example.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_codeFlyPay 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_JSON / INVALID_BODY400Invalid JSON, missing merchant order ID, or nonpositive amount
UNSUPPORTED_PAYMENT_METHOD400Only QRIS is accepted
IDEMPOTENCY_KEY_REUSED400The same key was sent with a different raw request body
MERCHANT_ORDER_ID_REUSED400The merchant order ID was sent with a different amount
INVALID_SIGNATURE401X-Signature does not match
ORDER_PENDING_CONFIRMATION409An earlier create attempt may still be with a gateway; reconcile before another attempt
NO_VENDOR503No payment gateway configured for payment_method
VENDOR_ERROR503No gateway produced a usable order; check the original order before retrying
Safe retry sequence

Keep the same merchant_order_id, Idempotency-Key, and exact request body for a retry. The same key returns the cached original response (including HTTP 201); the same confirmed merchant order ID with a different key returns the existing order (HTTP 200). If you get ORDER_PENDING_CONFIRMATION, a timeout, or VENDOR_ERROR, query GET /v1/orders?merchant_order_id=<your-id> and wait for confirmation. Do not create a new merchant order ID or ask the customer to pay a second QR until the first attempt is reconciled.