API reference / Rate limits & quotas
Rate limits & quotas
Two independent limits apply to /v1/generate: a monthly quota (how many documents you can
generate per calendar month) and a per-minute rate limit (how fast you can send requests).
They exist for different reasons and return different errors.
Limits by plan
| Plan | Monthly quota | Requests / min |
|---|---|---|
| Free | 50 | 5 |
| Starter | 1,000 | 30 |
| Pro | 5,000 | 120 |
| Scale | 25,000 | 300 |
(Plans also differ on active API keys and history retention. See Plans & limits.)
Monthly quota — limit_exceeded (429)
Each plan has a monthly generation quota, counted per calendar month in UTC (a period looks
like 2026-06). When you reach it, further calls return limit_exceeded (429) until the next
month begins. The fix is to upgrade or wait for the reset.
Only successful generations count toward the quota. A failed call never does.
Request rate — rate_limited (429)
Each document is a full browser render, so there is also a short-term cap on how many requests
per minute you may send. Bursting past it returns rate_limited (429) with a Retry-After
header telling you how long to wait. This is "slow down", not "you are out of quota".
Both limits use HTTP 429, but the code distinguishes them: rate_limited means wait a
moment and retry; limit_exceeded means you have hit your monthly allowance. Always branch on
code, not the status alone.
Capacity — service_unavailable (503)
If the render engine is momentarily saturated, a request can be shed with service_unavailable
(503) rather than queued indefinitely. This is transient: retry after a short, backed-off delay.
Accounting guarantee
The successful generation and its usage increment are written in a single transaction, so your usage figure can never disagree with what actually rendered, and a failed render leaves the counter untouched.
Retrying safely
There is no idempotency key today, but you do not need one to retry safely: a request either returns the PDF bytes or fails without producing a document or consuming quota. So:
- Retry the transient failures with exponential backoff:
rate_limited(wait at least theRetry-Aftervalue),service_unavailable, and usuallyinternal_error. - Do not retry request errors (
invalid_json,invalid_data,template_not_found,template_not_published): fix the request first, or you will just fail again. - A successful retry generates a new document (and counts once). If you trigger generation from a user action, guard against double-submits on your side.
A reasonable policy: up to ~3 retries, starting around 1s and doubling, capped at a few seconds, and never retrying a 4xx that is your request's fault. See Errors for the per-code guidance.