Error Response Format
All Zochil API errors follow a consistent structure to help you handle them programmatically:{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error message",
"metadata": {
"field": "additional_context",
"details": "More information about the error"
}
}
}
HTTP Status Codes
The API uses standard HTTP status codes to indicate the success or failure of requests:| Status Code | Description |
|---|---|
200 | OK - Request succeeded |
201 | Created - Resource created successfully |
204 | No Content - Request succeeded, no response body |
400 | Bad Request - Invalid request parameters |
401 | Unauthorized - Authentication required |
403 | Forbidden - Insufficient permissions |
404 | Not Found - Resource not found |
409 | Conflict - Resource conflict (e.g., duplicate email) |
422 | Unprocessable Entity - Validation errors |
429 | Too Many Requests - Rate limit exceeded |
500 | Internal Server Error - Server error |
503 | Service Unavailable - Temporary service outage |
Common Error Codes
Authentication Errors
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or expired access token"
}
}
{
"success": false,
"error": {
"code": "MISSING_TOKEN",
"message": "Access token is required"
}
}
{
"success": false,
"error": {
"code": "INVALID_DEVICE",
"message": "Device ID not recognized"
}
}
Validation Errors
{
"success": false,
"error": {
"code": "VALIDATION_FAILED",
"message": "Request validation failed",
"metadata": {
"fields": {
"email": "Invalid email format",
"password": "Password must be at least 8 characters"
}
}
}
}
{
"success": false,
"error": {
"code": "MISSING_REQUIRED_FIELD",
"message": "Required field missing",
"metadata": {
"field": "email"
}
}
}
Resource Errors
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Resource not found",
"metadata": {
"resource": "user",
"id": "123e4567-e89b-12d3-a456-426614174000"
}
}
}
{
"success": false,
"error": {
"code": "DUPLICATE_RESOURCE",
"message": "Resource already exists",
"metadata": {
"field": "email",
"value": "user@example.com"
}
}
}
Business Logic Errors
{
"success": false,
"error": {
"code": "INSUFFICIENT_FUNDS",
"message": "Insufficient balance for transaction",
"metadata": {
"available": 50.0,
"required": 100.0,
"currency": "USD"
}
}
}
{
"success": false,
"error": {
"code": "PRODUCT_OUT_OF_STOCK",
"message": "Product is currently out of stock",
"metadata": {
"product_id": "prod_123",
"requested_quantity": 5,
"available_quantity": 0
}
}
}
Error Handling Best Practices
1. Always Check the Response Status
const response = await fetch("/api/users/profile", {
headers: {
"access-token": token,
"device-id": deviceId
}
});
if (!response.ok) {
const error = await response.json();
throw new Error(`API Error: ${error.error.message}`);
}
const data = await response.json();
2. Handle Different Error Types
class APIError extends Error {
constructor(code, message, metadata = {}) {
super(message);
this.code = code;
this.metadata = metadata;
this.name = "APIError";
}
}
async function makeAPIRequest(endpoint, options) {
try {
const response = await fetch(endpoint, options);
const data = await response.json();
if (!data.success) {
throw new APIError(
data.error.code,
data.error.message,
data.error.metadata
);
}
return data.data;
} catch (error) {
if (error instanceof APIError) {
switch (error.code) {
case "UNAUTHORIZED":
// Redirect to login
window.location.href = "/login";
break;
case "VALIDATION_FAILED":
// Show validation errors to user
showValidationErrors(error.metadata.fields);
break;
case "INSUFFICIENT_FUNDS":
// Show payment options
showPaymentDialog();
break;
default:
// Generic error handling
showErrorMessage(error.message);
}
}
throw error;
}
}
3. Implement Retry Logic
async function makeRequestWithRetry(endpoint, options, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(endpoint, options);
if (response.status === 429) {
// Rate limited, wait and retry
const retryAfter = response.headers.get("Retry-After") || 1;
await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
continue;
}
if (response.status >= 500 && attempt < maxRetries) {
// Server error, wait and retry
await new Promise((resolve) => setTimeout(resolve, 1000 * attempt));
continue;
}
return response;
} catch (error) {
if (attempt === maxRetries) throw error;
await new Promise((resolve) => setTimeout(resolve, 1000 * attempt));
}
}
}
4. User-Friendly Error Messages
function getDisplayMessage(errorCode, message) {
const friendlyMessages = {
UNAUTHORIZED: "Please log in to continue",
VALIDATION_FAILED: "Please check your input and try again",
NOT_FOUND: "The requested item could not be found",
PRODUCT_OUT_OF_STOCK: "This item is currently out of stock",
INSUFFICIENT_FUNDS: "Insufficient balance for this transaction",
RATE_LIMITED: "Too many requests. Please wait a moment and try again"
};
return friendlyMessages[errorCode] || message;
}
Rate Limiting
The API implements rate limiting to ensure fair usage:- Standard endpoints: 100 requests per minute
- Authentication endpoints: 10 requests per minute
- Upload endpoints: 10 requests per minute
{
"success": false,
"error": {
"code": "RATE_LIMITED",
"message": "Too many requests. Please try again later.",
"metadata": {
"retry_after": 60,
"limit": 100,
"remaining": 0
}
}
}
Logging and Monitoring
For production applications, implement proper error logging:function logError(error, context = {}) {
console.error("API Error:", {
code: error.code,
message: error.message,
metadata: error.metadata,
context: context,
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent,
url: window.location.href
});
// Send to monitoring service
if (window.errorTracker) {
window.errorTracker.captureException(error, context);
}
}
Next Steps
Authentication
Learn about API authentication
Pagination
Handle paginated responses

