# Rate limits (/docs/api-reference/rate-limits)

The API limits requests per API key, by kind of request. Each limit is a bucket: it holds up to
**burst** requests, which can arrive at once, and refills at its **rate**. A key that keeps under
the rate never waits; a short spike up to the burst is fine too.

| Bucket | Covers | Counted per | Rate | Burst |
| --- | --- | --- | --- | --- |
| `api.read` | Reads: every `GET` | API key | 50 per second | 100 |
| `api.write` | Writes: every other request, unless a row below covers it | API key | 10 per second | 30 |
| `api.send` | Sends: emails and batches, SMS, inbox messages and replies, broadcasts, Hooks messages and endpoint tests, verifications | API key | 20 per second | 50 |
| `risk.assess` | Risk assessments, and email, IP, phone and content checks | API key | 100 per second | 200 |
| `risk.limit` | Risk rate limit checks (`coss.risk.limit()`) | API key | 500 per second | 1,000 |
| `api.authentication.key` | Authenticating a key, before any other limit (`too_many_authentications`) | API key | 50 per second | 100 |
| `api.authentication.ip` | Authenticating any key, before any other limit (`too_many_authentications`) | client IP | 100 per second | 200 |
| `api.auth_failure` | Requests with an invalid key (`too_many_failed_authentications`) | client IP | 30 per minute | 30 |

Every key has its own buckets, so a busy production key never slows down another environment's.
Requests with an invalid key never reach a route's bucket: they count against the authentication
buckets and their client address's allowance of failures, and an address that keeps failing is
refused for a while.

## Rate limit headers [#rate-limit-headers]

Responses carry the state of the bucket the request counted against:

| Header                | Meaning                                              |
| --------------------- | ---------------------------------------------------- |
| `RateLimit-Limit`     | The bucket's size (its burst)                        |
| `RateLimit-Remaining` | Requests left in it right now                        |
| `RateLimit-Reset`     | Seconds until it is full again                       |

## When you're limited [#when-youre-limited]

A limited request gets a `429` with the usual [error envelope](/docs/api-reference/errors)
(`type: "rate_limit_error"`) and a `Retry-After` header with the seconds to wait. Nothing was done:
retry it after that long. The [SDK](/docs/sdk/errors#automatic-retries) does this for you, waiting
exactly `Retry-After` (up to 60 seconds) before each of its retries; its `POST` requests reuse
their `Idempotency-Key`, so a retried send is never sent twice.

| `error.code`                      | Why                                                                     |
| --------------------------------- | ----------------------------------------------------------------------- |
| `rate_limited`                    | The key went over its bucket for this kind of request                   |
| `quota_exceeded`                  | The send is over the organization's send quota (below)                  |
| `too_many_authentications`        | Too many requests authenticating, for one key or from one address       |
| `too_many_failed_authentications` | Too many requests with invalid keys from your address                   |

A `quota_exceeded` without `Retry-After` can never succeed as it is: the email or batch has more
recipients than the quota allows at once, so split it.

## Send quotas [#send-quotas]

On top of the per-key limits, what an organization sends across all of its keys is limited by its
plan: email recipients per second and per day, and SMS segments per second and per day.

| | Free | Pro | Scale | Enterprise |
| --- | --- | --- | --- | --- |
| Price | Free | $25/month | $250/month | From $2,000/month, annual commitment |
| Included | 3,000 email recipients a month, 3,000 received emails a month, 1,000 form submissions a month, 1,000 MB of form uploads a month, 3 inboxes, 100 risk phone checks a month | $25 of usage, 3 inboxes, 100 risk phone checks a month | $250 of usage, 3 inboxes, 100 risk phone checks a month | Per contract |
| Usage beyond it | Not available | Usage rates below | Usage rates below | Contract rates |
| Sending rate | 2 emails a second, 3,000 a day | 14 emails a second, 100,000 a day | 50 emails a second, 1,000,000 a day | Custom |
| SMS rate | Sandbox only | 10 SMS segments a second, 10,000 a day | 30 SMS segments a second, 100,000 a day | Custom |
| Marketing rate | 2 marketing emails a second | 10 marketing emails a second | 50 marketing emails a second | Custom |
| Domains | 1 | 10 | 100 | Custom |
| Team members | 3 | 10 | Unlimited | Unlimited |
| Webhook endpoints per environment | 2 | 10 | 10 | Custom |
| Contacts per environment | 1,000 | 50,000 | 250,000 | Custom |
| SMS phone numbers | 0 | 5 | 50 | Custom |
| Inboxes | 3 | 1,000 | 10,000 | Custom |
| Email sub-accounts | 0 | 0 | 1,000 | Custom |
| Custom tracking domains | — | Yes | Yes | Yes |
| Audit log | — | Yes | Yes | Yes |
| Log drains | — | — | Yes | Yes |
| Single sign-on (SAML, OIDC) | — | — | Yes | Yes |
| Directory sync (SCIM) | — | — | — | Yes |
| Dedicated IPs | — | — | Add-on | Add-on |
| Email for platforms (sub-accounts) | — | — | Yes | Yes |

- Quotas are charged when a send is accepted (a scheduled send when it is scheduled), per recipient
  for email and per segment for SMS, and refunded when the send is refused or replayed.
- Marketing email has a slower pace of its own within the email quota, so a broadcast never takes
  the whole rate from transactional mail.
- Sandbox environments have their own, smaller daily quotas, per environment.
- [Sub-accounts](/docs/email/subaccounts) can have quotas you set, within the organization's.
- [Hooks](/docs/hooks/delivery), [Verify](/docs/verify) and [Risk](/docs/risk/lookups) have limits of
  their own, described with each product.

## Higher limits [#higher-limits]

The per-key buckets (`api.read`, `api.write`, `api.send`, `risk.assess`, `risk.limit`) and the send
quotas can be raised for an organization; the authentication buckets can't. Contact coss.com support
with your organization ID and the traffic you expect. Enterprise contracts set their own send rates.
