Account
Rate limits
How api14 rate limits work by plan, per-key requests per minute and daily USD limits, and how to handle 429 responses with retries.
Rate limits protect your balance and the service. Limits are counted in requests per minute (RPM) per API key, and keys can also have a daily USD spend limit.
Limits by plan
| Plan | Requests per minute |
|---|---|
| Free | 5 |
| Pro | 100 |
| Team | 3,000 |
| Enterprise | 3,000+ |
Upgrade on the pricing page to raise your limit.
Per-key limits
When you create or edit a key in API keys you can set:
| Limit | Effect |
|---|---|
| RPM limit | Caps requests per minute for this key. The effective limit is the lower of the key limit and your plan limit. |
| Daily USD limit | Once the key has spent this much today (UTC), further requests return 429 daily_limit_reached until the next day. |
| Model allowlist | Only the listed model ids can be used with this key; others return 403 model_not_allowed. |
The RPM window is one minute and is counted per key, so separate keys for separate apps do not share a limit, but every key is still capped by your plan limit.
Rate limit headers
Every generation response (success or error) tells you where you stand, so you can slow down before you hit the limit instead of after:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed in the current one-minute window for this key. |
X-RateLimit-Remaining | Requests left in the window. |
X-RateLimit-Reset | Seconds until the window resets. |
Browser clients can read them too (they are listed in Access-Control-Expose-Headers).
Bursts and concurrency
Requests over the limit are not rejected right away: they wait in a queue and start as soon as the one-minute window frees up. Up to 10 requests per account run at the same time; the rest wait until one finishes. Before a request starts, its estimated maximum cost is reserved from your balance together with the requests already running, so parallel requests can never spend more than you have. A request that cannot start within 60 seconds returns 429 (rate_limited or concurrency_limit) with Retry-After; one whose cost no longer fits your balance returns 402 insufficient_balance.
Safe retries with Idempotency-Key
A network error can leave you unsure whether a request reached us. Send an Idempotency-Key header (any unique string up to 120 characters, for example a UUID) and retry with the same key: if the first request was already sent to the model, the retry returns 409 idempotency_conflict instead of running, and paying for, the job twice. If the first request failed before reaching the model, the key is released and the retry runs normally. A key can be used once per account for 24 hours.
curl https://api14.com/api/v1/images/generations \
-H "Authorization: Bearer $API14_KEY" \
-H "Idempotency-Key: 6f1c2a3e-order-1842" \
-H "Content-Type: application/json" \
-d '{"model": "black-forest-labs/flux-3-image", "prompt": "a red bicycle"}'
When you hit a limit
Too many requests
HTTP/1.1 429 Too Many Requests
Retry-After: 60
{
"error": {
"message": "Rate limit of 5 requests per minute exceeded.",
"type": "rate_limit_error",
"code": "rate_limited"
}
}
Wait for the number of seconds in Retry-After, then retry. The official OpenAI SDKs retry 429 responses automatically with backoff (two retries by default; configure with maxRetries / max_retries).
Daily spend limit
{
"error": {
"message": "This API key reached its daily spend limit.",
"type": "rate_limit_error",
"code": "daily_limit_reached"
}
}
Retrying does not help until the next UTC day. Raise or remove the key's daily limit in API keys if this is expected traffic.
Upstream limits
Providers have their own limits, which are stricter for :free model variants. When a provider rate-limits a request, its 429 is passed through to you. Use model fallbacks or provider routing to spread load across providers.
Handling limits in code
- Respect
Retry-Afterand retry with exponential backoff and jitter. - Distinguish
rate_limited(retry later) fromdaily_limit_reachedandinsufficient_balance(retrying does not help). - Queue background jobs instead of firing them all at once.
- Stream long responses: one streamed request counts as one request.
import time
from openai import OpenAI, RateLimitError
client = OpenAI(base_url="https://api14.com/api/v1", api_key="sk-api14-...", max_retries=0)
for attempt in range(5):
try:
r = client.chat.completions.create(model="openai/gpt-5-mini", messages=[{"role": "user", "content": "Hi"}])
break
except RateLimitError as e:
if e.code == "daily_limit_reached":
raise
time.sleep(int(e.response.headers.get("retry-after", 2 ** attempt)))
See Errors for every status code.