# Rate limits and quotas

> Requests per minute and per month for each plan, the X-RateLimit headers, how usage is counted, and the hard limits of every request.

Source: https://docs.maylee.app/rate-limits

## Limits per plan

| Plan    | Requests per minute | Requests per month | Active API keys |
| ------- | ------------------- | ------------------ | --------------- |
| Free    | 60                  | 10,000             | 2               |
| Premium | 300                 | 200,000            | 10              |
| Expert  | 1,000               | 1,000,000          | 50              |

The plan that applies is the one **currently in force**: an expired subscription falls back to the Free limits, and the keys already issued keep working. The monthly allowance resets on the 1st of each month at 00:00 UTC.

The same allowance is shared with the [MCP server](/mcp/limits): tool calls count against the workspace quota too.

## Headers

Every authenticated response carries six headers, refusals included (`400`, `404`, `429`), so that you can slow down before you hit a limit:

```txt
X-RateLimit-Limit: 300              requests allowed per minute
X-RateLimit-Remaining: 287          left in the current minute
X-RateLimit-Reset: 1754995200       when the minute window resets (Unix seconds)
X-RateLimit-Quota: 200000           requests allowed this month
X-RateLimit-Quota-Remaining: 199000 left this month
X-RateLimit-Quota-Reset: 1756684800 first day of next month, 00:00 UTC (Unix seconds)
```

They are absent from `401` responses: the key is resolved before the counters are read.

## Two different 429s

| Code                  | Meaning                           | What to do                                                                                                                       |
| --------------------- | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `RATE_LIMIT_EXCEEDED` | Too many requests this minute.    | Wait the number of seconds in `Retry-After`. `details.resetAt` says when the window resets.                                      |
| `QUOTA_EXCEEDED`      | The monthly allowance is used up. | Waiting will not help before the 1st of next month (UTC): upgrade the plan. `details.used` and `details.quota` give the numbers. |

An exhausted API quota only blocks the API. The Maylee app and its real-time updates keep working.

## How usage is counted

* One request costs one unit.
* Bulk operations cost one unit **per email processed**: a [`POST /emails/bulk`](/api-reference/emails/bulk-update-emails) on 200 emails costs 200 units.
* Usage is counted when the request is accepted, not when it completes.
* A replayed [idempotent](/idempotency) request costs the same as the original.

## Hard limits

These values are enforced server-side, on every plan.

| Limit                       | Value               |
| --------------------------- | ------------------- |
| Emails per bulk operation   | 500                 |
| `limit` per page            | 200 (default 50)    |
| Filter tree depth           | 5 levels            |
| Conditions per filter tree  | 50                  |
| Length of a condition value | 500 characters      |
| Raw `filters` parameter     | 8 KB                |
| Search term                 | 2 to 200 characters |
| Request execution time      | 10 seconds          |
| JSON request body           | 256 KB              |

A query that runs longer than 10 seconds is **cancelled on the database side** and returns `408 QUERY_TIMEOUT`: narrow the filters, lower `limit`, or target a single mailbox. A body above 256 KB returns `413 PAYLOAD_TOO_LARGE`.
