Rate Limiting
The Printeers partner API enforces per-organization rate limits so one partner cannot saturate the API for everyone else. A healthy integration should never see a 429.
Limits are scoped to the organization that owns the API keys, so multiple keys belonging to the same organization share one budget.
Limits
Every authenticated request consumes from at least one rate-limit bucket:
| Policy | Quota (q) |
Window (w) |
Sustainable rate | Applies to |
|---|---|---|---|---|
default |
3000 | 60 seconds | 50 req/sec | every authenticated request |
uploads |
5000 | 24 hours | 5000 per day | POST /v2/images, POST /v2/evidence |
downloads |
100000 | 24 hours | 100000 per day | GET /v2/renders/{renderReference}/media, GET /v2/renders/{renderReference}/thumbnail |
Upload and download requests consume one token from default plus one token from their dedicated bucket.
default lets you sustain 50 requests per second indefinitely, or burst up to 3000 requests over 60 seconds before the bucket runs dry. uploads caps total uploads per organization per day to bound storage growth. downloads caps total media downloads per organization per day to prevent re-fetching the same media indefinitely. All buckets refill continuously.
The rate-limit policies, their numerical values, and which routes consume from which buckets may all change within a major API version as traffic patterns evolve. Tuning these is not considered a breaking change. Always read the live values from the X-RateLimit-Policy and X-RateLimit response headers; do not hard-code anything from this guide into your integration.
Response Headers
The two headers below follow the structured-field syntax from the IETF draft for rate-limit headers, the standardization effort for communicating rate limits over HTTP. We use the X- prefix because the draft is not yet a published RFC; partner-api v3 will switch to the unprefixed names (RateLimit and RateLimit-Policy) once it is. The parameter names (q, w, r, t) will not change.
Every authenticated response carries these two headers showing the buckets the request consumed from:
X-RateLimit-Policy: "default";q=3000;w=60, "uploads";q=5000;w=86400
X-RateLimit: "default";r=2987;t=0, "uploads";r=4982;t=0
X-RateLimit-Policy:qis the bucket capacity,wis the refill window in seconds. The long-term sustainable rate isq/w.X-RateLimit:ris your remaining tokens,tis the seconds until the bucket regains a full token (always0while the bucket still has tokens).
Requests that only consume from default show a single entry in each header.
If r is getting low for a bucket your integration depends on, slow down preemptively rather than waiting for a 429.
When You Hit a Limit
When any bucket is empty, you receive HTTP 429 Too Many Requests:
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 12
X-RateLimit-Policy: "default";q=3000;w=60
X-RateLimit: "default";r=0;t=12
{
"code": "rate_limited",
"message": "Rate limit exceeded; see Retry-After and X-RateLimit headers."
}
Wait at least the number of seconds in Retry-After, then retry. The value already includes jitter so concurrent clients will not synchronize their retries.
For uploads denials Retry-After is around 17 seconds (plus jitter), the time it takes the daily bucket to refill one token. Once you have hit the cap, you can resume at roughly one upload every 17 seconds until the bucket has filled back up.
For downloads denials Retry-After is around 1 second (plus jitter), since the daily bucket refills a token roughly every 0.86 seconds.
Retry-After follows RFC 9110.
Need a Higher Limit?
If your integration has a legitimate use case that bumps into these limits regularly, contact support@printeers.com. Tell us which policy is the bottleneck and roughly what volume you need; we can raise the limits for your organization on a case-by-case basis.
