Lumirank API docs

Rate limits

Each brand can make 200 requests per minute. How to see how many are left, and how to retry.

The limits

  • A brand can make 200 requests per minute. All keys of the brand share this count.
  • The count starts again at 0 at the start of each minute, in UTC.
  • A brand can run at most 4 reports at the same time.
  • Separately, each IP address can send at most 20 requests per second, with short bursts of up to 100.

See how many requests are left

Every response has 3 headers with the brand's count:

X-RateLimit-Limit: 200
X-RateLimit-Remaining: 143
X-RateLimit-Reset: 17

X-RateLimit-Remaining is the number of requests left this minute. X-RateLimit-Reset is the number of seconds until the count starts again.

When you go over the limit

The 201st request in a minute gets status 429 with the error code rate_limited. The response has a Retry-After header with the number of seconds to wait. It is the same number as X-RateLimit-Reset:

{
  "error": {
    "code": "rate_limited",
    "message": "This brand made more than 200 requests this minute. Retry after 12 seconds.",
    "param": null
  }
}

If a brand starts a 5th report while 4 of its reports are still running, the 5th gets status 429 with the error code too_many_concurrent_reports. Wait a moment and send it again.

Retry a failed request

  • After a 429, wait the number of seconds in Retry-After, then send the request again.
  • After a 500 or a 503, wait and retry, and wait twice as long after each failure.
  • Do not send any other failed request again without changing it. It gets the same error.

This Python function follows these rules:

import os
import time

import requests

API = "https://api.lumirank.ai/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['LUMIRANK_API_KEY']}"}


def get(path, params=None):
    for attempt in range(5):
        resp = requests.get(f"{API}{path}", headers=HEADERS, params=params, timeout=60)
        if resp.status_code == 429:
            time.sleep(int(resp.headers.get("Retry-After", "1")))
            continue
        if resp.status_code in (500, 503):
            time.sleep(2 ** attempt)
            continue
        resp.raise_for_status()
        return resp.json()
    raise RuntimeError(f"{path} still failing after 5 tries")


print(get("/brand")["name"])

In a long export, check X-RateLimit-Remaining and pause when it gets low, so you stay under the limit.

On this page