Error Handling Guide¶
Learn how to handle errors gracefully in your Nivatio integration.
API Error Format¶
All API errors return a consistent JSON format:
{
"statusCode": 400,
"message": "Invalid order amount",
"error": "Bad Request",
"code": "invalid_amount"
}
Common Error Codes¶
Client Errors (4xx)¶
| Code | HTTP Status | Description | Solution |
|---|---|---|---|
invalid_amount |
400 | Amount is not valid | Ensure amount uses 6 decimals (100000 = 100.000) |
invalid_currency |
400 | Currency not supported | Use NUSD |
unauthorized |
401 | Invalid API key or JWT | Check credentials |
forbidden |
403 | Insufficient permissions | Check API key permissions |
not_found |
404 | Order or resource not found | Verify the ID |
rate_limit |
429 | Too many requests | Implement exponential backoff |
Server Errors (5xx)¶
| Code | HTTP Status | Description | Solution |
|---|---|---|---|
internal_error |
500 | Internal server error | Retry with exponential backoff |
service_unavailable |
503 | Service temporarily unavailable | Retry after delay |
Handling Errors in Code¶
JavaScript/TypeScript¶
try {
const order = await client.orders.create({
amount: 100000,
currency: 'NUSD'
});
console.log('Order created:', order.id);
} catch (error) {
if (error.statusCode === 400) {
console.error('Bad request:', error.message);
// Show user-friendly error
} else if (error.statusCode === 401) {
console.error('Unauthorized - check API key');
// Refresh credentials
} else if (error.statusCode === 429) {
console.error('Rate limited - retry later');
// Implement retry with backoff
} else {
console.error('Unexpected error:', error);
}
}
Python¶
from nivatio import NivatioError
try:
order = client.orders.create(
amount=100000,
currency='NUSD'
)
print(f"Order created: {order.id}")
except NivatioError as e:
if e.status_code == 400:
print(f"Bad request: {e.message}")
elif e.status_code == 401:
print("Unauthorized - check API key")
elif e.status_code == 429:
print("Rate limited - retry later")
else:
print(f"Unexpected error: {e}")
Retry Strategy¶
Exponential Backoff¶
Implement retries for transient errors (429, 500, 503):
async function createOrderWithRetry(data, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await client.orders.create(data);
} catch (error) {
if (error.statusCode === 429 || error.statusCode >= 500) {
if (attempt === maxRetries) throw error;
// Exponential backoff: 1s, 2s, 4s, 8s...
const delay = Math.pow(2, attempt - 1) * 1000;
console.log(`Retry attempt ${attempt} after ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error; // Don't retry client errors (except 429)
}
}
}
}
Webhook Error Handling¶
Always Return 200¶
Nivatio expects a 200 status code within 5 seconds:
app.post('/webhook', (req, res) => {
try {
const event = req.body;
// Process event asynchronously
processEventAsync(event).catch(err => {
console.error('Error processing event:', err);
// Log but don't fail the webhook
});
// Acknowledge immediately
res.json({ received: true });
} catch (error) {
// Still return 200 to prevent retries
console.error('Webhook error:', error);
res.json({ received: true, error: 'Processing async' });
}
});
Idempotency¶
Prevent duplicate processing:
const processedEvents = new Set();
app.post('/webhook', (req, res) => {
const event = req.body;
// Check if already processed
if (processedEvents.has(event.eventId)) {
return res.json({ received: true, reason: 'duplicate' });
}
// Process event...
// Mark as processed
processedEvents.add(event.eventId);
// Clean up old events after 24 hours
setTimeout(() => {
processedEvents.delete(event.eventId);
}, 24 * 60 * 60 * 1000);
res.json({ received: true });
});
Payment-Specific Errors¶
Transaction Failures¶
app.post('/webhook', (req, res) => {
const event = req.body;
if (event.type === 'payment.failed') {
const order = event.data;
// Log failure reason
console.error(`Payment ${order.id} failed:`, order.failureReason);
// Notify customer
notifyCustomer(order, `Payment failed: ${order.failureReason}`);
// Update your database
updateOrderStatus(order.id, 'FAILED');
}
res.json({ received: true });
});
Timeout Handling¶
// Orders expire after a configurable timeout
if (event.type === 'payment.expired') {
const order = event.data;
console.log(`Payment ${order.id} expired`);
// Clean up your side
}
Logging Best Practices¶
What to Log¶
// Good: Log relevant context
console.log('Order created', {
orderId: order.id,
amount: order.amount,
currency: order.currency,
status: order.status
});
// Bad: Don't log sensitive data
console.log('API Key:', apiKey); // Never do this!
Structured Logging¶
function log(level, message, data) {
console.log(JSON.stringify({
timestamp: new Date().toISOString(),
level,
message,
...data
}));
}
log('info', 'Order created', { orderId: order.id, amount: order.amount });
log('error', 'Payment failed', { orderId: order.id, reason: error.message });
Monitoring & Alerting¶
Key Metrics to Monitor¶
- Payment success rate - % of successful payments
- Webhook delivery rate - % of webhooks delivered successfully
- API error rate - % of API calls returning errors
- Payment latency - Time from creation to confirmation
Setting Up Alerts¶
// Alert if success rate drops below 95%
if (successRate < 0.95) {
sendAlert({
title: 'Low Payment Success Rate',
message: `Success rate dropped to ${(successRate * 100).toFixed(2)}%`,
severity: 'high'
});
}
Next Steps¶
- Payment Processing - Complete payment guide
- Testing Guide - Test error scenarios
- Webhook Integration - Receive notifications