Rate limits
Each key may make 60 requests a minute, across every endpoint
together — a call to GET/v1/networks and a call to GET/v1/outages come out of
the same minute.
The limit is counted per key, not per IP address. An integration running behind a shared NAT or a cloud provider's egress shares its IP with strangers; counting by key means nobody else's traffic can use up yours. If one integration needs more headroom than another, give each its own key.
GET/v1/status needs no key and is limited per address instead: 60 requests a minute, cached
for 30 seconds, so polling it faster gains nothing.
Requests without a valid key
A request with no key, a key that is not valid, or a key in the URL is answered 401. Twenty of those in
a minute from one address, and every request from that address — a valid key included — is answered
429 until the minute is up. A misconfigured client retrying in a loop stops being refused one request at
a time; fix the key, wait the minute, and carry on.
The headers
Every response reports where the key stands:
| Header | Means |
|---|---|
x-ratelimit-limit | Requests allowed per minute on this key. |
x-ratelimit-remaining | Requests left in the current minute. |
x-ratelimit-reset | Seconds until the minute resets. |
retry-after | On a 429 only: seconds to wait before trying again. |
When you are limited
Past the limit, the API answers 429 rate_limited and a retry-after header. A refused call is not
billed, so a burst that hits the limit costs nothing — but it does not get you the data either.
Wait for retry-after seconds, then carry on. Retrying immediately only earns another 429.
async function get(url) {
for (;;) {
const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.AOT_API_KEY}` } });
if (res.status !== 429) return res;
const wait = Number(res.headers.get('retry-after') ?? 5);
await new Promise((r) => setTimeout(r, wait * 1000));
}
}You rarely need to go fast
The networks themselves update every few minutes, and meta.data_as_of on every response says when the
latest poll finished. Asking more often than that returns the same data. To follow changes, poll
GET/v1/outages with changed_since every few minutes rather than re-reading everything — see
Keeping a copy in sync.