Rate Limits
API requests are rate limited to ensure fair usage and system stability.
Rate Limits by Plan
| Plan | Requests/min | Emails/day | Storage |
|---|---|---|---|
| Platform | 1,000 | 100K/month* | 100 GB |
| Enterprise | Custom | Custom* | Custom |
* Usage-based pricing applies. See pricing for details.
Email-Specific Limits
| Limit Type | Value | Description |
|---|---|---|
| Batch size | 100 | Max emails per batch request |
| Broadcast recipients | 1,000 | Max recipients per broadcast |
| Email size | 25 MB | Max total email size with attachments |
| Attachments | 10 | Max attachments per email |
CDN-Specific Limits
| Limit Type | Value | Description |
|---|---|---|
| Max file size | 100 MB | Maximum upload file size |
| Bulk delete | 100 | Max assets per delete request |
| Bulk move | 100 | Max assets per move request |
| Image dimension | 4096px | Max transform output dimension |
Rate Limit Headers
Every API response carries the standard IETF rate-limit headers, so a client can self-throttle without guessing. Read RateLimit-Remaining and RateLimit-Reset and you have everything you need.
| Header | Value | Description |
|---|---|---|
| RateLimit-Limit | 200 | Requests permitted in the current window |
| RateLimit-Remaining | 199 | Requests still permitted in the current window |
| RateLimit-Reset | 60 | Seconds until the window resets. Not a Unix timestamp. |
| RateLimit | "default";r=199;t=60 | Current service limit as an RFC 8941 structured field: r remaining, t seconds to reset |
| RateLimit-Policy | "default";q=200;w=60 | The quota policy itself: q requests per w seconds |
| Retry-After | 45 | Seconds to wait. Present on 429 responses, and always equal to RateLimit-Reset. |
The legacy X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers carry the same values and are still sent, so existing clients keep working. New code should read the standard headers.
Handling Rate Limits
When you exceed the rate limit, you'll receive a 429 response:
429 Response
HTTP/1.1 429 Too Many RequestsContent-Type: application/jsonRateLimit-Limit: 200RateLimit-Remaining: 0RateLimit-Reset: 45RateLimit: "default";r=0;t=45RateLimit-Policy: "default";q=200;w=60Retry-After: 45{"error": {"code": "RATE_LIMITED","message": "Too many requests. Please wait 45 seconds before retrying."}}
Best Practices
- 1.Check headers — Monitor RateLimit-Remaining and slow down before you reach zero
- 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
const sleep = (ms: number) => new Promise(r => setTimeout(r, ms))class RateLimitedClient {private remaining = Number.POSITIVE_INFINITYprivate resetAt = 0 // epoch msasync request(fn: () => Promise<Response>): Promise<Response> {// Out of quota and the window has not rolled over yet: wait it out.if (this.remaining === 0 && Date.now() < this.resetAt) {await sleep(this.resetAt - Date.now())}const response = await fn()// RateLimit-Reset is seconds until reset, not a Unix timestamp.const remaining = response.headers.get('RateLimit-Remaining')const reset = response.headers.get('RateLimit-Reset')if (remaining !== null) this.remaining = Number(remaining)if (reset !== null) this.resetAt = Date.now() + Number(reset) * 1000if (response.status === 429) {// Retry-After always matches RateLimit-Reset on a 429.const retryAfter = Number(response.headers.get('Retry-After') ?? 60)await sleep(retryAfter * 1000)return this.request(fn)}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.