HTTP Status Codes
Here are the common HTTP status codes you may encounter when using our API:
200 - Success
The request was successful, and the intended action was completed.
For charge or verification requests, always check the data
object to confirm the specific outcome (success or failure).
201 - Created
A new resource was successfully created.
204 - No Content
The request was successful, but no content is returned in the response.
400 - Bad Request
A validation or client-side error occurred, preventing the request from being processed.
401 - Unauthorized
The request was not authorized. This commonly occurs due to:
- Invalid secret key in authorization header
- Missing authorization header
- Expired API key
- Using test key in production environment
- Using production key in test environment
403 - Forbidden
Access to the requested resource is denied due to insufficient permissions.
404 - Not Found
The requested resource could not be found.
This status code does not apply when a payment session is completed.
422 - Unprocessable Entity
Some required fields are missing or invalid, preventing the request from being processed.
429 - Too Many Requests
You’ve exceeded the API rate limits.
500 - Server Error
The request could not be fulfilled due to an error on Juicyway’s server.
Please report any encounters with 500 errors to our support team.
All API errors follow a consistent format:
{
"error": {
"code": "error_code",
"message": "Human readable error message",
"type": "error_type",
"details": {
// Additional error context if available
}
}
}
Common Error Types
Validation Errors
When required fields are missing or invalid:
{
"error": {
"code": "validation_error",
"message": "The request was invalid",
"type": "invalid_request_error",
"errors": [
{
"field": "amount",
"message": "Amount must be a positive integer"
},
{
"field": "currency",
"message": "Currency must be one of: NGN, USD, CAD"
}
]
}
}
Authentication Errors
When there are issues with API keys or authentication:
{
"error": {
"code": "invalid_key",
"message": "Invalid API key provided",
"type": "authentication_error"
}
}
Rate Limiting Errors
When you exceed the API rate limits:
{
"error": {
"code": "rate_limit_exceeded",
"message": "Too many requests. Please try again in 30 seconds.",
"type": "rate_limit_error",
"retry_after": 30
}
}
Server Errors
For 500-level server errors:
{
"error": {
"code": "internal_server_error",
"message": "An unexpected error occurred",
"type": "server_error",
"request_id": "req_123xyz"
}
}
Error Handling Best Practices
Timeout Handling
All API requests automatically timeout after 30 seconds. For long-running operations like payments that may take longer to process, we recommend:
- Implementing proper retry logic with exponential backoff
- Using webhooks to receive the final status asynchronously
- Checking the transaction status via the GET endpoints if webhook delivery fails
Rate Limit Handling
To handle rate limits effectively:
- Implement exponential backoff with jitter for retries
- Check the
retry_after
header to know when to retry
- Cache frequently requested data
- Batch requests where possible
Server Error Handling
Best practices for handling server errors:
- Log the
request_id
for debugging
- Implement retry logic with exponential backoff
- Contact support if errors persist
- Set up monitoring for error rates
Code Examples
Here’s how to properly handle API errors in different languages:
try {
const response = await juiceApi.createPayment({
amount: 1000,
currency: 'NGN'
});
} catch (error) {
if (error.type === 'validation_error') {
// Handle validation errors
error.errors.forEach(err => {
console.log(`${err.field}: ${err.message}`);
});
} else if (error.type === 'authentication_error') {
// Handle auth errors
console.log('Please check your API keys');
} else if (error.type === 'rate_limit_error') {
// Implement exponential backoff
const retryAfter = error.retry_after || 30;
await sleep(retryAfter * 1000);
// Retry request
} else {
// Handle other errors
console.error(`Error: ${error.message}`);
// Log error for debugging
console.error(`Request ID: ${error.request_id}`);
}
}
try {
const response = await juiceApi.createPayment({
amount: 1000,
currency: 'NGN'
});
} catch (error) {
if (error.type === 'validation_error') {
// Handle validation errors
error.errors.forEach(err => {
console.log(`${err.field}: ${err.message}`);
});
} else if (error.type === 'authentication_error') {
// Handle auth errors
console.log('Please check your API keys');
} else if (error.type === 'rate_limit_error') {
// Implement exponential backoff
const retryAfter = error.retry_after || 30;
await sleep(retryAfter * 1000);
// Retry request
} else {
// Handle other errors
console.error(`Error: ${error.message}`);
// Log error for debugging
console.error(`Request ID: ${error.request_id}`);
}
}
try:
response = juice_api.create_payment(
amount=1000,
currency='NGN'
)
except ValidationError as e:
# Handle validation errors
for error in e.errors:
print(f"{error['field']}: {error['message']}")
except AuthenticationError as e:
# Handle auth errors
print("Please check your API keys")
except RateLimitError as e:
# Implement exponential backoff
retry_after = getattr(e, 'retry_after', 30)
time.sleep(retry_after)
# Retry request
except ServerError as e:
# Handle server errors
print(f"Error: {e.message}")
# Log error for debugging
print(f"Request ID: {e.request_id}")
except Exception as e:
# Handle unexpected errors
print(f"Unexpected error: {str(e)}")