---
title: Rate limits
description: How rate limits work and how to back off when you hit one.
---

ZevSend rate-limits requests per API key. The limits are set so
typical transactional traffic doesn't notice them, while bulk
or runaway scripts get a clear signal to slow down.

## The default limit

By default, each API key is allowed **100 requests per 60
seconds**. The window is a rolling 60-second window, not a
calendar minute.

Send-pipeline limits (per channel) apply on top: SMS and
WhatsApp have additional per-team daily caps that scale with
your plan. The dashboard shows your current usage under
**Usage**.

## When you hit the limit

You get a `429` response with a `Retry-After` header:

```http
HTTP/1.1 429 Too Many Requests
Retry-After: 13
Content-Type: application/json

{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Retry after 13 seconds.",
    "type": "rate_limited",
    "request_id": "req_01HXYZ..."
  }
}
```

`Retry-After` is in seconds. Sleep for at least that long
before retrying. A reasonable client retries `429` with
exponential backoff:

```ts
async function withRetry<T>(fn: () => Promise<T>, attempt = 0): Promise<T> {
  try {
    return await fn();
  } catch (err) {
    if (isRateLimited(err) && attempt < 5) {
      const wait = retryAfterMs(err) ?? 2 ** attempt * 250;
      await sleep(wait);
      return withRetry(fn, attempt + 1);
    }
    throw err;
  }
}
```

## Raising your limit

If your application has a legitimate burst pattern that
exceeds the default, contact support from your dashboard.
We'll raise the per-key limit and add a note to your account.

## Spreading load

The simplest way to stay under the limit is to spread bulk
sends over time. If you're notifying 10,000 customers, send
them at a steady rate rather than in one tight loop. Queueing
the work in your own infrastructure (BullMQ, SQS, etc.) is the
right pattern.

Don't parallelise the same key across many workers without a
shared rate limiter — the limit is per key, not per process.