Skip to main content

Error Codes Reference

This comprehensive reference documents all error codes returned by the JPay Africa API.

Status Code Summary

Success Codes (2xx)

CodeMessageDescription
200OKRequest successful
201CreatedResource created successfully

Client Error Codes (4xx)

CodeCategoryDescription
400Bad RequestInvalid input data
401UnauthorizedAuthentication required or failed
403ForbiddenInsufficient permissions
404Not FoundResource not found
429Rate LimitedToo many requests

Server Error Codes (5xx)

CodeCategoryDescription
500Server ErrorInternal server error
502Bad GatewayService temporarily unavailable
503Service UnavailableServer 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

StatusErrorDescription
200-Success
400Missing required fieldapp_key or app_secret missing
401Invalid credentialsInvalid app_key or app_secret
403App not activeApp is suspended
403Merchant not activeMerchant account disabled
404App not foundApp doesn't exist

POST /auth/login

StatusErrorDescription
200-Success
400Missing fieldsEmail or password missing
401Invalid credentialsWrong email or password
403Account inactiveMerchant suspended
429Rate limitedToo many login attempts

POST /auth/refresh

StatusErrorDescription
200-Success
400Missing refresh tokenRefresh token not provided
401Invalid tokenRefresh token invalid
401Token expiredRefresh token older than 7 days

Payment Endpoints

POST /payments/collections/checkouts/initiate

StatusErrorDescription
200-Success
400Invalid phonePhone not in E.164 format
400Invalid amountAmount format incorrect
401UnauthorizedInvalid or expired token
403Not approvedMerchant profile not approved
403App inactiveApp not active
403Product disabledCollections not enabled
404App not foundApp doesn't exist

POST /payments/payouts/initiate

StatusErrorDescription
200-Success
400Invalid phonePhone not in E.164 format
400Invalid amountAmount format incorrect
400Insufficient balanceNot enough funds in payout wallet
401UnauthorizedInvalid or expired token
403Not approvedMerchant profile not approved
403App inactiveApp not active
403Product disabledPayouts not enabled
404App not foundApp doesn't exist

GET /payments/collections/list

StatusErrorDescription
200-Success
400Invalid paramsInvalid query parameters
401UnauthorizedInvalid or expired token

GET /payments/payouts/list

StatusErrorDescription
200-Success
400Invalid paramsInvalid query parameters
401UnauthorizedInvalid 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