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_minor is required and must be a positive integer"
}
}
Error Codes
Authentication
| Code | HTTP | Description |
|---|---|---|
UNAUTHORIZED | 401 | Missing or invalid X-API-Key |
INVALID_SIGNATURE | 401 | X-Signature header does not match computed HMAC |
MERCHANT_INACTIVE | 403 | Merchant account is suspended or disabled |
Request Validation
| Code | HTTP | Description |
|---|---|---|
INVALID_BODY | 400 | Malformed JSON or missing required field |
INVALID_ID | 400 | Path parameter is not a valid UUID |
Orders
| Code | HTTP | Description |
|---|---|---|
DUPLICATE_ORDER | 409 | merchant_order_id already exists for this merchant |
ORDER_NOT_FOUND | 404 | No order found with the given ref_code |
INVALID_STATUS | 422 | Operation not allowed for the order's current status (e.g., refunding a non-PAID order) |
AMOUNT_EXCEEDS_ORDER | 422 | Refund amount is greater than the remaining refundable amount |
NO_VENDOR | 503 | No payment gateway is configured or available for this payment method |
VENDOR_ERROR | 503 | All configured payment gateways returned errors |
Disbursements
| Code | HTTP | Description |
|---|---|---|
NOT_WALLET_MERCHANT | 403 | Merchant's settlement type is not WALLET; disbursements not available |
BANK_NOT_FOUND | 400 | bank_short_code does not match any active bank |
BANK_DISABLED | 422 | Bank exists but is not enabled for disbursement |
MISSING_BANK_INFO | 400 | account_number or account_name is missing for a BANK channel |
MISSING_EWALLET_INFO | 400 | ewallet_provider or ewallet_phone is missing for an EWALLET channel |
INSUFFICIENT_BALANCE | 422 | Wallet balance is less than amount_minor + fee_minor |
AMOUNT_EXCEEDS_LIMIT | 422 | Single transaction amount exceeds the per-transaction limit |
DAILY_LIMIT_EXCEEDED | 422 | Daily disbursement total would exceed the daily limit |
DUPLICATE_IDEMPOTENCY_KEY | 409 | A disbursement with this idempotency_key already exists |
DISBURSEMENT_NOT_FOUND | 404 | No disbursement found with the given identifier |
Beneficiaries
| Code | HTTP | Description |
|---|---|---|
BENEFICIARY_NOT_FOUND | 404 | No beneficiary found with the given ID |
Handling Errors
Node.js — error handling pattern
const res = await fetch('https://api.nusio-saka.com/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 (body.error.code === 'DUPLICATE_ORDER') {
// Idempotent — safe to return the existing order ref
}
if (body.error.code === 'VENDOR_ERROR') {
// All gateways failed — retry after a short delay
}
}
tip
Always branch on error.code, not HTTP status alone. Multiple distinct business errors share the same HTTP status (e.g., 400).