> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xem.email/llms.txt
> Use this file to discover all available pages before exploring further.

# Error Handling

> Learn how to handle API errors properly

# Error Handling

Posthoot API uses standard HTTP status codes and provides detailed error messages to help you understand and resolve issues.

## 📋 HTTP Status Codes

### 2xx Success

* **200 OK**: Request successful
* **201 Created**: Resource created successfully

### 4xx Client Errors

* **400 Bad Request**: Invalid request data
* **401 Unauthorized**: Authentication required
* **403 Forbidden**: Insufficient permissions
* **404 Not Found**: Resource not found
* **409 Conflict**: Resource conflict
* **422 Unprocessable Entity**: Validation errors
* **429 Too Many Requests**: Rate limit exceeded

### 5xx Server Errors

* **500 Internal Server Error**: Server error
* **502 Bad Gateway**: Gateway error
* **503 Service Unavailable**: Service temporarily unavailable

## 🚨 Error Response Format

All error responses follow this format:

```json theme={"dark"}
{
  "error": "error_type",
  "message": "Human-readable error message",
  "details": {
    "field": "Additional error details"
  },
  "code": "ERROR_CODE",
  "timestamp": "2024-01-01T00:00:00Z"
}
```

## 🔍 Common Error Types

### Validation Errors (400)

```json theme={"dark"}
{
  "error": "validation_error",
  "message": "Invalid request data",
  "details": {
    "email": "Invalid email format",
    "password": "Password must be at least 8 characters"
  },
  "code": "VALIDATION_ERROR"
}
```

### Authentication Errors (401)

```json theme={"dark"}
{
  "error": "unauthorized",
  "message": "Invalid or expired token",
  "code": "INVALID_TOKEN"
}
```

### Permission Errors (403)

```json theme={"dark"}
{
  "error": "forbidden",
  "message": "Insufficient permissions for this resource",
  "code": "INSUFFICIENT_PERMISSIONS"
}
```

### Not Found Errors (404)

```json theme={"dark"}
{
  "error": "not_found",
  "message": "Campaign not found",
  "code": "RESOURCE_NOT_FOUND"
}
```

### Rate Limit Errors (429)

```json theme={"dark"}
{
  "error": "rate_limit_exceeded",
  "message": "Rate limit exceeded. Try again in 60 seconds.",
  "retry_after": 60,
  "code": "RATE_LIMIT_EXCEEDED"
}
```

## 🛠️ Error Handling Examples

### JavaScript/Node.js

```javascript theme={"dark"}
async function makeApiCall() {
  try {
    const response = await fetch('/api/v1/campaigns', {
      headers: {
        'Authorization': `Bearer ${token}`
      }
    });

    if (!response.ok) {
      const error = await response.json();
      
      switch (response.status) {
        case 401:
          // Handle authentication error
          await refreshToken();
          break;
        case 403:
          // Handle permission error
          console.error('Insufficient permissions');
          break;
        case 429:
          // Handle rate limit
          const retryAfter = error.retry_after || 60;
          await delay(retryAfter * 1000);
          return makeApiCall();
        default:
          throw new Error(error.message);
      }
    }

    return await response.json();
  } catch (error) {
    console.error('API Error:', error);
    throw error;
  }
}
```

### Python

```python theme={"dark"}
import requests
import time

def make_api_call():
    try:
        response = requests.get(
            'https://api.posthoot.com/api/v1/campaigns',
            headers={'Authorization': f'Bearer {token}'}
        )
        
        if response.status_code == 401:
            # Handle authentication error
            refresh_token()
            return make_api_call()
        elif response.status_code == 429:
            # Handle rate limit
            error = response.json()
            retry_after = error.get('retry_after', 60)
            time.sleep(retry_after)
            return make_api_call()
        elif response.status_code >= 400:
            # Handle other errors
            error = response.json()
            raise Exception(error['message'])
            
        return response.json()
        
    except requests.exceptions.RequestException as e:
        print(f"Request error: {e}")
        raise
```

### cURL

```bash theme={"dark"}
# Check for errors in response
response=$(curl -s -w "%{http_code}" \
  -H "Authorization: Bearer $TOKEN" \
  https://api.posthoot.com/api/v1/campaigns)

http_code="${response: -3}"
body="${response%???}"

if [ "$http_code" -eq 401 ]; then
    echo "Authentication error: $body"
elif [ "$http_code" -eq 429 ]; then
    echo "Rate limit exceeded: $body"
elif [ "$http_code" -ge 400 ]; then
    echo "Error $http_code: $body"
else
    echo "Success: $body"
fi
```

## 🔄 Retry Strategies

### Exponential Backoff

```javascript theme={"dark"}
async function retryWithBackoff(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.status === 429) {
        const retryAfter = error.retry_after || Math.pow(2, i) * 1000;
        await delay(retryAfter);
        continue;
      }
      throw error;
    }
  }
  throw new Error('Max retries exceeded');
}
```

### Circuit Breaker

```javascript theme={"dark"}
class CircuitBreaker {
  constructor(failureThreshold = 5, timeout = 60000) {
    this.failureThreshold = failureThreshold;
    this.timeout = timeout;
    this.failures = 0;
    this.lastFailure = null;
    this.state = 'CLOSED';
  }

  async call(fn) {
    if (this.state === 'OPEN') {
      if (Date.now() - this.lastFailure > this.timeout) {
        this.state = 'HALF_OPEN';
      } else {
        throw new Error('Circuit breaker is OPEN');
      }
    }

    try {
      const result = await fn();
      this.onSuccess();
      return result;
    } catch (error) {
      this.onFailure();
      throw error;
    }
  }

  onSuccess() {
    this.failures = 0;
    this.state = 'CLOSED';
  }

  onFailure() {
    this.failures++;
    this.lastFailure = Date.now();
    
    if (this.failures >= this.failureThreshold) {
      this.state = 'OPEN';
    }
  }
}
```

## 📊 Error Monitoring

### Log Errors

```javascript theme={"dark"}
function logError(error, context = {}) {
  console.error({
    timestamp: new Date().toISOString(),
    error: error.message,
    status: error.status,
    code: error.code,
    context,
    stack: error.stack
  });
}
```

### Error Tracking

```javascript theme={"dark"}
// Send errors to monitoring service
function trackError(error) {
  fetch('/api/errors', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      error: error.message,
      status: error.status,
      code: error.code,
      userAgent: navigator.userAgent,
      url: window.location.href
    })
  });
}
```

## 🛡️ Best Practices

### 1. Always Check Status Codes

```javascript theme={"dark"}
if (!response.ok) {
  const error = await response.json();
  throw new Error(error.message);
}
```

### 2. Handle Specific Error Types

```javascript theme={"dark"}
switch (error.code) {
  case 'INVALID_TOKEN':
    await refreshToken();
    break;
  case 'RATE_LIMIT_EXCEEDED':
    await delay(error.retry_after * 1000);
    break;
  default:
    console.error('Unknown error:', error);
}
```

### 3. Provide User-Friendly Messages

```javascript theme={"dark"}
const errorMessages = {
  'VALIDATION_ERROR': 'Please check your input and try again',
  'INVALID_TOKEN': 'Please log in again',
  'RATE_LIMIT_EXCEEDED': 'Too many requests. Please wait a moment.',
  'INSUFFICIENT_PERMISSIONS': 'You don\'t have permission to perform this action'
};

const userMessage = errorMessages[error.code] || error.message;
```

### 4. Implement Proper Logging

```javascript theme={"dark"}
function handleError(error, context) {
  // Log for debugging
  console.error('API Error:', { error, context });
  
  // Show user-friendly message
  showUserMessage(getUserMessage(error));
  
  // Track for monitoring
  trackError(error);
}
```

## 📚 Related Topics

* [Authentication](/authentication) - Handle authentication errors
* [Rate Limiting](/rate-limiting) - Handle rate limit errors
* [Quickstart Guide](/guides/quickstart) - Learn error handling basics
