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.
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() over N client.images.update() calls, and prefer the workflows over hand-rolled loops.
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)
# …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