Documentation Index
Fetch the complete documentation index at: https://docs.ozura.com/llms.txt
Use this file to discover all available pages before exploring further.
Handle payment errors gracefully to give customers a smooth experience.
All API errors follow this structure:
{
"success": false,
"error": "Human-readable error message",
"details": ["Specific validation error 1", "Specific validation error 2"]
}
HTTP Status Codes
| Code | Meaning | What to Do |
|---|
400 | Bad Request | Check your request parameters |
401 | Unauthorized | Verify your API keys |
404 | Not Found | Session doesn’t exist |
409 | Conflict | Session already completed/cancelled |
410 | Gone | Session expired |
500 | Server Error | Retry the request |
502 | Bad Gateway | Upstream service unavailable — retry with backoff |
503 | Service Unavailable | Service temporarily down — retry with backoff |
Two Types of Errors
Ozura Checkout handles errors differently based on whether the customer can fix them:
Fixable Errors (Customer Stays on Checkout)
These errors allow the customer to try again without leaving the checkout page:
- Card declined
- Insufficient funds
- Invalid card number
- Expired card
- Wrong CVV
- Address verification failed
What happens: An inline error message appears. The customer can correct their information and try again.
Unrecoverable Errors (Redirect to errorUrl)
These errors require redirecting the customer away from checkout:
- Server/system errors
- Authentication failures
- Network connectivity issues
- Payment processor unavailable
What happens: The customer is redirected to your errorUrl with error details in the URL.
Redirect Behavior Summary
| Situation | What Happens | Session Status |
|---|
| Payment successful | Redirect to successUrl | completed |
| Fixable error (card declined) | Stays on checkout – inline error | pending |
| Unrecoverable error | Redirect to errorUrl | failed |
| Customer cancels | Redirect to cancelUrl | cancelled |
| Session expires | Ozura expiration page → cancelUrl | expired |
Error URL Parameters
When an unrecoverable error occurs, the customer is redirected to your errorUrl:
https://yoursite.com/error?success=false&errorCode=SYSTEM_ERROR&error=Payment+service+unavailable&cancelUrl=https://yoursite.com/cart
| Parameter | Description | Example |
|---|
success | Always false | false |
errorCode | Machine-readable error type | SYSTEM_ERROR, SESSION_FAILED |
error | Human-readable message | Payment service unavailable |
cancelUrl | Your cancelUrl (for “return” navigation) | https://yoursite.com/cart |
Error Codes
| Code | Meaning |
|---|
SYSTEM_ERROR | Server or connectivity issue |
SESSION_FAILED | Session marked as failed |
MANUAL_REVIEW | Transaction flagged for manual review |
FORBIDDEN | Too many failed payment attempts |
Building Your Error Page
// Parse URL parameters
const params = new URLSearchParams(window.location.search);
const errorCode = params.get('errorCode');
const errorMessage = params.get('error');
const returnUrl = params.get('cancelUrl');
// Display to user
document.getElementById('error-message').textContent =
errorMessage || 'Something went wrong. Please try again.';
// Set up return button
if (returnUrl) {
document.getElementById('return-btn').href = returnUrl;
}
Recommended Approach: Redirect to Cart with Message
Instead of showing a dead-end error page, redirect customers back to their cart with a popup message:
Set your errorUrl to your cart page with a flag:
errorUrl: "https://yoursite.com/cart?showError=true"
Then on your cart page:
const params = new URLSearchParams(window.location.search);
if (params.get('showError')) {
const errorMessage = params.get('error') || 'Something went wrong during checkout';
showErrorPopup(errorMessage);
// Clean up URL
window.history.replaceState({}, '', '/cart');
}
This keeps customers in their shopping flow instead of showing a confusing error page.
Retry Logic for API Calls
If you get a 500 error, it’s safe to retry with exponential backoff:
async function createSessionWithRetry(data, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch('https://checkout.ozura.com/api/sessions/create', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-KEY': process.env.VAULT_API_KEY,
'X-OZURA-API-KEY': process.env.MERCHANT_API_KEY
},
body: JSON.stringify(data)
});
if (response.ok) {
return await response.json();
}
// Don't retry client errors (4xx)
if (response.status < 500) {
throw new Error(`Request failed: ${response.status}`);
}
// Wait before retrying (exponential backoff)
await new Promise(r => setTimeout(r, 1000 * attempt));
} catch (error) {
if (attempt === maxRetries) throw error;
}
}
}
Network Retry Protection
To prevent duplicate sessions from network issues, use an idempotency key:
{
"merchantId": "your_merchant_id",
"merchantName": "My Store",
"amount": "25.00",
"idempotencyKey": "order_12345"
}
If you send the same idempotencyKey twice, you’ll get back the original session instead of creating a duplicate.