Error Codes
Every Sendr API error code with cause and resolution.
All API errors return JSON with this shape:
{
"statusCode": 403,
"code": "insufficient_scope",
"message": "This API key requires 'full_access' scope or higher. Current scope: 'read_only'.",
"details": {}
}
Authentication errors (401)
unauthorized
Status: 401
Cause: The Authorization header is missing, malformed, or the API key does not exist.
Fix:
- Check that you're sending
Authorization: Bearer <api_key> - Verify the key exists in your dashboard under API Keys
- Ensure there are no extra spaces or characters in the key
expired_key
Status: 401
Cause: The API key has passed its expiration date.
Fix: Create a new API key in the dashboard and update your environment variable.
Authorization errors (403)
insufficient_scope
Status: 403
Cause: The API key's scope does not have permission to call this endpoint.
full_access > sending_access > read_only
Fix: Create an API key with the required scope. Scope requirements per endpoint:
- Sending endpoints:
sending_accessor higher - Create/delete endpoints:
full_access - Read endpoints:
read_onlyor higher
domain_not_verified
Status: 403
Cause: The from address uses a domain that has not been verified with Sendr.
Fix:
- Add the domain in the dashboard under Domains
- Configure the DNS records (SPF, DKIM, DMARC)
- Click Verify and wait for DNS propagation
- Alternatively, use a test-mode API key for development
plan_limit_reached
Status: 403
Cause: Your plan's resource limit has been reached (e.g., max domains, API keys, templates, or webhooks).
Fix: Either delete unused resources or upgrade your plan.
Payment errors (402)
payment_required
Status: 402
Cause: Your account is on a paid plan and has exceeded the monthly email quota, but no valid payment method is on file. Overage billing requires a payment method.
Fix: Add a payment method in the dashboard under Billing.
billing_suspended
Status: 402
Cause: Your account has been suspended due to a failed payment that was not resolved.
Fix: Update your payment method in the dashboard under Billing. Once payment succeeds, the account is automatically reinstated.
Rate limit errors (429)
daily_limit_reached
Status: 429
Cause: Your organization has hit the daily email sending limit for your plan.
| Plan | Daily limit |
|---|---|
| Free | 100 |
| Pro+ | Unlimited |
Fix: Wait until midnight UTC for the counter to reset, or upgrade to a paid plan.
monthly_limit_reached
Status: 429
Cause: Your organization has hit the monthly email quota on a plan without overage support (Free plan).
Fix: Upgrade to Pro or Business to enable overage billing, or wait until the next billing period.
overage_limit_reached
Status: 429
Cause: Your organization has hit the overage cap for this billing period. The cap is 3× the monthly quota.
| Plan | Monthly quota | Max overage | Total max |
|---|---|---|---|
| Pro | 50,000 | 150,000 | 200,000 |
| Business | 200,000 | 600,000 | 800,000 |
Fix: Wait until the next billing period, or contact support to request a temporary limit increase.
rate_limited
Status: 429
Cause: Too many API requests in a short period.
Fix: Implement exponential backoff. The Retry-After response header tells you how many seconds to wait.
try {
await sendr.emails.send(payload);
} catch (error) {
if (error instanceof RateLimitError) {
const delay = (error.retryAfter ?? 1) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
// Retry
}
}
See Rate Limits guide for full retry patterns.
Validation errors (422)
validation_error
Status: 422
Cause: The request body failed schema validation.
Response includes details:
{
"statusCode": 422,
"code": "validation_error",
"message": "Request validation failed",
"details": {
"errors": [
{"path": "/subject", "message": "Required"},
{"path": "/to", "message": "Expected string or array of strings"}
]
}
}
Fix: Check the details.errors array for which fields failed validation and why.
Request errors (413)
payload_too_large
Status: 413
Cause: The request body exceeds the size limit. Limits:
- HTML body: 5 MB
- Text body: 1 MB
- Total email payload: typically 40 MB (including attachments)
Fix: Reduce HTML size or compress attachments. For large files, consider using a link to the file rather than attaching it.
Resource errors (404)
not_found
Status: 404
Cause: The requested resource does not exist or belongs to a different organization.
Fix: Check the resource ID. IDs are organization-scoped — you cannot access another organization's resources.
Server errors (500)
Status: 500
Cause: An internal server error occurred on Sendr's side.
Fix: These are transient. Retry with exponential backoff. Check status.sendr.dev for active incidents.
ID formats
Resources use nanoid with type prefixes. If you're passing the wrong ID type, you'll get not_found.
| Resource | Prefix example |
|---|---|
em_abc123 | |
| Domain | dom_abc123 |
| Template | tmpl_abc123 |
| Webhook | wh_abc123 |
| API key | ak_abc123 |
| Contact | con_abc123 |
| Audience | aud_abc123 |
| Campaign | camp_abc123 |