Rate Limits
How tier-based rate limits, the daily credit cap, and 429 responses work.
Rate limits protect the API and keep usage fair. They are applied per API key and are tier-based: your plan determines the exact per-minute and per-day request limits, the concurrency limit, and the daily credit cap.
Because limits depend on your tier, read your current values from the tier endpoint rather than hardcoding numbers.
GET /v1/account/tier
Return the current rate limits and quotas for your account. Authenticated with your API key — usable from backend services, CI jobs, and agents without a browser session.
Auth: API Key (Bearer token)
| Field | Type | Description |
|---|---|---|
plan_code |
string |
Current tier name (e.g. "pro"). |
requests_per_minute |
integer |
Max requests per rolling minute window. |
requests_per_day |
integer |
Max requests per calendar day (UTC). |
concurrent_limit |
integer |
Max in-flight requests at once. |
max_credits_per_day |
integer |
Daily credit spending cap. Resets 00:00 UTC. |
allowed_model_types |
string[] |
Model categories this tier can access. |
curl https://api.picxstudio.com/v1/account/tier \
-H "Authorization: Bearer pxsk_your_key"
{
"plan_code": "pro",
"requests_per_minute": 60,
"requests_per_day": 10000,
"concurrent_limit": 10,
"max_credits_per_day": 13000,
"allowed_model_types": ["image", "video", "audio", "agent"]
}
Call this once at startup and cache it. Tier limits rarely change mid-session.
GET /api/tier (Dashboard)
The same data, authenticated with your browser session (JWT). This is what the dashboard UI calls — if you are building a headless integration, prefer /v1/account/tier above.
Auth: Dashboard (JWT)
Tiers are examples and may change — always read /api/tier for your real limits. Typical seeded tiers: Starter 10/min · 500/day, Pro 30/min · 2,000/day, Max 60/min · 5,000/day, Ultra 120/min · 10,000/day.
When you exceed a limit the API returns HTTP 429 with standard rate-limit headers:
Rate-limit headers (on 429)
X-RateLimit-Limit: 30 # your per-minute request cap
X-RateLimit-Remaining: 0 # requests left in the current window
X-RateLimit-Reset: 1718659245 # unix time when the window resets
Retry-After: 12 # seconds to wait before retrying
On HTTP 429 Too Many Requests, read the Retry-After header and wait that many seconds before retrying. Do not retry immediately.
429 response
HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1718659245
{
"detail": "Rate limit exceeded. Retry after 12 seconds."
}
Separate from request limits, each account has a daily credit cap. When it is reached the API also returns 429 with a Retry-After header; the cap resets at 00:00 UTC.
Handling rate limits
-
Watch for 429s
Treat HTTP 429 as a signal to slow down, not an error to surface to users.
-
Honor Retry-After
Wait for the number of seconds in the Retry-After header before the next attempt.
-
Back off exponentially
For repeated 429s, increase the wait each time (for example 1s, 2s, 4s) with a capped maximum and a retry limit.
Retry with backoff
python
import time
import requests
def api_request(method, url, max_retries=3, **kwargs):
for attempt in range(max_retries):
resp = requests.request(method, url, **kwargs)
if resp.status_code == 429:
retry_after = int(resp.headers.get("Retry-After", "5"))
print(f"Rate limited; waiting {retry_after}s")
time.sleep(retry_after)
continue
resp.raise_for_status()
return resp.json()
raise RuntimeError("Max retries exceeded")
javascript
async function apiRequest(url, options = {}, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const res = await fetch(url, options);
if (res.status === 429) {
const retryAfter = parseInt(res.headers.get("Retry-After") || "5", 10);
console.log(`Rate limited; waiting ${retryAfter}s`);
await new Promise((r) => setTimeout(r, retryAfter * 1000));
continue;
}
if (!res.ok) throw new Error(`API error: ${res.status}`);
return res.json();
}
throw new Error("Max retries exceeded");
}
FAQ
How do I find my actual rate limits instead of guessing?
Call GET /v1/account/tier with your API key — it returns your real requests_per_minute, requests_per_day, concurrent_limit, and max_credits_per_day for your current plan. Limits are tier-based, so don't hardcode numbers.
What happens when I exceed a rate limit?
The API returns HTTP 429 with X-RateLimit-* headers and a Retry-After header telling you how many seconds to wait. Read Retry-After and wait — don't retry immediately.
Is the daily credit cap the same thing as the rate limit?
No — they're separate. Request-rate limits govern how many calls you can make per minute/day; the daily credit cap governs total spend per day. Both return 429 when exceeded, and the credit cap resets at 00:00 UTC.
What's the recommended way to handle 429s in my own retry logic?
Honor Retry-After first, then back off exponentially on repeated 429s (e.g. 1s, 2s, 4s) with a capped maximum and a retry limit — see "Retry with backoff" above for working Python and JavaScript examples.
Should I cache my tier limits, or check them on every request?
Cache them. Call /v1/account/tier once at startup — tier limits rarely change mid-session.