Rate limits
Per-tier request budgets, the response headers, and how the SDK handles 429s.
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
- Error handling - the full exception hierarchy
- Credits - paid-operation budgeting