Error Handling
FWD uses standard HTTP status codes and returns consistent JSON error responses. This guide covers error formats, common codes, and troubleshooting steps.
Error Response Format
All error responses follow this format:
{
"error": "Human-readable error description"
}Successful responses follow this format (for dashboard API routes):
{
"success": true,
"data": { ... },
"message": "Operation completed successfully"
}HTTP Status Codes
| Code | Meaning | Common Causes |
|---|---|---|
| 200 | Success | Request processed successfully |
| 201 | Created | Resource created (API key, template, webhook) |
| 400 | Bad Request | Missing fields, invalid email format, suppressed recipient, invalid domain format |
| 401 | Unauthorized | Missing, invalid, or revoked API key |
| 403 | Forbidden | Plan limit exceeded (domains, templates) |
| 404 | Not Found | Template, webhook, or email not found |
| 429 | Rate Limited | Monthly email limit reached |
| 500 | Server Error | Internal failure — retry with exponential backoff |
Common Errors & Solutions
Missing API Key
{ "error": "Missing API key. Include x-api-key header." }Solution: Add the x-api-key header with your API key to every request.
Invalid API Key
{ "error": "Invalid or revoked API key" }Solution: Check that your API key is correct and has not been revoked. Generate a new key from the dashboard if needed.
Missing Required Fields
{ "error": "Missing fields: to, subject, and html or text required" }Solution: Ensure your request body includes to, subject, and either html or text (or use templateId).
Suppressed Recipient
{ "error": "Email to user@example.com blocked: recipient is on suppression list (bounce)" }Solution: The recipient's address previously bounced and was added to the suppression list. Remove it manually or contact support.
Unverified Domain
{ "error": "Domain 'yourdomain.com' is not verified. Add and verify it in your dashboard first." }Solution: Verify your domain in the Domains section before using it as a custom sender.
Best Practices
- Always check the HTTP status code before parsing the response body
- Implement exponential backoff for
500errors (retry after 1s, 2s, 4s…) - Monitor
X-RateLimit-Remainingheaders to avoid hitting limits - Log error responses for debugging — the
errorfield contains actionable details - Use webhooks to track delivery status rather than polling