Guides

Rate Limits

Satryx enforces per-key request limits to keep the API stable for everyone.

Current limits

ParameterTypeDescription
Default RPM60Requests per minute per API key, across all endpoints.
Burst allowance10Short 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:

ParameterTypeDescription
X-RateLimit-LimitintegerYour RPM limit for this key.
X-RateLimit-RemainingintegerRequests remaining in the current window.
X-RateLimit-ResetintegerUnix timestamp when the window resets.
Retry-AfterintegerSeconds 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)
    # retry

Exponential 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 jitter

Client-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.