Errors
JKAPay uses standard HTTP status codes and returns a structured JSON body for every error. Always inspect the body rather than relying on status alone.
Error envelope
JSON
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request",
"details": {
"fieldErrors": {
"customer.msisdn": ["Required"]
}
}
}
}Error codes
| Status | Code | Meaning |
|---|---|---|
| 400 | VALIDATION_ERROR | The request body or query failed validation. Inspect error.details for field-level info. |
| 401 | UNAUTHENTICATED | Missing, malformed, or revoked API key. |
| 403 | FORBIDDEN | Authenticated but not allowed — e.g. merchant is SUSPENDED, or insufficient role. |
| 404 | NOT_FOUND | Resource doesn't exist or doesn't belong to your merchant. |
| 409 | CONFLICT | Resource state conflict — e.g. duplicate email at registration. |
| 429 | RATE_LIMITED | Too many requests. Back off and retry with exponential delay. |
| 502 | PROVIDER_ERROR | A mobile network or bank returned an error or was unreachable. Safe to retry. |
| 500 | INTERNAL | Unexpected server error. Report to support with the request ID if it persists. |
Retry strategy
- Safe to retry:
429,502,503, network timeouts. - Do NOT retry without an idempotency key: any
POSTthat creates resources. PassidempotencyKeyon every write so retries are safe. - Do not retry:
400,401,403,404,409— fix the request first.
For retries, use exponential backoff: start at 1s, double each attempt, cap at 30s, give up after 5 attempts.