API Reference
Base URL
https://api.optail.io/v1
For self-hosted instances, replace with your API server URL.
Authentication
All API requests require a Bearer token in the Authorization header:
Authorization: Bearer ms_live_your_api_key_here
API keys are created in the dashboard under Settings > API Keys. Each key has scoped permissions:
| Permission | Access |
|---|---|
SEND | Send emails |
TEMPLATES_READ | Read templates |
TEMPLATES_WRITE | Create, update, delete templates |
PROVIDERS_READ | Read provider accounts |
PROVIDERS_WRITE | Connect, update, delete providers |
METRICS_READ | Read delivery metrics |
SETTINGS_WRITE | Manage organization settings |
Rate Limits
| Endpoint | Limit |
|---|---|
POST /v1/send | 100 requests/second per organization |
| All other endpoints | 1,000 requests/second per organization |
| Unauthenticated | 20 requests/minute per IP |
Rate limit headers are included in every response:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
Retry-After: 1 (only on 429 responses)
Error Format
All errors follow a consistent JSON structure:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": {
"issues": [
{
"path": "to",
"message": "Invalid email"
}
]
}
}
}
Error Codes
| HTTP Status | Code | Description |
|---|---|---|
| 400 | VALIDATION_ERROR | Request body or query params failed validation |
| 401 | AUTHENTICATION_ERROR | Missing or invalid API key |
| 404 | NOT_FOUND | Resource does not exist |
| 409 | CONFLICT | Resource already exists (e.g., duplicate suppression) |
| 422 | VALIDATION_ERROR | Semantic validation failed (e.g., no active provider) |
| 429 | RATE_LIMIT_EXCEEDED | Too many requests; check Retry-After header |
| 500 | INTERNAL_ERROR | Unexpected server error |
Pagination
List endpoints support pagination via query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number (1-indexed) |
limit | integer | 20 | Items per page (max 100) |
Paginated responses include a pagination object:
{
"data": [...],
"pagination": {
"page": 1,
"limit": 20,
"total": 142,
"totalPages": 8
}
}