Error Codes
Every NaafiPay API error returns the same JSON envelope, with a stable error.code string you can switch on in your application. HTTP status codes follow standard semantics: 4xx for client errors, 5xx for server errors. This page lists every error code the API can emit, what it means, and what action you (or your customer) need to take to resolve it. Use these codes — not the human-readable messages — when deciding how your application should react.
Error envelope
Error
1{2 "error": {3 "code": "invalid_amount",4 "message": "The amount must be greater than 0.",5 "status": 400,6 "param": "amount"7 }8}Authentication errors (401)
| Field | Type | Required | Description |
|---|---|---|---|
| unauthorized | 401 | optional | API key is missing or malformed. |
| invalid_key | 401 | optional | API key was revoked or never existed. |
| test_mode_only | 401 | optional | Live key required for this operation, or vice versa. |
Authorisation errors (403)
| Field | Type | Required | Description |
|---|---|---|---|
| wrong_storefront | 403 | optional | Resource belongs to a different storefront. |
| permission_denied | 403 | optional | API key role does not allow this action. |
| kyc_required | 403 | optional | Live payments are blocked until KYC is approved. |
Validation errors (400)
| Field | Type | Required | Description |
|---|---|---|---|
| invalid_amount | 400 | optional | Amount is missing, zero, negative, or above the max. |
| invalid_currency | 400 | optional | Currency is not BDT. |
| invalid_url | 400 | optional | success_url, cancel_url, or webhook_url is not a valid HTTPS URL. |
| invalid_email | 400 | optional | Email is missing or not a valid address. |
| missing_field | 400 | optional | A required field is missing. error.param tells you which. |
| invalid_status | 400 | optional | Status filter must be one of the documented values. |
| invalid_date | 400 | optional | date_from or date_to is not a valid ISO 8601 timestamp. |
| invalid_plan | 400 | optional | plan_id does not exist or is archived. |
| already_paid | 400 | optional | Cannot cancel an invoice that is already completed. |
| already_cancelled | 400 | optional | Cannot cancel an invoice that is already cancelled. |
Not found (404)
| Field | Type | Required | Description |
|---|---|---|---|
| not_found | 404 | optional | The resource does not exist. |
Rate limiting (429)
| Field | Type | Required | Description |
|---|---|---|---|
| rate_limited | 429 | optional | Too many requests in the current window. Read the Retry-After header. |
Server errors (5xx)
| Field | Type | Required | Description |
|---|---|---|---|
| internal_error | 500 | optional | Unexpected error on our side. Safe to retry with exponential backoff. |
| upstream_unavailable | 502 | optional | An upstream provider (bKash, Nagad, card processor) is temporarily unavailable. |
| gateway_timeout | 504 | optional | Upstream provider did not respond in time. Safe to retry. |
TipSwitch on error.code, not error.message
We may rephrase
error.message for clarity in the future without warning. error.code values are stable and safe to depend on.WarningRetry only on 5xx and 429
4xx errors (other than 429) indicate a problem with your request. Retrying without changing the request will produce the same error.