Error Handling
The API uses standard HTTP status codes and Laravel's validation error format to help you handle errors gracefully.
| Code | Meaning | Description |
|---|
| 200 | OK | Request succeeded |
| 201 | Created | Resource created successfully |
| 204 | No Content | Request succeeded with no response body |
| Code | Meaning | Common Causes |
|---|
| 400 | Bad Request | Invalid parameters or malformed request |
| 401 | Unauthorized | Invalid or missing Bearer token |
| 403 | Forbidden | Valid token but insufficient permissions or scope |
| 404 | Not Found | Resource doesn't exist |
| 422 | Unprocessable Entity | Validation errors |
| 429 | Too Many Requests | Rate limit exceeded |
| Code | Meaning | Action Required |
|---|
| 500 | Internal Server Error | Retry with exponential backoff |
| 502 | Bad Gateway | Temporary issue, retry |
| 503 | Service Unavailable | Service temporarily down |
When a request fails validation, the API returns a 422 response:
{
"message": "The given data was invalid.",
"errors": {
"amount": ["The amount field is required."],
"currencyCode": ["The selected currency code is invalid."],
"clientId": ["The client id field is required."]
}
}
| Error | Cause | Solution |
|---|
amount required | Missing amount field | Include amount in request body |
currencyCode invalid | Currency not supported | Use a supported fiat currency code |
clientId invalid | Client ID not found | Verify your Client ID in the dashboard |
reference required | Missing reference | Include a unique reference string |
| HTTP Status | Cause | Solution |
|---|
| 401 | Missing or invalid token | Check your Bearer token |
| 403 | Token lacks required scope | Use a token with the correct scope (e.g., payments.create) |
| Error | Cause | Solution |
|---|
| Payment not found | Invalid payment ID | Verify the payment UUID |
| Refund not allowed | Payment has refund = false | Only payments with refund enabled can be refunded |
| Refund already exists | Duplicate refund request | A refund request already exists for this payment |
async function createPayment(data) {
try {
const response = await fetch('https://api.yourdomain.com/api/payment/checkout', {
method: 'POST',
headers: {
'Authorization': `Bearer ${CLIENT_TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
if (!response.ok) {
const error = await response.json();
if (response.status === 422) {
// Validation errors
console.error('Validation failed:', error.errors);
} else if (response.status === 401) {
console.error('Authentication failed');
} else if (response.status === 429) {
// Rate limited — wait and retry
const delay = 2 ** retryCount * 1000;
await new Promise((resolve) => setTimeout(resolve, delay));
return createPayment(data);
}
throw new Error(error.message);
}
return await response.json();
} catch (error) {
console.error('Payment creation failed:', error);
throw error;
}
}
If your webhook endpoint fails to respond with a 2xx status code within 10 seconds, the webhook will be retried. Common issues:
| Error | Cause | Solution |
|---|
| Connection timeout | Endpoint unreachable | Check server availability |
| Invalid signature | Secret mismatch | Verify your webhook secret matches the application config |
| Response timeout | Slow processing | Return 200 immediately, process asynchronously |
- Handle validation errors by displaying field-specific messages to users
- Implement retry logic with exponential backoff for 5xx errors
- Log request details including status codes for debugging
- Validate input on your side before making API calls