Skip to main content

Error Codes Reference

Every AfriRoute API error returns a consistent JSON envelope with a machine-readable code, a human-readable message, and a request_id you can quote to support. This page lists the standard HTTP statuses and the full catalog of error codes.

📦 Error Envelope​

{
"success": false,
"error": {
"code": "INVALID_PHONE",
"message": "Phone number must be in E.164 format",
"details": "Received '0911234567', expected '+251911234567'",
"request_id": "req_xyz789",
"timestamp": "2026-05-10T12:30:00Z"
}
}

Always log request_id — it lets support trace a single request end to end.

🚦 HTTP Status Codes​

CodeStatusMeaning
200OKRequest succeeded
201CreatedResource created
400Bad RequestMalformed request or invalid parameter
401UnauthorizedMissing or invalid API key
403ForbiddenKey lacks permission for this resource
404Not FoundResource does not exist
409ConflictResource state conflict (e.g. duplicate)
413Payload Too LargeUploaded media exceeds the limit
422Unprocessable EntityValidation failed
429Too Many RequestsRate limit exceeded
500Internal Server ErrorUnexpected server error
503Service UnavailableDependency temporarily unavailable

🔑 Authentication & Authorization​

CodeHTTPDescription
MISSING_API_KEY401No Authorization header supplied
INVALID_API_KEY401Key is malformed, revoked, or unknown
EXPIRED_TOKEN401Bearer token has expired
FORBIDDEN_SCOPE403Key not authorized for this endpoint
IP_NOT_ALLOWED403Request IP not in the allowlist

⏱️ Rate Limiting & Quotas​

CodeHTTPDescription
RATE_LIMIT_EXCEEDED429Too many requests; see Retry-After header
QUOTA_EXCEEDED429Monthly plan quota reached
INSUFFICIENT_BALANCE402Wallet balance too low to complete the action

✉️ Messaging (SMS / Voice / Email)​

CodeHTTPDescription
INVALID_PHONE400Number is not valid E.164
INVALID_SENDER_ID400Sender ID not registered or malformed
MESSAGE_TOO_LONG422Message exceeds the segment limit
UNDELIVERABLE422Carrier could not deliver
UNSUPPORTED_COUNTRY422Destination country not supported

💰 Payments​

CodeHTTPDescription
INSUFFICIENT_FUNDS422Payer has insufficient funds
PAYMENT_DECLINED422Provider declined the transaction
INVALID_AMOUNT400Amount is zero, negative, or unsupported
DUPLICATE_TRANSACTION409A transaction with this reference already exists
PROVIDER_UNAVAILABLE503Mobile-money provider temporarily down

🪪 Identity Verification​

CodeHTTPDescription
INVALID_DOCUMENT_TYPE400Unsupported document_type for the country
IMAGE_QUALITY_LOW422Image too blurry, dark, or cropped
NO_FACE_DETECTED422No face found in the supplied image
MULTIPLE_FACES422More than one face detected
FACE_MISMATCH422Selfie does not match the document photo
LIVENESS_FAILED422Presentation attack detected
DOCUMENT_EXPIRED422Document past its expiry date
OTP_EXPIRED422OTP code has expired
OTP_INVALID422OTP code does not match
OTP_MAX_ATTEMPTS429Too many OTP attempts
REGISTRY_UNAVAILABLE503Government registry (BVN/Fayda/Ghana Card) unreachable

🔔 Webhooks​

CodeHTTPDescription
INVALID_URL400Webhook URL is not valid HTTPS
INVALID_EVENT400Unknown event type in subscription
WEBHOOK_NOT_FOUND404No webhook with that ID
WEBHOOK_LIMIT_REACHED422Plan webhook limit exceeded
WEBHOOK_TIMEOUT—Delivery timed out (>10s)
WEBHOOK_EXHAUSTED—All retry attempts failed

🛠️ Handling Errors (JavaScript)​

const res = await fetch(url, options);
if (!res.ok) {
const { error } = await res.json();
switch (error.code) {
case 'RATE_LIMIT_EXCEEDED':
await backoff(res.headers.get('Retry-After'));
break;
case 'INSUFFICIENT_BALANCE':
notifyBilling();
break;
default:
logError(error.request_id, error.message);
}
}

Last Updated: May 2026 | Need help? [email protected]