Skip to content

Rate Limits

API usage is subject to fair-use limits that may change without notice.

Results per page. List endpoints return at most 100 results per page on all paid tiers (10 on Free), controlled by the per_page query parameter. There is no pagination depth cap on paid tiers, so the full result set is retrievable by paging through it — see Pagination for Large Datasets.

Monthly API-call allowance. Each organization has a monthly allowance for calls made with a bs_live_ API key: 25,000/month on Professional, unlimited on Enterprise. Every API-key response reports your current position via headers:

Header Meaning
X-RateLimit-Limit Your monthly allowance (unlimited on unlimited tiers)
X-RateLimit-Used Calls made so far this calendar month
X-RateLimit-Remaining Calls left this month (unlimited on unlimited tiers)

These headers are informational: the allowance is currently tracked and reported but not enforced, so calls are not rejected for exceeding it. The counter resets at the start of each calendar month (UTC).

Burst rate. If you send too many requests in a short window you may receive HTTP 429 with error code RATE_LIMITED. Back off and retry.

Handling Rate Limits

When you receive HTTP 429 (error code RATE_LIMITED), back off and retry.

import time
import requests

def api_request(url, headers, max_retries=3):
    for attempt in range(max_retries):
        response = requests.get(url, headers=headers)
        if response.status_code == 429:
            retry_after = int(response.headers.get("Retry-After", 60))
            time.sleep(retry_after)
            continue
        return response
    raise Exception("Rate limit exceeded after retries")

Pagination for Large Datasets

Always paginate large requests rather than fetching all at once.

def fetch_all_cves(api_key, severity="CRITICAL"):
    headers = {"Authorization": f"Bearer {api_key}"}
    base_url = "https://breachspider.com/api/v1/cves"
    page = 1

    while True:
        response = requests.get(
            f"{base_url}?severity={severity}&page={page}&per_page=100",
            headers=headers
        )
        data = response.json()
        yield from data["data"]

        if not data["pagination"]["has_next"]:
            break
        page += 1