Rate Limits

API requests are rate limited to ensure fair usage and system stability.

Rate Limits by Plan

PlanRequests/minEmails/dayStorage
Free601001 GB
Hobby300Unlimited*10 GB
Pro1,000Unlimited*100 GB
EnterpriseCustomUnlimited*Custom

* Usage-based pricing applies. See pricing for details.

Email-Specific Limits

Limit TypeValueDescription
Batch size100Max emails per batch request
Broadcast recipients1,000Max recipients per broadcast
Email size25 MBMax total email size with attachments
Attachments10Max attachments per email

CDN-Specific Limits

Limit TypeValueDescription
Max file size100 MBMaximum upload file size
Bulk delete100Max assets per delete request
Bulk move100Max assets per move request
Image dimension4096pxMax transform output dimension

Rate Limit Headers

All API responses include headers to help you track your rate limit status:

HeaderDescription
X-RateLimit-LimitMax requests allowed per minute
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetUnix timestamp when window resets
Retry-AfterSeconds to wait (only on 429 responses)

Handling Rate Limits

When you exceed the rate limit, you'll receive a 429 response:

429 Response
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1699999999
Retry-After: 45
{
"error": {
"code": "RATE_LIMITED",
"message": "Too many requests. Please wait 45 seconds before retrying."
}
}

Best Practices

  • 1.Check headers — Monitor X-RateLimit-Remaining to avoid hitting limits
  • 2.Use batch endpoints — Send multiple emails in one request instead of many single requests
  • 3.Implement backoff — Use exponential backoff when retrying after rate limit errors
  • 4.Queue requests — For high-volume operations, implement a queue to spread requests over time
  • 5.Cache responses — Cache read operations where possible to reduce API calls

Example: Rate Limit Aware Client

rate-limit-client.ts
class RateLimitedClient {
private remaining = Infinity
private resetAt = 0
async request(fn: () => Promise<Response>) {
// Wait if we know we're rate limited
if (this.remaining === 0 && Date.now() < this.resetAt) {
const waitTime = this.resetAt - Date.now()
await new Promise(r => setTimeout(r, waitTime))
}
const response = await fn()
// Update rate limit state from headers
this.remaining = parseInt(
response.headers.get('X-RateLimit-Remaining') || 'Infinity'
)
this.resetAt = parseInt(
response.headers.get('X-RateLimit-Reset') || '0'
) * 1000
if (response.status === 429) {
const retryAfter = parseInt(
response.headers.get('Retry-After') || '60'
)
await new Promise(r => setTimeout(r, retryAfter * 1000))
return this.request(fn) // Retry
}
return response
}
}

Need Higher Limits?

If you need higher rate limits or custom quotas, contact us about our Enterprise plan. We can accommodate high-volume use cases with dedicated infrastructure.