Error Handling

Understanding and handling API errors

Error Response Format

All errors follow a consistent JSON format:

{ "success": false, "error": "Error name", "message": "Human-readable description" }

HTTP Status Codes

Code Meaning Cause
200 OK Request succeeded
201 Created Resource created successfully
400 Bad Request Invalid request parameters
401 Unauthorized Invalid or missing token
403 Forbidden Access denied (plan/subscription issue)
404 Not Found Resource doesn't exist
422 Unprocessable Entity Validation errors in request
429 Too Many Requests Rate limit exceeded
500 Server Error Internal server error

Common Errors

401 Unauthorized - Invalid Token

{ "success": false, "error": "Unauthorized" }

Causes:

Solution: Verify your token and authorization header format.

403 Forbidden - API Access Denied

{ "success": false, "error": "API access is not available on your plan", "message": "Upgrade your subscription to use the API", "current_plan": "free" }

Causes:

Solution: Upgrade to Starter plan or higher.

403 Forbidden - Subscription Expired

{ "success": false, "error": "Your subscription has expired", "expired_at": "2025-01-20T00:00:00Z" }

Solution: Renew your subscription from billing settings.

404 Not Found

{ "message": "Resource not found" }

Causes:

Solution: Verify the endpoint and resource ID.

422 Unprocessable Entity - Validation Error

{ "message": "The given data was invalid.", "errors": { "email": ["The email has already been taken."], "url": ["The url field is required."] } }

Causes:

Solution: Check the errors object and provide valid data.

429 Too Many Requests - Rate Limited

{ "success": false, "error": "Rate limit exceeded", "message": "You have exceeded the API rate limit of 5 requests per minute", "limit": 5, "reset_at": "2025-01-27T15:31:00Z" }

Solution: Wait for the reset time or upgrade your plan.

500 Server Error

{ "message": "Server error" }

Causes:

Solution: Retry the request after a delay. Contact support if persistent.

Error Handling Examples

JavaScript

async function callAPI(endpoint, options = {}) { try { const response = await fetch(endpoint, { headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, ...options }); const data = await response.json(); if (!response.ok) { switch(response.status) { case 401: throw new Error('Authentication failed. Check your token.'); case 403: if (data.error.includes('plan')) { throw new Error('API not available on your plan. Upgrade to continue.'); } throw new Error('Access denied.'); case 422: const errors = Object.entries(data.errors || {}) .map(([key, msgs]) => `${key}: ${msgs.join(', ')}`) .join('\n'); throw new Error(`Validation error:\n${errors}`); case 429: throw new Error(`Rate limited. Retry after ${data.reset_at}`); default: throw new Error(data.message || 'API error'); } } return data; } catch (error) { console.error('API Error:', error.message); throw error; } }

Python

import requests from datetime import datetime def call_api(endpoint, method='GET', data=None): headers = { 'Authorization': f'Bearer {token}', 'Content-Type': 'application/json' } try: response = requests.request( method, f'{base_url}{endpoint}', headers=headers, json=data ) if response.status_code == 401: raise Exception('Authentication failed. Check your token.') elif response.status_code == 403: error = response.json() if 'plan' in error.get('error', ''): raise Exception('API not available on your plan. Upgrade to continue.') raise Exception('Access denied.') elif response.status_code == 422: errors = response.json().get('errors', {}) error_str = '\n'.join([ f'{k}: {", ".join(v)}' for k, v in errors.items() ]) raise Exception(f'Validation error:\n{error_str}') elif response.status_code == 429: reset_at = response.json().get('reset_at') raise Exception(f'Rate limited. Retry after {reset_at}') elif response.status_code >= 400: raise Exception(response.json().get('message', 'API error')) return response.json() except requests.RequestException as e: raise Exception(f'Network error: {e}')

Retry Strategy

Exponential Backoff

async function apiCallWithRetry(endpoint, maxRetries = 3) { for (let attempt = 0; attempt < maxRetries; attempt++) { try { const response = await fetch(endpoint, { headers: { 'Authorization': `Bearer ${token}` } }); if (response.ok) { return response.json(); } if (response.status === 429) { // Rate limited - exponential backoff const delay = Math.pow(2, attempt) * 1000; console.log(`Rate limited. Waiting ${delay}ms...`); await new Promise(r => setTimeout(r, delay)); continue; } if (response.status >= 500) { // Server error - retry with backoff if (attempt < maxRetries - 1) { const delay = Math.pow(2, attempt) * 1000; console.log(`Server error. Retrying in ${delay}ms...`); await new Promise(r => setTimeout(r, delay)); continue; } } // Don't retry for client errors (4xx except 429) const data = await response.json(); throw new Error(data.message || data.error); } catch (error) { if (attempt === maxRetries - 1) throw error; } } }

Logging Errors

// Log errors but never log tokens function logError(error, context = {}) { console.error({ timestamp: new Date().toISOString(), error: error.message, status: error.status, endpoint: context.endpoint, // Never log tokens! // ❌ token: context.token, userAgent: navigator.userAgent }); }

Support

If you encounter errors not listed here or need help:

Next: FAQ →