Sign in Get started

Rate limits

Per-tier request budgets, the response headers, and how the SDK handles 429s.

View as Markdown

Every API key is rate-limited per organization tier with a 1-hour sliding window. The SDK auto-retries short waits; longer waits raise so your code can decide.

Source: _http/retry.py

Per-tier limits

Tier Requests / hour
Free 1,000
Core 5,000
Pro 20,000
Enterprise 100,000

Response headers

Every successful response carries the current state of the window. Read them off the underlying response if you’re tracking your own consumption - most users can ignore them and let the SDK retry automatically.

Header Meaning
X-RateLimit-Limit Cap for the current window
X-RateLimit-Remaining Calls left in the current window
X-RateLimit-Reset Unix timestamp when the window resets
Retry-After (429 only) seconds until the next call may succeed

What counts

One HTTP request → one count. Payload size doesn’t matter. Streaming downloads (image / model / export blobs) count as a single request regardless of size.

Bulk operations are designed to keep counts low - prefer client.batch.move() / client.batch.update() over per-image calls in a loop.

SDK auto-retry

RateLimitError carries a retry_after attribute. The SDK waits and retries automatically when the response includes a Retry-After header and the wait is at most 120 seconds. Anything longer raises immediately so your code can back off, queue, or fail.

from pictograph.exceptions import RateLimitError
import time

try:
    client.datasets.list(
        limit=1000,
    )
except RateLimitError as e:
    print(f"Hit cap; retry in {e.retry_after}s")
    time.sleep(e.retry_after or 5.0)
    # …then retry. The SDK won't auto-recover for waits >120s.

The pictograph CLI inherits the same behaviour. On a long wait it prints the retry estimate to stderr so you can Ctrl-C if you don’t want to wait.

Spreading bursty load

If your workload is bursty (nightly imports, large auto-annotation runs), pace it across the hour:

from time import sleep

for batch in batches:
    process(batch)
    sleep(0.5)  # ~7,200 req/hr ceiling - comfortably under Core

For sustained workloads above your tier, the right move is to upgrade - retrying harder doesn’t increase your share.

See also

Copied to clipboard