Reference
Rate limits
How concurrency, request limits and quotas behave, and how to back off.
Updated 2026-10-25 · MainAI Compute docs
Limits protect shared GPU capacity. They are enforced per virtual key by the router. Set request and token limits on each key so one workload cannot starve another.
LayersLink to this section
| Layer | Behavior |
|---|---|
| Request rate | rpmLimit on the key. Excess returns 429. |
| Token rate | tpmLimit on the key. Excess returns 429. |
| Concurrency | One concurrent stream per key is soft-limited by the router. |
| Key budget | Hard cap from budgetCents. Exhaustion surfaces as an upstream budget error. |
| Wallet | Prepaid wallets stop serving at zero. Invoice organizations stop at their credit limit. |
| Request size | 8 MiB maximum body. |
| Stream idle | 300 seconds. An idle stream is closed. |
| Connect + first token | 300 second budget before a 503; streaming may then idle for 300 seconds. |
Request rate
- Behavior
rpmLimiton the key. Excess returns429.
Token rate
- Behavior
tpmLimiton the key. Excess returns429.
Concurrency
- Behavior
- One concurrent stream per key is soft-limited by the router.
Key budget
- Behavior
- Hard cap from
budgetCents. Exhaustion surfaces as an upstream budget error.
Wallet
- Behavior
- Prepaid wallets stop serving at zero. Invoice organizations stop at their credit limit.
Request size
- Behavior
- 8 MiB maximum body.
Stream idle
- Behavior
- 300 seconds. An idle stream is closed.
Connect + first token
- Behavior
- 300 second budget before a
503; streaming may then idle for 300 seconds.
Reading remaining capacityLink to this section
When the router supplies it, responses include x-mainai-remaining-requests for the current window. It is a hint, not a reservation. A 429 may include Retry-After.
curl -sS -D - -o /dev/null https://cloud.mainai.dk/v1/models \
-H "Authorization: Bearer $MAINAI_API_KEY" \
| grep -iE "^(x-request-id|x-mainai-remaining-requests|retry-after):"BackoffLink to this section
- 01
Stop on 429
Do not hammer through the window. Pause the worker or queue the job.
- 02
Honor Retry-After
If present, wait at least that long. Otherwise use exponential backoff with jitter.
- 03
Retry once the window opens
Keep the retry budget small and surface exhaustion to your own caller.
- 04
Reduce the base rate
If 429s recur, lower worker concurrency or raise the key limit.
const wait = (ms: number) => new Promise((r) => setTimeout(r, ms));
async function requestWithBackoff(init: RequestInit, attempts = 4) {
for (let i = 0; i < attempts; i++) {
const res = await fetch(`https://cloud.mainai.dk/v1/embeddings`, init);
if (res.status !== 429) return res;
const retryAfter = Number(res.headers.get("retry-after"));
await wait(Number.isFinite(retryAfter) ? retryAfter * 1000 : 500 * 2 ** i + Math.random() * 250);
}
throw new Error("rate limit retries exhausted");
}Design for the limitLink to this section
- Batch embeddings instead of sending one document per request.
- Queue bulk backfills separately from interactive traffic.
- Reuse HTTP connections; do not open a client per call.
- Use streaming for long generations so the user sees progress before the first full response completes.
- Use
max_tokensso one runaway response cannot consume a whole window. - Split workloads across keys when they need independent limits, then cap each key's budget.
Rate limits versus availabilityLink to this section
A 429 is a throughput decision, not an outage. A 503 with upstream_unavailable means the API could not reach an engine. Both are retryable, but only the second belongs on an availability dashboard.