<!-- section: Auth API · status: building · source: docs/auth-api/16-limits.md -->

> Two rate limits answering different questions, and what a project still being provisioned returns.


# Limits and states

## Rate limits

Two limits apply, and they answer different questions.

**Per API key: 600 requests a minute**, shared with the rest of the platform.
Every response carries `X-RateLimit-Remaining` so you can slow down before being
told to; a refusal adds `Retry-After`. This bounds what your project as a whole
can do.

**Per end user, per endpoint**, which is what protects your users from each
other:

| Endpoint | Limit |
|---|---|
| Sign in with a password | **3 attempts every 10 seconds from one IP address** |
| Asking for a code | **3 a minute from one IP address** |
| Everything else | 100 requests a minute |

A code itself has a limit of its own that no rate limiter provides: **three
wrong guesses and it is dead**, and it expires ten minutes after it was sent
regardless. Six digits with three attempts is a one-in-333,000 shot per code.

Somebody guessing passwords against one of your accounts is held to a crawl while
everyone else signs in normally.

A refusal is a **429** with `X-Retry-After` in seconds:

```json
{ "message": "Too many requests. Please try again later." }
```

The counters live in **your project's own database**, so your traffic and another
customer's never share one.

**This is a throttle rather than a lockout.** No account is ever disabled by
failed attempts, because that turns a nuisance into a way to lock your users out
of their own accounts.

## While a project is being set up

A project whose auth database is still being created answers **503** with a
`Retry-After`. Provisioning takes a few seconds and happens once.

```json
{ "error": "Auth isn't ready for this project yet." }
```

**The same 503 covers a suspended project, deliberately.** The response does not
tell a browser which of our internal states a project is in.

## Cold starts

A database that has been idle scales to zero, so the first request after a quiet
period pays a wake-up of a second or two. Steady traffic never sees it.

It lands on whoever signs in first after the quiet period, which is worth knowing
if your app has a nightly lull and a morning rush.

## Errors everywhere

These apply to every endpoint in this section, so the per-page tables do not
repeat them.

| Status | Means |
|---|---|
| `401` | Missing, malformed or unknown API key |
| `403` | Publishable key from an origin you have not registered |
| `403` | The key is not scoped for the action |
| `429` | Rate limited — read `Retry-After` |
| `503` | Auth is not ready for this project |
