Rate limits

Two layers sit between your request and an answer: the edge, by address, and the gateway, by key.

The edge (the TLS terminator in front of everything) limits by IP address and exists to make a credential-guessing flood or a reconnect storm cheap to refuse before it reaches anything that costs GPU time. The gateway then limits by key, and that is the budget that actually belongs to your account. You can hit either one; both answer 429 with the same envelope.

The edge, per IP address

PathLimitBody cap
/v1/* — no credential presented12 / min⁦32 MB⁩
/v1/* — a credential presented (valid or not)600 / min⁦32 MB⁩
/v1/audio/*60 / min⁦200 MB⁩
/v1/files*60 / min⁦256 MB⁩
/v1/models, /v1/pdf*, /v1/skills*, /v1/mcp*, /v1/vector_stores*, /v1/sandbox/*, /v1/route120 / min⁦64 MB⁩
/v1/realtime* (connection attempts)60 / min

"A credential presented" means the request carried a non-empty Authorization, x-api-key or api-key header — whether the key in it turns out to be valid is the gateway's question, not the edge's. The edge only separates "tried to authenticate" from "did not".

The gateway, per API key

TierRequests / minTokens / minMonthly spend capFree grant
free2060,000$5.00$5.00
paid3001,000,000None$0.00
rpm/tpm are stamped onto a key the moment it is minted. Moving your organisation to a higher tier changes the limit for keys you create *after* the change, not the ones already in your pocket — mint a new key (or ask whoever manages your org to) to pick up a new tier's throughput. The monthly spend cap and the free grant, by contrast, are read live and apply immediately.

What comes back on every response

HeaderWhen
x-ratelimit-limit-requests x-ratelimit-remaining-requestsOn every response, once your key carries an rpm limit.
x-ratelimit-limit-tokens x-ratelimit-remaining-tokensOn every response, once your key carries a tpm limit.
retry-afterOnly on 429 — seconds to wait. At the edge this counts down to a fixed one-minute window; at the gateway it counts down to the top of the next clock minute.

The 429 itself

From the edge — an address over its budget, before any key was even checked:

JSON
{"error": {"message": "Too Many Requests", "type": "api_error", "code": "429"}}

From the gateway — your key over its rpm or tpm budget for the current minute. The envelope matches every other gateway error (see Errors); the message names which dimension tripped and its current/limit values:

JSON
{
  "error": {
    "message": "LiteLLM Rate Limit Handler for rate limit type = key. Max parallel request limit reached. current rpm: 20, rpm limit: 20, current tpm: 4021, tpm limit: 60000, current max_parallel_requests: 1, max_parallel_requests: 100",
    "type": "requests",
    "param": null,
    "code": "429"
  }
}

Backing off correctly

Read retry-after when it is present and wait at least that long. When it is not, back off exponentially from a small base with jitter, so that many clients throttled at the same instant do not all retry on the same beat and recreate the flood they backed off from. Cap the number of attempts and give up loudly rather than retrying forever.
# Bash: exponential backoff with jitter, honouring Retry-After.
attempt=0
until [ $attempt -ge 6 ]; do
  code=$(curl -s -o /tmp/resp.json -w "%{http_code}" \
    https://api.console.larsa.larsima.com/v1/chat/completions \
    -H "Authorization: Bearer $LARSA_API_KEY" \
    -H "Content-Type: application/json" \
    -d "{\"model\":\"larsa-general\",\"messages\":[{\"role\":\"user\","\"content\":\"hi\"}]}")
  [ "$code" -lt 429 ] && cat /tmp/resp.json && break
  wait=$(( (2 ** attempt) + (RANDOM % 1000) / 1000 ))
  sleep "$wait"
  attempt=$((attempt + 1))
done
Navigate Open esc Close