Error Codes
Every Sendry 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 Sendry.
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.
Automation runs also use this code once a plan's monthly run quota is used up.
automation_not_available
Status: 403
Cause: Your plan includes no automation runs at all. The Free plan does not include automations, so every trigger, event, schedule, segment join, or manual run is refused before any run is created.
Fix: Upgrade to Pro or higher. Existing automations stay in place and start running again after the upgrade.
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 sendry.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 Sendry's side.
Fix: These are transient. Retry with exponential backoff. Check status.sendry.online 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 |
|---|---|
email_abc123 | |
| Domain | dom_abc123 |
| Template | tmpl_abc123 |
| Webhook | wh_abc123 |
| API key | key_abc123 |
| Contact | ct_abc123 |
| Audience | aud_abc123 |
| Segment | seg_abc123 |
| Campaign | cp_abc123 |
| Event | evt_abc123 |
| Inbound | inb_abc123 |