Error Codes
Complete reference of V2 API error codes and their meanings.
Error Codes
All V2 API errors follow a consistent format with machine-readable error codes.
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable description of the error.",
"details": {}
},
"meta": {
"request_id": "req_a1b2c3d4e5f6",
"timestamp": "2024-01-15T10:30:00.000Z"
}
}
Authentication Errors
| Code | HTTP Status | Description |
|---|
INVALID_API_KEY | 401 | API key is missing, malformed, or not recognized |
EXPIRED_API_KEY | 401 | API key has passed its expiration date |
REVOKED_API_KEY | 401 | API key has been revoked from the Enterprise Portal |
IP_NOT_ALLOWED | 403 | Request originated from an IP not in the key's allowlist |
INSUFFICIENT_PERMISSIONS | 403 | API key lacks the required permission for this endpoint |
Validation Errors
| Code | HTTP Status | Description |
|---|
INVALID_PHONE_NUMBER | 400 | Phone number format is invalid or unrecognizable |
MISSING_REQUIRED_FIELD | 400 | A required field is missing from the request body |
INVALID_AMOUNT | 400 | Amount is outside the allowed range for this network |
Network Errors
| Code | HTTP Status | Description |
|---|
NETWORK_NOT_FOUND | 404 | The specified network ID does not exist |
UNSUPPORTED_NETWORK | 400 | This network is not currently available for top-ups |
HLR_LOOKUP_FAILED | 400 | Network auto-detection failed. Try specifying network_id manually |
Transaction Errors
| Code | HTTP Status | Description |
|---|
TRANSACTION_NOT_FOUND | 404 | No transaction found with the given ID |
INSUFFICIENT_BALANCE | 400 | Wallet balance is too low for this transaction |
DELIVERY_FAILED | 500 | Airtime delivery to the provider failed |
DUPLICATE_TRANSACTION | 409 | A duplicate transaction was detected |
Rate Limiting
| Code | HTTP Status | Description |
|---|
RATE_LIMIT_EXCEEDED | 429 | Too many requests. Wait and retry. |
System Errors
| Code | HTTP Status | Description |
|---|
INTERNAL_ERROR | 500 | Unexpected server error. Contact support if it persists. |
Always check the error.code field programmatically rather than parsing the message string, as messages may change.
Handling Errors
const response = await fetch('https://api.clickairtime.com/v2/topups', {
method: 'POST',
headers: {
'Authorization': 'Bearer ce_live_xxx',
'Content-Type': 'application/json',
},
body: JSON.stringify({ /* ... */ }),
});
const result = await response.json();
if (!result.success) {
switch (result.error.code) {
case 'INSUFFICIENT_BALANCE':
// Prompt user to fund wallet
break;
case 'INVALID_PHONE_NUMBER':
// Ask user to re-enter phone number
break;
case 'RATE_LIMIT_EXCEEDED':
// Implement exponential backoff
break;
default:
// Log error for debugging
console.error('API Error:', result.error);
}
}