# Rate limits

Source: https://docs.simail.ai/rate-limits/

> Request-rate limits for the API, MCP, WebSocket, sign-up and the console, and how to handle 429 and Retry-After.

Rate limits stop runaway loops and abuse. Quotas on how much mail you can send or receive are on
[Usage, limits & breakers](/limits/).

## API and MCP

| What | Limit | Counted per |
|---|---|---|
| Requests with an API key (REST and MCP) | 600 per minute (burst) | key |
| Requests without a key | 120 per minute | IP address |
| API calls per day | by plan | organization |
| `POST /v0/agent/sign-up` | 10 per hour per network range. Refused codes also pause sign-up for the rest of the hour: per network operator (50 refused codes per hour from one ASN) and globally (200 per hour from all sources); a paused sign-up answers `503` with `Retry-After`. A network range whose last successful sign-up was less than 7 days ago and that has had no refused code this hour is not paused | network range / ASN / global |
| `POST /v0/waitlist` | 5 per day per network range, 50 per day per network operator, plus a global daily cap | network range / ASN |
| MCP OAuth client registration | 10 per day | network range |
| WebSocket | 50 connections per organization, 10 per key, 10 handshakes per minute, 1 hour per connection | organization / key |
| Webhook deliveries | 60 per minute (extra deliveries are delayed, never dropped) | endpoint |

A network range is an IPv4 /24 or an IPv6 /48. Burst limits are enforced close to you and are
approximate; quotas (per day) are exact.

## Console (humans)

| What | Limit |
|---|---|
| Email sign-in codes sent | 3 per 15 minutes and 10 per day per email address and network range together; 30 per day per email address across all ranges; 20 per hour per network range |
| Code attempts | 3 per code; 30 verifications per hour per network range |
| Failed codes | 10 failed codes per hour from one network range lock code sign-in for that address and range for an hour; 50 failed codes per hour from anywhere lock the address for an hour. Passkey sign-in is never locked. |
| Re-verification codes | sent 3 per 15 minutes and 10 per day per session (20 per hour per network range, counted separately from sign-in); 3 attempts per code; 10 failures per hour lock re-verification codes for that session for an hour |
| Adding or removing passkeys | 5 per day per user |
| Invite code redemption | 5 per hour per user, 20 per hour per IP; 5 failures in a row lock redemption for an hour |
| Console requests | 300 per minute per signed-in session; 60 per minute per network range without a session (requests that carry a session cookie first pass a looser 600 per minute per network range check) |

Responses never reveal whether an email address is registered: the limits and the messages are the
same either way.

## Handling `429`

Every `429` has a `Retry-After` header (seconds) and a problem+json body with `retryable: true`:

```json
{
  "type": "https://docs.simail.ai/errors#rate_limited",
  "title": "RateLimitedError",
  "status": 429,
  "code": "rate_limited",
  "message": "Too many requests.",
  "fix": "Wait for Retry-After seconds, then retry.",
  "retryable": true,
  "request_id": "req_…"
}
```

- Wait at least `Retry-After` seconds, then retry the **same** request (with the same
  `Idempotency-Key` for sends).
- Add jitter and back off exponentially if you hit the limit again.
- Do not spread load over more keys to get around a limit; limits that matter are per organization.
- Prefer events ([polling](/events/), [webhooks](/webhooks/), [WebSocket](/realtime/)) to tight
  polling loops over messages.

`429 daily_limit_exceeded` means a daily quota, not a burst: `Retry-After` points at the next window.
