Rate Limits

How Woosmap APIs report rate limit usage in response headers, and how to back off when a request returns 429 Too Many Requests.

Each endpoint has its own rate limit, shared by all the API keys of a project. The endpoint’s reference page shows it: Ratelimit: 50/1s means 50 requests per second.

Read your remaining quota

Every response tells you where you stand:

        RateLimit-Policy: "requests";q=40;w=1
RateLimit: "requests";r=39;t=1

    
Field Meaning Here
q Requests allowed per window 40
w Window length, in seconds 1 second
r Requests left in this window 39
t Seconds until the window resets 1 second

Handle a 429

Once r reaches 0, the API answers 429 Too Many Requests until the window resets. Wait t seconds, then retry. Retrying right away fails again.

  • Retry at most three times.
  • If the 429 has no RateLimit header, wait 1, 2, then 4 seconds.
  • In a batch job, pause as soon as r reaches 0, without waiting for the 429.
Retry on 429
        import re
import time

import requests


def retry_delay(response: requests.Response, attempt: int) -> int:
    header = response.headers.get("RateLimit", "")
    waits = [
        int(reset)
        for remaining, reset in re.findall(r"r=(\d+);t=(\d+)", header)
        if remaining == "0"
    ]
    return max(waits, default=2**attempt)


def get(url: str, params: dict, retries: int = 3) -> requests.Response:
    for attempt in range(retries + 1):
        response = requests.get(url, params=params, timeout=10)
        if response.status_code != 429 or attempt == retries:
            return response
        time.sleep(retry_delay(response, attempt))

    
        function retryDelay(response, attempt) {
  const header = response.headers.get("RateLimit") ?? "";
  const waits = [...header.matchAll(/r=(\d+);t=(\d+)/g)]
    .filter(([, remaining]) => remaining === "0")
    .map(([, , reset]) => Number(reset));
  return waits.length ? Math.max(...waits) : 2 ** attempt;
}

async function get(url, retries = 3) {
  for (let attempt = 0; ; attempt++) {
    const response = await fetch(url);
    if (response.status !== 429 || attempt === retries) return response;
    await new Promise((resolve) => setTimeout(resolve, retryDelay(response, attempt) * 1000));
  }
}

    

Complete scripts, with tests, are in woosmap-samples.

Special cases

  • The Distance Matrix limits requests and matrix elements separately, and lists both policies: RateLimit: "elements";r=999;t=1, "requests";r=19;t=2. Wait for the one at r=0. The code above handles it.
  • RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset (X-RateLimit-* on the Distance API) are legacy headers that describe only the last policy. Use RateLimit.
  • Browsers can’t read these headers, because the API does not expose them to cross-origin JavaScript. Read them on your server.
  • If your normal traffic keeps reaching the limit, contact [email protected].
Was this helpful?