Error Codes Reference
This comprehensive reference documents all error codes returned by the JPay Africa API.
Status Code Summary
Success Codes (2xx)
| Code | Message | Description |
|---|---|---|
| 200 | OK | Request successful |
| 201 | Created | Resource created successfully |
Client Error Codes (4xx)
| Code | Category | Description |
|---|---|---|
| 400 | Bad Request | Invalid input data |
| 401 | Unauthorized | Authentication required or failed |
| 403 | Forbidden | Insufficient permissions |
| 404 | Not Found | Resource not found |
| 429 | Rate Limited | Too many requests |
Server Error Codes (5xx)
| Code | Category | Description |
|---|---|---|
| 500 | Server Error | Internal server error |
| 502 | Bad Gateway | Service temporarily unavailable |
| 503 | Service Unavailable | Server under maintenance |
Detailed Error Codes
400 Bad Request Errors
These errors indicate issues with the request data.
Invalid Phone Number
Code: 400
Error: "Invalid phone number"
Cause: Phone number not in E.164 format or invalid
Solution: Use format like +254712345678
Example:
Bad: 0712345678, 254712345678, +2547123456
Good: +254712345678
Invalid Amount
Code: 400
Error: "Invalid amount"
Cause: Amount format incorrect or missing decimal places
Solution: Use decimal format with exactly 2 decimal places
Example:
Bad: 1000, 1000.5, 1000.123
Good: 1000.00, 5000.50
Missing Required Field
Code: 400
Error: "{field} field is required"
Cause: Required field missing from request
Solution: Include all required fields
Example Fields:
- Collections: payfrom, amount, ref_no, account_number
- Payouts: payto, amount, ref_no
- Auth: app_key, app_secret (or email, password)
Invalid JSON
Code: 400
Error: "JSON parse error"
Cause: Request body is not valid JSON
Solution: Ensure valid JSON syntax in request body
Example:
Bad: {payfrom: "+254712345678"} // Missing quotes
Good: {"payfrom": "+254712345678"}
Invalid Query Parameter
Code: 400
Error: "Invalid query parameter: {parameter}"
Cause: Query parameter value is invalid
Solution: Check parameter format and valid values
Common Parameters:
- page: positive integer
- page_size: 1-100
- status: pending, completed, failed
- date_from/date_to: YYYY-MM-DD format
Insufficient Balance
Code: 400
Error: "Insufficient balance in {wallet} wallet"
Cause: Wallet doesn't have enough funds for payout
Solution: Fund your wallet or wait for settlement
Wallets:
- payout_wallet: Funds available for sending money
- collection_wallet: Money received from collections
401 Unauthorized Errors
Authentication failed or not provided.
Missing Authorization Header
Code: 401
Error: "Authentication credentials were not provided"
Cause: Missing Authorization header
Solution: Include Authorization header with valid token
Example:
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...
Invalid Token Format
Code: 401
Error: "Invalid token format"
Cause: Authorization header format incorrect
Solution: Use "Bearer {token}" format
Example:
Bad: Bearer {token} // Extra braces
Bad: Token {token} // Wrong prefix
Good: Bearer eyJ0eXAi...
Invalid or Expired Token
Code: 401
Error: "Invalid or expired token"
Cause: Token invalid, expired, or revoked
Solution: Obtain new token:
- For app auth: POST /auth/app/token
- For merchant: POST /auth/login
- For refresh: POST /auth/refresh with refresh_token
Refresh Token Expired
Code: 401
Error: "Refresh token has expired. Please login again."
Cause: Refresh token older than 7 days
Solution: Re-authenticate with original credentials
- App: POST /auth/app/token with app_key, app_secret
- Merchant: POST /auth/login with email, password
Token Revoked
Code: 401
Error: "Token has been revoked"
Cause: Token manually revoked or user deactivated
Solution: Obtain new token by re-authenticating
403 Forbidden Errors
Authentication succeeded but authorization failed.
Merchant Not Approved
Code: 403
Error: "Your merchant profile is not approved. Please ensure your profile has been verified before initiating {operation}."
Cause: Merchant account not verified
Solution: Complete merchant verification in dashboard
1. Log in to merchant dashboard
2. Go to Profile settings
3. Complete KYC verification
4. Wait for approval (24-48 hours)
App Inactive
Code: 403
Error: "App is not active"
Cause: App is suspended or not activated
Solution: Activate app in merchant dashboard
1. Log in to dashboard
2. Navigate to Apps section
3. Click "Activate" for your app
4. Verify activation status
Product Not Enabled
Code: 403
Error: "App does not have {product} product enabled"
Cause: Required product not enabled for app
Solution: Enable product in app settings
Products:
- collections: For receiving payments
- payouts: For sending money
- disbursements: For bulk payouts
IP Address Not Allowed
Code: 403
Error: "Access denied: IP address not allowed"
Cause: Request IP not in app's allowed IP whitelist
Solution: Add your server's IP address to allowed IPs
1. Find your server's IP address:
curl https://api.ipify.org
2. Log in to merchant dashboard
3. Navigate to Apps → Select your app
4. Go to Security Settings
5. Add your IP address to Allowed IPs list
6. Save changes
Note: If IP restrictions are too strict:
- Remove all IPs to allow any IP (not recommended for production)
- Use CIDR notation for IP ranges (e.g., 203.0.113.0/24)
Insufficient Permissions
Code: 403
Error: "You do not have permission to access this resource"
Cause: User role doesn't have required permission
Solution: Contact account admin to grant permissions
Roles:
- Admin: Full access
- Finance: Collections & Payouts access
- Operator: Limited API access
Wallet Not Found
Code: 403
Error: "Wallet not found or not initialized"
Cause: Merchant wallet not properly set up
Solution: Contact support to initialize wallet
404 Not Found Errors
Requested resource doesn't exist.
App Not Found
Code: 404
Error: "App not found"
Cause: App with specified code doesn't exist
Solution: Verify app code:
1. Check dashboard for correct app code
2. Ensure app exists under your merchant account
3. App may have been deleted
Merchant Not Found
Code: 404
Error: "Merchant not found"
Cause: Merchant account doesn't exist
Solution: Verify merchant account is active
Transaction Not Found
Code: 404
Error: "Transaction not found"
Cause: Transaction with specified ID doesn't exist
Solution: Verify transaction ID and check transaction list
Endpoint Not Found
Code: 404
Error: "Not found"
Cause: Endpoint URL incorrect or doesn't exist
Solution: Verify API endpoint URL:
- Check documentation for correct endpoint
- Verify HTTP method (GET, POST, etc.)
- Check base URL: https://sandbox.api.jpay.africa/api/v1
429 Rate Limit Errors
Too many requests.
Rate Limit Exceeded
Code: 429
Error: "Request rate limit exceeded"
Cause: Exceeded rate limit of 60 requests/minute
Solution: Implement exponential backoff retry
Rate Limits:
- Standard: 60 requests per minute
- Burst: 100 requests per 10 seconds
Headers Returned:
- X-RateLimit-Limit: 60
- X-RateLimit-Remaining: {count}
- X-RateLimit-Reset: {timestamp}
500 Server Error Codes
Server-side errors.
Internal Server Error
Code: 500
Error: "Internal server error"
Cause: Unexpected server error
Solution:
1. Retry request after 5 seconds
2. Use exponential backoff for retries
3. Contact support if error persists
Service Temporarily Unavailable
Code: 503
Error: "Service temporarily unavailable"
Cause: Server maintenance or overload
Solution:
1. Wait 30-60 seconds and retry
2. Check status page for maintenance notifications
3. Implement exponential backoff
Error Code by Endpoint
Auth Endpoints
POST /auth/app/token
| Status | Error | Description |
|---|---|---|
| 200 | - | Success |
| 400 | Missing required field | app_key or app_secret missing |
| 401 | Invalid credentials | Invalid app_key or app_secret |
| 403 | App not active | App is suspended |
| 403 | Merchant not active | Merchant account disabled |
| 404 | App not found | App doesn't exist |
POST /auth/login
| Status | Error | Description |
|---|---|---|
| 200 | - | Success |
| 400 | Missing fields | Email or password missing |
| 401 | Invalid credentials | Wrong email or password |
| 403 | Account inactive | Merchant suspended |
| 429 | Rate limited | Too many login attempts |
POST /auth/refresh
| Status | Error | Description |
|---|---|---|
| 200 | - | Success |
| 400 | Missing refresh token | Refresh token not provided |
| 401 | Invalid token | Refresh token invalid |
| 401 | Token expired | Refresh token older than 7 days |
Payment Endpoints
POST /payments/collections/checkouts/initiate
| Status | Error | Description |
|---|---|---|
| 200 | - | Success |
| 400 | Invalid phone | Phone not in E.164 format |
| 400 | Invalid amount | Amount format incorrect |
| 401 | Unauthorized | Invalid or expired token |
| 403 | Not approved | Merchant profile not approved |
| 403 | App inactive | App not active |
| 403 | Product disabled | Collections not enabled |
| 404 | App not found | App doesn't exist |
POST /payments/payouts/initiate
| Status | Error | Description |
|---|---|---|
| 200 | - | Success |
| 400 | Invalid phone | Phone not in E.164 format |
| 400 | Invalid amount | Amount format incorrect |
| 400 | Insufficient balance | Not enough funds in payout wallet |
| 401 | Unauthorized | Invalid or expired token |
| 403 | Not approved | Merchant profile not approved |
| 403 | App inactive | App not active |
| 403 | Product disabled | Payouts not enabled |
| 404 | App not found | App doesn't exist |
GET /payments/collections/list
| Status | Error | Description |
|---|---|---|
| 200 | - | Success |
| 400 | Invalid params | Invalid query parameters |
| 401 | Unauthorized | Invalid or expired token |
GET /payments/payouts/list
| Status | Error | Description |
|---|---|---|
| 200 | - | Success |
| 400 | Invalid params | Invalid query parameters |
| 401 | Unauthorized | Invalid or expired token |
Error Handling Examples
Handle Multiple Error Types
def handle_api_response(response):
"""Handle different error types appropriately"""
try:
if response.status_code == 200:
return response.json()
error_data = response.json()
detail = error_data.get('detail', 'Unknown error')
if response.status_code == 400:
handle_validation_error(detail)
elif response.status_code == 401:
handle_auth_error(detail)
elif response.status_code == 403:
handle_permission_error(detail)
elif response.status_code == 404:
handle_not_found_error(detail)
elif response.status_code == 429:
handle_rate_limit_error(detail)
elif response.status_code >= 500:
handle_server_error(detail)
except Exception as e:
logger.error(f"Error parsing response: {e}")
def handle_validation_error(detail):
"""Handle 400 Bad Request errors"""
if "phone" in detail.lower():
print("Error: Invalid phone number format. Use E.164 format (e.g., +254712345678)")
elif "amount" in detail.lower():
print("Error: Invalid amount. Use decimal with 2 places (e.g., 1000.00)")
else:
print(f"Validation error: {detail}")
def handle_auth_error(detail):
"""Handle 401 Unauthorized errors"""
print("Error: Authentication failed. Please log in again.")
redirect_to_login()
def handle_permission_error(detail):
"""Handle 403 Forbidden errors"""
if "approved" in detail.lower():
print("Error: Your merchant account is not approved.")
print("Please complete verification in the dashboard.")
elif "active" in detail.lower():
print("Error: Your app or account is not active.")
else:
print(f"Permission denied: {detail}")
def handle_not_found_error(detail):
"""Handle 404 Not Found errors"""
print(f"Error: Resource not found. {detail}")
def handle_rate_limit_error(detail):
"""Handle 429 Rate Limit errors"""
print("Error: Too many requests. Please wait before retrying.")
# Implement exponential backoff
def handle_server_error(detail):
"""Handle 5xx Server errors"""
print("Error: Server error. Please try again later.")
# Implement retry logic
Troubleshooting Flowchart
API Request Failed
↓
Check Status Code
├→ 4xx Error
│ ├→ 400: Validate request data
│ │ ├→ Phone format? (E.164)
│ │ ├→ Amount format? (decimal, 2 places)
│ │ └→ All required fields?
│ │
│ ├→ 401: Re-authenticate
│ │ ├→ Token expired?
│ │ ├→ Token invalid?
│ │ └→ Refresh token or log in again
│ │
│ ├→ 403: Check permissions
│ │ ├→ Merchant approved?
│ │ ├→ App active?
│ │ └→ Product enabled?
│ │
│ ├→ 404: Check resource
│ │ ├→ App exists?
│ │ ├→ Endpoint correct?
│ │ └→ Resource not deleted?
│ │
│ └→ 429: Implement backoff
│ └→ Wait and retry
│
└→ 5xx Error
├→ Retry with exponential backoff
├→ Check status page for maintenance
└→ Contact support if persists
Related Resources
- Error Handling Overview - General error handling guide
- Best Practices - Integration best practices
- API Endpoints - Endpoint documentation