> ## Documentation Index
> Fetch the complete documentation index at: https://docs.brudcast.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Rate limits

> Request limits on the platform API and the email send API, organization sending limits, the headers to watch and how to retry a 429.

Brudcast limits how fast each credential and each IP address can call it, and how much mail each
organization can send. When you hit a limit you get a `429`, and waiting always clears it.

## Platform API

Each [API key](/developers/api-keys) has its own budget, so two keys never share one.

| Window     | Default      | Configurable                       |
| ---------- | ------------ | ---------------------------------- |
| Per minute | 300 requests | Yes, on the key's **Settings** tab |
| Per day    | No cap       | Yes, on the key's **Settings** tab |

Every response tells you where you stand. When a key has both windows, the headers describe
whichever is closer to running out.

| Header                  | Meaning                        |
| ----------------------- | ------------------------------ |
| `X-RateLimit-Limit`     | Requests allowed in the window |
| `X-RateLimit-Remaining` | Requests left in the window    |

A request over the limit fails with `429` and two extra headers, `Retry-After` (seconds) and
`X-RateLimit-Reset` (an ISO 8601 time):

```json theme={"system"}
{
  "success": false,
  "message": "Too many requests",
  "code": "E_TOO_MANY_REQUESTS",
  "retryAfter": 42
}
```

## Email send API

The send API applies limits per client IP address and per organization.

| Limit                                | Value                                                               | 429 message                                        |
| ------------------------------------ | ------------------------------------------------------------------- | -------------------------------------------------- |
| Any request, per client IP           | 1,000 requests a minute                                             | `Too many requests, please try again later.`       |
| `POST /api/v1/send`, per client IP   | 30 requests a minute                                                | `Too many requests, please try again later.`       |
| Failed authentication, per client IP | More than 20 failures in 15 minutes, counted from the first failure | `Too many failed attempts, please try again later` |
| Your organization's sending limits   | Set per organization, see below                                     | `Rate limit exceeded: <window>`                    |

The per-IP limits send `RateLimit` and `RateLimit-Policy` headers on every response and
`Retry-After` on a `429`.

### Organization sending limits

Every organization has sending limits in five windows. All windows run on UTC.

| Window      | What it counts             | Resets                                   |
| ----------- | -------------------------- | ---------------------------------------- |
| `perSecond` | Send requests              | Continuously                             |
| `perMinute` | Send requests              | At the start of each minute              |
| `perHour`   | Send requests              | At the start of each hour                |
| `perDay`    | Recipients (To + Cc + Bcc) | At midnight UTC                          |
| `perMonth`  | Recipients (To + Cc + Bcc) | At the start of each calendar month, UTC |

So one call to 50 recipients counts once against the second, minute and hour windows, and 50 times
against the day and month windows.

The numbers depend on your plan and how long your account has been sending. New accounts start
lower and grow. See [New account sending limits](/deliverability/new-account-sending-limits).

A few rules make these predictable:

* **A request is accepted whole or not at all.** If 50 recipients would take you past the daily
  limit, the whole request is refused. No recipient is sent.
* **Refused requests cost nothing.** A request refused by any window doesn't use up budget in the
  others.
* **The message names the window.** `Rate limit exceeded: perDay` means you're done until midnight
  UTC. Don't retry in a loop.
* **The same limits apply to SMTP and campaigns.** Campaign messages over a limit are held and
  retried for up to 24 hours.

## SMTP relay

The relay applies your organization's sending limits once per SMTP transaction, when your client
sends `MAIL FROM`. A transaction counts as one request and one recipient, however many recipients
follow.

Over a limit, the relay replies `451 Rate limit exceeded: <window>`. `451` is a temporary failure,
so a standard SMTP client queues the message and retries on its own.

## Handling a 429

1. If the response has a `Retry-After` header, wait that many seconds.
2. If it doesn't, back off exponentially: wait about 1 second, then 2, then 4, up to a minute, with
   some random jitter.
3. If the message names `perDay` or `perMonth`, stop and resume after the window resets.

<CodeGroup>
  ```javascript Node.js theme={"system"}
  async function fetchWithRetry(url, options, maxAttempts = 5) {
    for (let attempt = 1; ; attempt++) {
      const response = await fetch(url, options);
      if (response.status !== 429 || attempt === maxAttempts) return response;

      const retryAfter = Number(response.headers.get("Retry-After"));
      const backoff = Math.min(2 ** (attempt - 1), 60);
      const seconds = retryAfter > 0 ? retryAfter : backoff + Math.random();

      await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
    }
  }
  ```

  ```python Python theme={"system"}
  import random
  import time

  import requests


  def request_with_retry(method, url, max_attempts=5, **kwargs):
      for attempt in range(1, max_attempts + 1):
          response = requests.request(method, url, **kwargs)
          if response.status_code != 429 or attempt == max_attempts:
              return response

          retry_after = response.headers.get("Retry-After")
          if retry_after and retry_after.isdigit():
              delay = int(retry_after)
          else:
              delay = min(2 ** (attempt - 1), 60) + random.random()
          time.sleep(delay)
  ```

  ```php PHP theme={"system"}
  <?php
  function requestWithRetry(string $url, array $curlOptions, int $maxAttempts = 5): array
  {
      for ($attempt = 1; ; $attempt++) {
          $retryAfter = null;
          $ch = curl_init($url);
          curl_setopt_array($ch, $curlOptions + [
              CURLOPT_RETURNTRANSFER => true,
              CURLOPT_HEADERFUNCTION => function ($ch, $header) use (&$retryAfter) {
                  if (stripos($header, "Retry-After:") === 0) {
                      $retryAfter = (int) trim(substr($header, 12));
                  }
                  return strlen($header);
              },
          ]);
          $body = curl_exec($ch);
          $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

          if ($status !== 429 || $attempt === $maxAttempts) {
              return [$status, $body];
          }

          $delay = $retryAfter ?: min(2 ** ($attempt - 1), 60) + mt_rand() / mt_getrandmax();
          usleep((int) ($delay * 1000000));
      }
  }
  ```
</CodeGroup>

<Warning>
  The email send API doesn't deduplicate requests. Retry a send only when you got a response that
  says it wasn't accepted, such as a `429` or `5xx`. If the connection dropped before any response
  arrived, the message may already be queued. See
  [Retries and duplicate sends](/developers/sending/http-api#retries-and-duplicate-sends).
</Warning>

## Staying under the limits

* Use one API key per integration, and set each key's per-minute limit to what it needs.
* For bulk or marketing mail, send a [campaign](/campaigns/overview) instead of calling the send API
  in a loop. Campaigns are paced for you.
* Watch `X-RateLimit-Remaining` and slow down before it reaches zero.

## Related

<Columns cols={2}>
  <Card title="API keys" icon="key-round" href="/developers/api-keys">
    Set a key's per-minute and per-day limits.
  </Card>

  <Card title="Errors" icon="circle-alert" href="/developers/errors">
    Every 429 message and what it means.
  </Card>

  <Card title="Email send API" icon="send" href="/developers/sending/http-api">
    When a send is safe to retry, and how to avoid duplicates.
  </Card>

  <Card title="New account sending limits" icon="trending-up" href="/deliverability/new-account-sending-limits">
    Why a new organization's limits start low and grow.
  </Card>
</Columns>
