Stay within rate limits
Give this prompt to your AI agent. The agent does the task for you.
Read https://thirds.ai/docs/rate-limits and help me set request concurrency and safe retries for thirds.ai using its rate, size, and queue limits.
Send work at a steady rate and wait for active jobs to finish. Every plan has the same render limits. Plans change credits and queue order. They do not increase these safety limits.
Request and job limits
| Limit | Maximum |
|---|---|
| API-key submission rate | 5 per second, with an idle burst of 21 |
| Live jobs per API key | 8 |
| Live jobs per account | 16 |
| Paid queued-job backlog | 500 across the service |
| Anonymous playground allowance | 200 renders per browser per month |
A live job is queued or running. PDF and image work share account capacity. A burst allowance does not increase live-job capacity. The playground also has CAPTCHA, address rate controls, and a separate live-job cap. These safety controls are not a promise of throughput. There is no lifetime render quota.
Render size limits
| Limit | Maximum |
|---|---|
| Render request body | 8 MiB |
| HTML input | 5 MiB |
| Template source | 1 MiB |
| Template data | 1 MiB of canonical JSON |
| Template data depth | 32 levels |
| One data collection | 10,000 items |
| Total template data values | 50,000 |
| One fetched asset | 10 MiB |
| All fetched assets | 20 MiB across at most 128 assets |
| PDF output | 100 pages and 25 MiB |
| Static-image output | 32,000,000 pixels and 25 MiB |
| Image width | 320 to 7680 pixels |
| Image height | 200 to 4320 pixels |
| Worker render time | 30 seconds |
| JavaScript ready-marker wait | 2 seconds |
Memory, CPU, browser processes, temporary storage, and template evaluation also have fixed safety limits. A limit failure spends no render credits. Repeated failed renders can still trigger abuse limits. Split large documents, resize images, and remove unused assets before trying again. See PDF and image options.
Read the retry headers
A retryable request error includes Retry-After in seconds and the same value at error.retry.retry_after_seconds. Wait at least that long. Keep the same Idempotency-Key and input when you retry a render request. Add a small random delay when many workers retry together.
| Response | What to do |
|---|---|
429 rate_limited | Slow down. The current retry delay is between 1 and 60 seconds. |
429 account_concurrency_limited or key_concurrency_limited | Wait for active jobs to finish. The response gives a 5-second retry delay. |
429 abuse_limited | Fix repeated failures. The response gives a 3600-second retry delay; the daily failure count can still block a later attempt. |
503 overloaded | Wait for the 30-second retry delay before submitting again. |
202 with a job | Poll the route in Location. Retry-After: 1 gives the initial polling delay. |
The API does not provide a remaining-request counter or X-RateLimit-* headers. Use Retry-After, the response code, and your own count of active jobs. A retry header is guidance for the next attempt, not a guarantee that capacity becomes available at that time.
Give each client a deadline and a retry limit. If the deadline ends while a job is active, save its ID and read it later. Do not create a replacement job just because your request times out. See safe retries.
Understand queue order
The queue orders work by enqueue time plus the plan's priority offset. The offsets are 0 seconds for Scale, 30 seconds for Growth, 2 minutes for Starter, 5 minutes for packs, 10 minutes for Free, and 15 minutes for anonymous work.
These offsets only sort jobs. They don't set a fixed wait or promise a finish time. Older work gains priority so lower tiers can still run. Keep polling the same job while it is queued. Webhooks can notify your server when the job ends.
For a specific refusal or failed job, use the error guide. For credit grants and spend limits, use billing.