Guides
Rate Limits
Satryx enforces per-key request limits to keep the API stable for everyone.
Current limits
| Parameter | Type | Description |
|---|---|---|
| Default RPM | 60 | Requests per minute per API key, across all endpoints. |
| Burst allowance | 10 | Short burst above the RPM limit before throttling begins. |
Note:Limits are enforced per API key, not per IP or per account. Give each integration its own key so limits are isolated.
Rate limit headers
Every response includes these headers so you can track your usage proactively:
| Parameter | Type | Description |
|---|---|---|
| X-RateLimit-Limit | integer | Your RPM limit for this key. |
| X-RateLimit-Remaining | integer | Requests remaining in the current window. |
| X-RateLimit-Reset | integer | Unix timestamp when the window resets. |
| Retry-After | integer | Seconds to wait before retrying. Only present on 429 responses. |
bash
HTTP/2 429
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1714001234
Retry-After: 7
Content-Type: application/json
{
"error": {
"type": "rate_limit_error",
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded. Retry in 7 seconds.",
"param": null
}
}Handling 429s
Read Retry-After
Always use the Retry-After header value — it's the exact number of seconds until your bucket refills. Don't guess or use a fixed delay.
python
import time, httpx
resp = httpx.post("https://api.satryx.ai/v1/chat/completions", ...)
if resp.status_code == 429:
wait = int(resp.headers.get("Retry-After", "5"))
time.sleep(wait)
# retryExponential backoff fallback
If Retry-After is absent (e.g. on a 500), use exponential backoff with jitter:
python
import random, time
def backoff(attempt: int) -> float:
base = min(2 ** attempt, 60) # cap at 60s
jitter = base * random.uniform(0.5, 1.5)
return jitterClient-side smoothing
If you're sending many requests in parallel, add a small delay between concurrent requests to stay within the RPM window:
python
import asyncio, time
async def smooth_batch(prompts, rpm=50):
interval = 60 / rpm
tasks = []
for prompt in prompts:
tasks.append(asyncio.create_task(call_api(prompt)))
await asyncio.sleep(interval) # space out requests
return await asyncio.gather(*tasks)Known limitations
Rate limiting is currently in-process per server worker. In a multi-worker deployment the effective limit may be higher than advertised (up to workers × RPM). This is a known gap that will be addressed when Redis is added to the stack.
Warning:Do not rely on the lenient multi-worker behavior — it will tighten when Redis rate limiting ships.