Error Handling
Common error responses and status codes.
All error responses follow a consistent format:
{
"statusCode": 400,
"message": "Description of what went wrong",
"error": "Bad Request"
}
Common status codes:
• 400 Bad Request — Invalid request body or parameters
• 401 Unauthorized — Missing or invalid API key
• 403 Forbidden — API key doesn't have access to this resource (see scope errors below)
• 404 Not Found — Resource doesn't exist or doesn't belong to you
• 429 Too Many Requests — Rate limit exceeded
• 500 Internal Server Error — Something went wrong on our end
For 429 errors, check the X-RateLimit-Reset header for when you can retry.
Insufficient scope errors (403):
When an API key lacks the required scope for an endpoint, you get a structured 403 response:
{
"statusCode": 403,
"error": "insufficient_scope",
"message": "This API key does not have permission to access POST /v1/send. Required scope: sending.",
"required_scopes": ["sending"],
"key_scopes": ["reading"],
"hint": "Create a new API key with \"sending\" or \"full_access\" scope in the Posthawk dashboard under API Keys.",
"scope_reference": {
"sending": "Send emails, render templates, schedule/cancel/reschedule emails"
}
}
The response tells you exactly which scope is needed and what your key currently has. To fix this, create a new API key with the correct scope in the dashboard.
Scope requirements by endpoint:
• POST /v1/send, POST /v1/render → sending
• GET /v1/send/:jobId, GET /v1/queue/stats → reading
• POST /scheduled, DELETE /scheduled/:id, PATCH /scheduled/:id/reschedule → sending
• GET /scheduled, GET /scheduled/:id → reading
• full_access keys can access all endpoints
Domain sending limits (cloud edition):
When per-domain sending limits are configured, exceeding them returns an error:
• "Daily sending limit reached for example.com (1,000 emails/day)."
• "Monthly sending limit reached for example.com (25,000 emails/month)."
These limits apply to both the REST API (/v1/send) and SMTP relay (port 587). Configure them via PATCH /v1/domains/:id/limits or the dashboard.