Rate Limits
Understand API rate limits and how to handle them.
Rate Limits
send0 enforces rate limits to ensure fair usage and platform stability. Limits apply per API key and vary by plan tier.
Rate limit headers
Every API response includes rate limit headers so you can track your usage in real time.
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 94
X-RateLimit-Reset: 1712922000When you hit the limit, the response also includes a Retry-After header:
Retry-After: 47| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed per minute |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
Retry-After | Seconds to wait before retrying (only on 429 responses) |
Limits by tier
| Tier | Requests/min | Emails/month |
|---|---|---|
| Free | 100 | 3,000 |
| Growth | 500 | 50,000 |
| Scale | 2,000 | Unlimited |
Send operations and read operations have separate rate limits. Sending an email and listing emails count against different buckets, so high read volume won't block your sends.
SDK behavior
The SDK handles 429 responses automatically with exponential backoff. If a request is rate limited, the SDK waits for the duration specified in the Retry-After header and retries the request. No additional code is needed.
import { Send0 } from 'send0';
// Automatic retry on 429 — no extra configuration required
const send0 = new Send0('sk_live_...');
await send0.emails.send({
from: 'hello@yourdomain.com',
to: 'user@example.com',
subject: 'Hello',
html: '<p>Hello</p>',
});Manual handling
If you need to handle rate limits manually — for example, to log them or implement custom retry logic — catch the Send0RateLimitError.
import { Send0RateLimitError } from 'send0';
try {
await send0.emails.send({
from: 'hello@yourdomain.com',
to: 'user@example.com',
subject: 'Hello',
html: '<p>Hello</p>',
});
} catch (err) {
if (err instanceof Send0RateLimitError) {
const waitMs = (err.retryAfter ?? 60) * 1000;
console.log(`Rate limited. Retrying in ${waitMs / 1000}s...`);
await new Promise(r => setTimeout(r, waitMs));
// retry the request
}
}Best practices
- Check headers proactively. Monitor
X-RateLimit-Remainingand slow down before hitting the limit rather than reacting to 429 errors. - Use exponential backoff. If you implement custom retry logic, use exponential backoff with jitter to avoid thundering herd problems.
- Batch where possible. Instead of sending 100 individual requests, check if the API supports batch operations to reduce request count.
- Separate send and read traffic. Since sends and reads have independent limits, separate your send and read logic to maximise throughput.
- Upgrade your plan if you consistently hit limits. Growth and Scale tiers offer significantly higher throughput.