Skip to content
Updraft Docs
Türkçe

Rate limits and quota

The API is free for the first year: there are no plan tiers, invoices or payments. Still, every keyed request is counted and limited against abuse. Limits are per product.

Products and limits

Product Covers Minute Day
tiles Keyed tile requests, region pack 1,200 200,000
query Every other /v1 call (reads, uploads, consent, sharing) 60 10,000
render Flight videos (next release) 5 100

These are the values of a standard key; the minute and day windows are fixed UTC windows (reset at the start of the minute and at UTC midnight). Each key also has a monthly quota across all products (UTC month), given to you with the key. Write to the administrator if you need higher limits.

The 429 response

When a limit is reached the API answers 429 with the usual error body (Errors):

{"code": "rate_limited", "detail": "rate limit of 60 per minute reached"}
code What ran out
rate_limited The minute or day window
quota_exceeded The monthly quota
Header Meaning
Retry-After Seconds until the window ends (at least 1)
X-RateLimit-Limit Limit of the exhausted window
X-RateLimit-Window minute, day or month

Refused requests are not counted, nor are 401 and 403. Invalid requests (422) are counted.

What a client should do

  • On 429 wait Retry-After seconds; do not repeat the request at once.
  • Keep read responses with their ETag: ask the same query with If-None-Match and you get 304 (no body, cheap) when nothing changed.
  • If you see 429 all the time, review your request pattern or ask the administrator for higher limits.
// A simple client that honours Retry-After (Node 24 or browser fetch).
export async function updraftGet(url, apiKey, { attempts = 3 } = {}) {
  for (let attempt = 1; ; attempt += 1) {
    const response = await fetch(url, { headers: { 'X-Api-Key': apiKey } });
    if (response.status !== 429 && response.status < 500) return response;
    if (attempt >= attempts) return response;
    const wait = Number(response.headers.get('Retry-After') ?? 2 ** attempt);
    await new Promise((resolve) => setTimeout(resolve, wait * 1000));
  }
}

Limits on tiles

Keyed tile requests fall under the tiles limits above and are counted for you. Tile requests without a key are guarded by a coarse limit per client address (a plain 429 without a body) and are not counted. Details: Tiles and styles.