Skip to main content

Errors

Error Response Shape​

All errors return a JSON body with a machine-readable code and a human-readable message:

{
"success": false,
"error": {
"code": "INVALID_BODY",
"message": "amount is required and must be a positive integer"
}
}

Error Codes​

Authentication​

CodeHTTPDescription
UNAUTHORIZED401Missing or invalid X-API-Key
INVALID_SIGNATURE401X-Signature header does not match computed HMAC
MERCHANT_INACTIVE403Merchant account is suspended or disabled

Request Validation​

CodeHTTPDescription
INVALID_BODY400Malformed JSON or missing required field
INVALID_JSON400Request body is not valid JSON
UNSUPPORTED_PAYMENT_METHOD400V1 order creation accepts QRIS only
IDEMPOTENCY_KEY_REUSED400The key was reused with a different raw request body
MERCHANT_ORDER_ID_REUSED400The same merchant order ID was used with a different amount
INVALID_ID400Path parameter is not a valid UUID

Orders​

CodeHTTPDescription
ORDER_PENDING_CONFIRMATION409Existing order's gateway result is unresolved; reconcile before another attempt
ORDER_NOT_FOUND404No order found with the given ref_code
INVALID_STATUS422Operation not allowed for the order's current status (e.g., refunding a non-PAID order)
AMOUNT_EXCEEDS_ORDER422Refund amount is greater than the remaining refundable amount
NO_VENDOR503No payment gateway is configured or available for this payment method
VENDOR_ERROR503All configured payment gateways returned errors

Disbursements​

CodeHTTPDescription
NOT_WALLET_MERCHANT403Merchant's settlement type is not WALLET; disbursements not available
BANK_NOT_FOUND400bank_short_code does not match any active bank
BANK_DISABLED422Bank exists but is not enabled for disbursement
MISSING_BANK_INFO400account_number or account_name is missing for a BANK channel
MISSING_EWALLET_INFO400ewallet_provider or ewallet_phone is missing for an EWALLET channel
INSUFFICIENT_BALANCE422Wallet balance is less than the requested amount plus the Rupiah fee
AMOUNT_EXCEEDS_LIMIT422Single transaction amount exceeds the per-transaction limit
DAILY_LIMIT_EXCEEDED422Daily disbursement total would exceed the daily limit
DUPLICATE_IDEMPOTENCY_KEY409A disbursement with this idempotency_key already exists
DISBURSEMENT_NOT_FOUND404No disbursement found with the given identifier

Beneficiaries​

CodeHTTPDescription
BENEFICIARY_NOT_FOUND404No beneficiary found with the given ID

Handling Errors​

Node.js — error handling pattern
const res = await fetch('https://api.flypay.asia/v1/orders', {
method: 'POST',
headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
});

const body = await res.json();

if (!body.success) {
console.error(`[${body.error.code}] ${body.error.message}`);
// Handle specific codes:
if (['ORDER_PENDING_CONFIRMATION', 'VENDOR_ERROR'].includes(body.error.code)) {
// Query GET /v1/orders?merchant_order_id=<your-id> before any retry.
}
}
tip

Always branch on error.code, not HTTP status alone. Multiple distinct business errors share the same HTTP status (e.g., 400).