export const metadata = {
  title: "Rate Limits",
  description:
    "Per-organization FaithTranscripts rate limits, response headers, and recommended backoff strategies for 429 responses.",
  alternates: { canonical: "/docs/api/rate-limits" },
};

# Rate Limits

Rate limits are enforced **per organization**, not per API key. Minting
more keys does not raise your cap. We bucket by endpoint class so heavy
polling doesn't starve your ability to create transcripts.

## Defaults (v1)

| Class                                | Limit                       |
| ------------------------------------ | --------------------------- |
| Create transcript (`POST /transcripts`, uploads, ai-pass) | 60 / minute / org         |
| Read endpoints (`GET /transcripts`, `GET /jobs`)          | 600 / minute / org        |
| Sync create (`POST /transcripts?wait=true`)               | 10 concurrent / org        |
| Webhook delivery retries              | 5 attempts, exp. backoff    |

We'll revisit these after launch based on real usage.

## Response headers

Every rate-limited endpoint returns standard headers on every response
(not just `429`):

```http
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 41
X-RateLimit-Reset: 1714524612
```

- `X-RateLimit-Limit` — total requests allowed in the current window.
- `X-RateLimit-Remaining` — requests left before the limit kicks in.
- `X-RateLimit-Reset` — unix timestamp (seconds) when the bucket refills.

On `429 rate_limited` we also include `Retry-After: <seconds>` — wait at
least that long before retrying.

## Handling 429

```ts
async function request(input: string, init: RequestInit, attempt = 0) {
  const res = await fetch(input, init);
  if (res.status !== 429 || attempt >= 5) return res;
  const retryAfter = Number(res.headers.get("Retry-After") ?? 2);
  await new Promise((r) => setTimeout(r, retryAfter * 1000));
  return request(input, init, attempt + 1);
}
```

## Polling guidance

Use **exponential backoff starting at 1s, capping at 30s**. You'll rarely
hit the 600/min read ceiling at reasonable poll rates, but aggressive
tight loops will. Webhooks are strictly better for production.

## Requesting a limit increase

We're happy to raise limits for production workloads. Reach out through
the dashboard support channel with:

- Your organization id
- The endpoint class (create / read / sync)
- Expected peak requests per minute
- Any hard deadlines or spikes you're anticipating
