The Send.dev API uses conventional HTTP status codes and returns detailed error information in JSON format. This page covers all error types and how to handle them.
Error Response Format
All errors follow a consistent format:
{
"error": {
"code": "error_code",
"message": "Human-readable error message",
"details": [...],
"docs_url": "https://send.dev/docs/guides/errors#error_code"
}
}| Field | Description |
|---|---|
code | Machine-readable error code |
message | Human-readable description |
details | Additional context (validation errors, etc.) |
docs_url | Link to relevant documentation |
HTTP Status Codes
| Status | Meaning |
|---|---|
200 | Success |
201 | Created |
400 | Bad Request - Invalid parameters |
401 | Unauthorized - Invalid/missing API key |
403 | Forbidden - Valid key, insufficient permissions |
404 | Not Found - Resource doesn't exist |
409 | Conflict - Resource already exists |
422 | Unprocessable Entity - Validation failed |
429 | Too Many Requests - Rate limited |
500 | Internal Server Error - Our fault |
503 | Service Unavailable - Temporary outage |
Common Error Codes
Authentication Errors
unauthorized
{
"error": {
"code": "unauthorized",
"message": "Invalid API key provided"
}
}Cause: Missing or invalid API key in Authorization header.
Solution: Verify your API key is correct and properly formatted as Bearer sk_live_...
forbidden
{
"error": {
"code": "forbidden",
"message": "API key not authorized for this action"
}
}Cause: Valid API key but lacks permission (e.g., domain-restricted key).
Solution: Check API key permissions or use a key with appropriate access.
Validation Errors
validation_error
{
"error": {
"code": "validation_error",
"message": "Invalid request parameters",
"details": [
{ "field": "to", "message": "Invalid email address format" },
{ "field": "subject", "message": "Subject is required" }
]
}
}Cause: Request body contains invalid data.
Solution: Fix the fields listed in details and retry.
Domain Errors
domain_not_verified
{
"error": {
"code": "domain_not_verified",
"message": "Domain 'mail.example.com' is not verified"
}
}Cause: Trying to send from an unverified domain.
Solution: Complete domain verification at Domains.
domain_not_authorized
{
"error": {
"code": "domain_not_authorized",
"message": "API key not authorized to send from 'other.domain.com'",
"authorized_domains": ["mail.yourdomain.com"]
}
}Cause: API key is restricted to specific domains.
Solution: Use an authorized domain or update API key permissions.
Rate Limiting
rate_limited
{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded",
"retry_after": 60
}
}Cause: Too many requests in the current time window.
Solution: Wait retry_after seconds before retrying. See Rate Limits.
Resource Errors
not_found
{
"error": {
"code": "not_found",
"message": "Email not found",
"resource_type": "email",
"resource_id": "email_01HXYZ123456789"
}
}Cause: The requested resource doesn't exist.
Solution: Verify the resource ID is correct.
already_exists
{
"error": {
"code": "already_exists",
"message": "Domain already exists",
"resource_type": "domain",
"existing_id": "dom_01HXYZ123456789"
}
}Cause: Attempting to create a duplicate resource.
Solution: Use the existing resource or choose a different identifier.
Email Errors
attachment_too_large
{
"error": {
"code": "attachment_too_large",
"message": "Attachment exceeds maximum size",
"max_size_bytes": 10485760,
"actual_size_bytes": 15728640
}
}Cause: File attachment exceeds the 10 MB limit.
Solution: Compress the file or host it externally.
invalid_recipient
{
"error": {
"code": "invalid_recipient",
"message": "Recipient address is invalid or blocked",
"recipient": "bounced@example.com",
"reason": "hard_bounce"
}
}Cause: Recipient address is invalid or has been blocked.
Solution: Remove the address from your list.
Server Errors
internal_error
{
"error": {
"code": "internal_error",
"message": "An unexpected error occurred",
"request_id": "req_01HXYZ123456789"
}
}Cause: Something went wrong on our end.
Solution: Retry with exponential backoff. If persistent, contact support with the request_id.
Error Handling Examples
Node.js / TypeScript
import { SendDev, SendDevError } from '@send.dev/sdk';
const send = new SendDev({ apiKey: process.env.SEND_API_KEY });
try {
const email = await send.emails.send({
from: 'hello@mail.yourdomain.com',
to: 'user@example.com',
subject: 'Hello',
html: '<p>Hello!</p>',
});
} catch (error) {
if (error instanceof SendDevError) {
switch (error.code) {
case 'rate_limited':
await sleep(error.retryAfter * 1000);
// Retry the request
break;
case 'validation_error':
console.error('Validation failed:', error.details);
break;
case 'domain_not_verified':
console.error('Please verify your domain first');
break;
default:
console.error(`Error: ${error.message}`);
}
}
}Python
from senddev import SendDev, SendDevError
import time
send = SendDev(api_key="sk_live_your_api_key")
try:
email = send.emails.send(
from_="hello@mail.yourdomain.com",
to="user@example.com",
subject="Hello",
html="<p>Hello!</p>",
)
except SendDevError as error:
if error.code == "rate_limited":
time.sleep(error.retry_after)
# Retry the request
elif error.code == "validation_error":
print(f"Validation failed: {error.details}")
elif error.code == "domain_not_verified":
print("Please verify your domain first")
else:
print(f"Error: {error.message}")Best Practices
- Always check error codes - Use
codefor programmatic handling - Log request IDs - Include
request_idin error logs for debugging - Implement retries - Use exponential backoff for transient errors
- Handle rate limits gracefully - Queue requests and respect
retry_after - Validate before sending - Catch validation errors early
- Monitor error rates - Set up alerts for unusual error spikes
Getting Help
If you encounter persistent errors:
- Check the Status Page for service issues
- Search our documentation for solutions
- Contact us or email help@do.dev with:
- Error code and message
- Request ID (if available)
- Request payload (sanitize sensitive data)
- Timestamp of the error