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

# Errors

> Handle API errors gracefully with proper error codes and messages.

# Errors

The Zeplo API uses standard HTTP status codes and returns consistent error responses.

## Error response format

All errors follow this structure:

```json theme={null}
{
  "error": "Error type",
  "message": "Human-readable description of the error",
  "code": "ERROR_CODE",
  "details": {}
}
```

## HTTP status codes

| Status | Meaning |
| - | - |
| `200` | Success |
| `201` | Resource created |
| `400` | Bad request — invalid parameters or body |
| `401` | Unauthorized — missing or invalid authentication |
| `403` | Forbidden — insufficient permissions |
| `404` | Not found — resource does not exist |
| `409` | Conflict — resource already exists |
| `422` | Validation error — request body failed validation |
| `429` | Rate limit exceeded |
| `500` | Internal server error |
| `503` | Service unavailable |

## Common error codes

### Authentication errors

| Code | HTTP | Description |
| - | - | - |
| `INVALID_API_KEY` | 401 | The API key is invalid or revoked |
| `INVALID_API_SECRET` | 401 | The API secret key is invalid |
| `MISSING_API_KEY` | 401 | No API key provided |
| `MISSING_API_SECRET` | 401 | No API secret key provided |
| `SESSION_EXPIRED` | 401 | Session has expired |
| `INVALID_CREDENTIALS` | 401 | Wrong username or password |
| `INSUFFICIENT_PERMISSIONS` | 403 | Lacks required permission for this action |

### Resource errors

| Code | HTTP | Description |
| - | - | - |
| `RESOURCE_NOT_FOUND` | 404 | Requested resource does not exist |
| `CHANNEL_NOT_FOUND` | 404 | WhatsApp channel not found |
| `CONTACT_NOT_FOUND` | 404 | Contact not found |
| `TEMPLATE_NOT_FOUND` | 404 | Template not found |
| `DUPLICATE_RESOURCE` | 409 | Resource already exists |

### Validation errors

| Code | HTTP | Description |
| - | - | - |
| `VALIDATION_ERROR` | 422 | Request body failed validation |
| `INVALID_PHONE_NUMBER` | 400 | Phone number format is invalid |
| `INVALID_TEMPLATE` | 400 | Template is not approved or not found |

### Subscription errors

| Code | HTTP | Description |
| - | - | - |
| `SUBSCRIPTION_REQUIRED` | 403 | Active subscription required |
| `SUBSCRIPTION_EXPIRED` | 403 | Subscription has expired |
| `QUOTA_EXCEEDED` | 403 | Subscription quota exceeded |

### WhatsApp errors

| Code | HTTP | Description |
| - | - | - |
| `WHATSAPP_API_ERROR` | 502 | Upstream WhatsApp API error |
| `MEDIA_UPLOAD_FAILED` | 500 | Failed to upload media to WhatsApp |
| `TEMPLATE_REJECTED` | 400 | WhatsApp rejected the template submission |

## Handling errors

**Node.js**

```javascript theme={null}
const response = await fetch('https://zeplo.ai/api/v1/messages/template', {
  method: 'POST',
  headers: {
    'x-api-key': API_KEY,
    'x-api-secret': API_SECRET,
    'x-channel-id': CHANNEL_ID,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(payload),
});

if (!response.ok) {
  const error = await response.json();
  switch (response.status) {
    case 401:
      throw new Error('Invalid API key');
    case 429:
      const retryAfter = response.headers.get('Retry-After');
      throw new Error(`Rate limited. Retry after ${retryAfter}s`);
    default:
      throw new Error(error.message);
  }
}
```

**Python**

```python theme={null}
response = requests.post(url, headers=headers, json=payload)

if not response.ok:
    error = response.json()
    if response.status_code == 401:
        raise Exception("Invalid API key")
    elif response.status_code == 429:
        retry_after = response.headers.get("Retry-After")
        raise Exception(f"Rate limited. Retry after {retry_after}s")
    else:
        raise Exception(error.get("message", "Unknown error"))
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.