Using the API
Rate limits
What you get
Each client has a token bucket. You may spend up to 600 requests at once, and you earn them back at 10 a second. Spending the whole bucket and then waiting a minute puts you back where you started.
A burst allowance matters more than an average here: drawing a map view is a rush of requests followed by nothing at all. A map that fetches its tiles and a join table does not come close to the bucket.
Clients are counted by address. An IPv6 client is counted by its /64 prefix rather than a single address, because one machine is usually given the whole prefix.
Reading the headers
Every response carries your budget, not just a refusal, so you can slow down before you're turned away. These are the fields of the IETF HTTPAPI draft:
| Header | What it says |
|---|---|
RateLimit-Policy | "default";q=600;w=60 — the bucket holds 600 requests and takes 60 seconds to refill from empty. |
RateLimit | "default";r=487;t=12 — you have 487 requests left, and the bucket is full again in 12 seconds. |
Retry-After | Sent only with a 429. The whole seconds to wait before the refused request would be affordable. |
When you're refused
A request you cannot afford is answered with 429 Too Many Requests as a problem document, with Retry-After in seconds. Nothing is queued and nothing is charged for the refusal: waiting the stated time and sending it again is the whole recovery.
Retry-Afteris authoritative. Prefer it to a backoff schedule of your own.- A
429is sent withCache-Control: no-store, so it never lands in a cache. - The limit is applied by the server rather than the route, so any operation can answer with it.
async function get(url) {
for (let attempt = 0; ; attempt++) {
const response = await fetch(url);
if (response.status !== 429) return response;
// Retry-After is authoritative; only guess if it's missing.
const wait = Number(response.headers.get("retry-after") ?? 2 ** attempt);
await new Promise((resolve) => setTimeout(resolve, wait * 1000));
}
}Staying under the limit
Most clients that hit the limit are re-fetching things that haven't changed, or fetching one row at a time. Both have a cheaper shape:
- Send back the
ETagyou were given. A304 Not Modifiedstill costs a request, but it costs no bandwidth. See Caching. - Take a whole table rather than a row at a time: bulk downloads serve an entire partition or lookup in one request.
- Use conditional requests for current Atlas data. An unchanged resource returns
304, so you do not re-download it. - Ask for a bigger page.
limitaccepts up to 500, so one request can replace ten.
Running the API yourself? The bucket is set by ATLAS_RATE_LIMIT_CAPACITY and ATLAS_RATE_LIMIT_REFILL_PER_SECOND, and a capacity of 0 turns the limit off.