Error Handling
Learn how to handle errors gracefully in your LosCenotes API integration.
Error Response Format
All API errors follow a consistent structure:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "One or more fields are invalid",
"status": 400,
"details": {
"field": "email",
"constraint": "Invalid email format"
},
"requestId": "req_1234567890abcdef",
"timestamp": "2024-01-15T10:30:00Z"
}
}
HTTP Status Codes
The LosCenotes API uses standard HTTP status codes:
| Status Code | Meaning | Description |
|---|---|---|
| 200 | OK | Request successful |
| 201 | Created | Resource created successfully |
| 400 | Bad Request | Invalid request parameters |
| 401 | Unauthorized | Invalid or missing API key |
| 403 | Forbidden | Insufficient permissions |
| 404 | Not Found | Resource not found |
| 409 | Conflict | Resource already exists |
| 422 | Unprocessable Entity | Validation failed |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Server error |
| 503 | Service Unavailable | Service temporarily unavailable |
Common Error Codes
Authentication Errors
INVALID_API_KEY
{
"success": false,
"error": {
"code": "INVALID_API_KEY",
"message": "The provided API key is invalid",
"status": 401
}
}
AUTHENTICATION_REQUIRED
{
"success": false,
"error": {
"code": "AUTHENTICATION_REQUIRED",
"message": "Authentication is required for this endpoint",
"status": 401
}
}
Validation Errors
VALIDATION_ERROR
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "One or more fields are invalid",
"status": 400,
"details": [
{
"field": "email",
"constraint": "Invalid email format"
}
]
}
}
Resource Errors
RESOURCE_NOT_FOUND
{
"success": false,
"error": {
"code": "RESOURCE_NOT_FOUND",
"message": "The requested resource was not found",
"status": 404,
"details": {
"resource": "cenote",
"id": "cenote-not-found"
}
}
}
Business Logic Errors
CENOTE_NOT_AVAILABLE
{
"success": false,
"error": {
"code": "CENOTE_NOT_AVAILABLE",
"message": "The cenote is not available for the selected date",
"status": 422,
"details": {
"cenoteId": "cenote-uuid",
"date": "2025-01-15",
"reason": "maintenance"
}
}
}
INSUFFICIENT_CAPACITY
{
"success": false,
"error": {
"code": "INSUFFICIENT_CAPACITY",
"message": "Not enough capacity for the requested reservation",
"status": 422,
"details": {
"requested": 10,
"available": 5
}
}
}
Rate Limiting Errors
RATE_LIMIT_EXCEEDED
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Please try again later",
"status": 429,
"details": {
"limit": 1000,
"window": "1 hour",
"resetTime": "2025-01-15T11:00:00Z"
}
}
}
Error Handling Best Practices
1. Always Check the Success Field
const response = await fetch('https://service-gateway.loscenotes.com/partner/cenotes', {
headers: { 'X-API-Key': apiKey }
});
const data = await response.json();
if (!data.success) {
console.error('API Error:', data.error.code, data.error.message);
// Handle specific error codes
switch (data.error.code) {
case 'RESOURCE_NOT_FOUND':
// Handle not found
break;
case 'RATE_LIMIT_EXCEEDED':
// Implement backoff strategy
break;
default:
// Handle generic error
break;
}
return;
}
// Success - use data.data
console.log(data.data);
2. Implement Exponential Backoff
async function apiCallWithRetry(apiCall, maxRetries = 3, baseDelay = 1000) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await apiCall();
const data = await response.json();
if (data.success) {
return data;
}
if (data.error.status === 429 && attempt < maxRetries - 1) {
const delay = baseDelay * Math.pow(2, attempt);
console.log(`Rate limited. Retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
throw data.error;
} catch (error) {
if (attempt === maxRetries - 1) throw error;
}
}
throw new Error('Max retries exceeded');
}
// Usage
const data = await apiCallWithRetry(() =>
fetch('https://service-gateway.loscenotes.com/partner/cenotes', {
headers: { 'X-API-Key': apiKey }
})
);
3. Validate Input Before API Calls
function validateReservationData(data) {
const errors = [];
if (!data.cenoteId) {
errors.push('Cenote ID is required');
}
if (!data.date || new Date(data.date) < new Date()) {
errors.push('Valid future date is required');
}
if (!data.ageBreakdown || !data.ageBreakdown.adult) {
errors.push('At least one adult is required');
}
return errors;
}
// Usage
const validationErrors = validateReservationData(reservationData);
if (validationErrors.length > 0) {
console.error('Validation errors:', validationErrors);
return;
}
// Proceed with API call
const response = await createReservation(reservationData);
4. Handle Network Errors
try {
const response = await fetch('https://service-gateway.loscenotes.com/partner/cenotes', {
headers: { 'X-API-Key': apiKey }
});
if (!response.ok) {
throw new Error(`HTTP Error: ${response.status}`);
}
const data = await response.json();
// Process data...
} catch (error) {
if (error.name === 'TypeError') {
console.error('Network error - check your internet connection');
} else if (error.message.includes('timeout')) {
console.error('Request timeout - try again later');
} else {
console.error('Error:', error.message);
}
}
5. Log Errors for Debugging
function logApiError(error, context) {
const errorLog = {
timestamp: new Date().toISOString(),
requestId: error.requestId,
endpoint: context.endpoint,
method: context.method,
errorCode: error.code || 'UNKNOWN_ERROR',
errorMessage: error.message || 'Unknown error occurred',
details: error.details
};
console.error('LosCenotes API Error:', JSON.stringify(errorLog, null, 2));
// Send to your logging service
// yourLogger.error(errorLog);
}
// Usage
try {
const response = await makeApiCall();
} catch (error) {
logApiError(error, {
endpoint: '/partner/cenotes',
method: 'GET'
});
}
Pricing Specific Errors
| Code | Description |
|---|---|
error.cenote.not_found | Cenote ID not found |
error.tour.not_found | Tour ID not found |
error.pricing.invalid_item_type | Item type must be "cenote" or "tour" |
error.transport.pickup_required_when_included | Pickup info required when transport is included |
Payment Errors
| Code | Description |
|---|---|
card_declined | Card was declined |
insufficient_funds | Insufficient funds |
expired_card | Card has expired |
invalid_cvc | Invalid security code |
processing_error | Payment processing error |