Guide
Rate limits
Each API key may make 120 requests per minute. Every response tells you how many you have left, and a refused request tells you how long to wait.
The limit
The limit is per key, not per project. A minute starts with a key's first request and lasts 60 seconds; the count then starts again at zero. It is a fixed window, not a rolling one.
Note · Counted per server instance
The counters live in the memory of the server that handled the request, and start again if it restarts. Treat the headers as the truth for the response you are holding, not as a guarantee about the next one.
- Limit
- 120 requests per minute
- Counted per
- API key; two keys are counted separately
- Window
- Fixed: 60 seconds from a key's first request
- Counts
- Every request with a valid key, including ones that fail or are refused
- Does not count
- Requests without a valid key (401)
- Kept
- In one server instance's memory
Headers
Every response to a request with a valid key carries three headers.
| Header | Value |
|---|---|
X-RateLimit-Limit | The limit: 120. |
X-RateLimit-Remaining | Requests left in the current window. |
X-RateLimit-Reset | Seconds until the window ends. A duration, not a timestamp. |
Retry-After | Only on 429. The same number of seconds as X-RateLimit-Reset. |
HTTP/1.1 200 OKX-RateLimit-Limit: 120X-RateLimit-Remaining: 119X-RateLimit-Reset: 60Content-Type: application/json; charset=utf-8Handling 429
When a request is refused, wait the number of seconds in Retry-After and send it again. Nothing was done with the refused request, so repeating it is safe.
- Add a little random delay if several workers share a key, so they do not all retry in the same instant.
- Give up after a few attempts and report the failure, instead of looping forever.
- Better still, stay under the limit: watch
X-RateLimit-Remainingand slow down as it approaches zero. Waiting for webhooks instead of pollingGET /v1/calls/:idremoves most of the requests an integration makes.
#!/bin/sh# Repeats a request while the API answers 429, waiting as Retry-After says.attempt=0while :; do status=$(curl -s -o response.json -D headers.txt -w "%{http_code}" \ "http://localhost:4000/v1/agents" \ -H "Authorization: Bearer $OXUMI_API_KEY") [ "$status" != "429" ] && break
attempt=$((attempt + 1)) [ "$attempt" -ge 5 ] && break
wait=$(awk 'tolower($1) == "retry-after:" { print $2 + 0 }' headers.txt) sleep "${wait:-1}"done
echo "$status"cat response.jsonHTTP/1.1 429 Too Many RequestsX-RateLimit-Limit: 120X-RateLimit-Remaining: 0X-RateLimit-Reset: 16Retry-After: 16Content-Type: application/json; charset=utf-8
{"statusCode":429,"message":"Rate limit of 120 requests per minute exceeded."}