Skip to main content
Two separate ceilings guard the API, and both answer with a 429. A rate limit counts how many requests you send per minute. A concurrency limit counts how many long operations you keep running at the same time. Read error.type to tell them apart. A rate limit means slow down. A concurrency limit means wait for work already in flight to finish.

Rate limits

The sustained rate is 1,000 requests per minute, and the window holds a little headroom above that so a short burst is not punished. Every response carries the current state of the window.
429, rate limit exceeded

Concurrency limits

Renders and uploads hold separate concurrency budgets, and the upload budget is never the larger of the two. Only the endpoints that hold a slot report these headers: a PSD upload, a synchronous render, and a background removal.
429, concurrency limit exceeded
A concurrency 429 carries Retry-After as well, and five seconds is usually enough: the slot frees as soon as the request holding it returns.

Queue instead of waiting

A queued render never holds a concurrency slot while it waits. Send is_async as true on POST /api/v1/renders and the call returns a 202 with a job you poll through GET /api/v1/jobs/{job_id}, or receive over a webhook. Video mockups are always queued and behave the same way. That is the right shape for a large batch: submit the whole set, then follow the jobs.

Read your own ceilings

Do not hardcode the concurrency numbers. Both budgets move with the plan catalogue, so read them at runtime from GET /api/v1/packages/plans, which returns max_concurrent_requests and max_concurrent_uploads for the plan you are on. Size your worker pool from those two fields and a 429 stops being something you have to handle.

Errors

Every status code, every error_code, and the retry loop.