Appearance
Rate limits
The API rate-limits each account with a fixed window per endpoint class. Over a limit returns 429 rate_limited with a Retry-After header (seconds to wait).
Limits
Limits are per account, in a rolling fixed window (default 60 seconds):
| Bucket | Default | Covers |
|---|---|---|
| Job creation | 20 / window | POST /jobs — the expensive path (enqueues work + spends balance). |
Polling (GET /jobs/{id}) and downloads are not part of this bucket, but poll politely — every 1–2 seconds per job is plenty.
Exact numbers can be tuned per deployment/plan. Read the effective ceilings from
GET /options(limits) and treat the429+Retry-Aftercontract as the source of truth, not a hardcoded number.
Handling 429
When you hit a limit:
HTTP/1.1 429 Too Many Requests
Retry-After: 12json
{ "error": "rate_limited", "message": "Rate limit exceeded. Retry in 12s." }Back off for Retry-After seconds, then retry. A simple, robust pattern:
python
import time, requests
def with_retry(fn, tries=5):
for _ in range(tries):
r = fn()
if r.status_code != 429:
return r
time.sleep(int(r.headers.get("Retry-After", "5")))
return r # give up after `tries` — surface the 429Staying under the limits
- Batch with
copies, not with many jobs. One job withcopies: 20is a single creation call; twenty separate jobs is twenty. Fanning out inside a job is cheaper and faster. - Poll, don't hammer. One in-flight poll per job every 1–2 seconds is ample.
- Pre-upload large sources once with
inputKeyand reuse the key across jobs rather than re-uploading.