Troubleshooting1 min readUpdated Mar 22, 2026

Handling Rate Limits in PriceFetch

TL;DR

Read the X-RateLimit headers, implement exponential backoff on 429 responses, and use a request queue with concurrency control to stay within limits.

Understanding PriceFetch Rate Limits

PriceFetch applies two rate limits per API key:

**Per-second limit** — defaults to 5 requests/second. Protects the service from burst traffic. If you exceed this, you get a 429 with a short reset time.

**Monthly limit** — depends on your plan. Tracks total requests per billing period. When hit, all requests return 429 until the next period or until you upgrade.

Every response includes three headers: - `X-RateLimit-Limit` — your maximum requests per second - `X-RateLimit-Remaining` — requests remaining in the current window - `X-RateLimit-Reset` — seconds until the rate limit window resets

Read these headers proactively. If `X-RateLimit-Remaining` is 1, slow down before you hit 0.

Exponential Backoff and Request Queuing

When you receive a 429, don't immediately retry. Wait for the duration specified in `X-RateLimit-Reset`, then retry. If the header is missing, use exponential backoff: wait 1s, then 2s, then 4s.

For batch operations (checking hundreds of URLs), use a request queue with concurrency control. This prevents bursts that trigger rate limits in the first place.

python
import asyncio
import httpx

API_KEY = "pf_live_abc123"

async def fetch_with_rate_limit(urls: list[str], max_per_second: int = 4):
    """Fetch prices respecting rate limits. Use max_per_second slightly
    below your actual limit to leave headroom."""
    semaphore = asyncio.Semaphore(max_per_second)
    results = []

    async with httpx.AsyncClient(timeout=30) as client:
        async def fetch_one(url: str):
            async with semaphore:
                for attempt in range(3):
                    resp = await client.get(
                        "https://api.pricefetch.dev/v1/price",
                        params={"url": url},
                        headers={"X-API-Key": API_KEY},
                    )
                    if resp.status_code == 429:
                        reset = int(resp.headers.get("X-RateLimit-Reset", 2 ** attempt))
                        await asyncio.sleep(reset)
                        continue
                    return resp.json()
                return None

        tasks = [fetch_one(url) for url in urls]
        results = await asyncio.gather(*tasks)

    return results

Still stuck?

Our support team can help debug your integration.

Contact Support

Frequently asked questions

Related Retailers

Start fetching prices — 500 free credits

Sign up in 30 seconds. No credit card required. One credit per successful API call.