BatchRouter Docs

Rate limits

How BatchRouter rate-limits the API, what an HTTP 429 looks like, and how to back off correctly with retries and the Retry-After header.

The BatchRouter API is rate-limited to keep the platform stable and fair across all accounts. Limits are enforced per API key and per account. When you exceed a limit, the API responds with HTTP 429 Too Many Requests; your client should back off and retry rather than hammering the endpoint.

This page explains how to detect rate limiting and how to handle it. For the current limits and any per-endpoint details, consult the interactive API reference and the response headers you receive at runtime.

How rate limiting works

Rate limits apply at two scopes:

  • Per API key — each br_live_… key is metered independently.
  • Per account — usage is also aggregated across all of an account's keys.

Limits are enforced on request volume over a rolling window. BatchRouter is built for batch workloads, so the design intent is that you submit a small number of large batches rather than a high volume of tiny requests — a single POST /v1/batches call can carry many thousands of items, which is far more efficient than one request per item.

This page intentionally does not quote fixed numeric limits, because they can change and may differ by endpoint. Treat a 429 response (and any rate-limit headers it carries) as the authoritative signal, and check the API reference for the values in effect for your account.

A few endpoints have their own dedicated, stricter limits — for example, registration endpoints are tightly throttled to deter abuse. Those constraints are documented alongside the relevant operation in the API reference.

The 429 response

When you exceed a limit, the API returns HTTP 429 Too Many Requests. The response may include a Retry-After header indicating how long to wait before retrying — in seconds, or as an HTTP date. Always prefer the value the server gives you over a fixed delay of your own.

Inspect response headers on every 429. If a Retry-After header is present, wait at least that long before retrying. Any additional rate-limit headers the response carries are the source of truth for your remaining budget.

Handling 429 with backoff

The correct response to a 429 is to wait and retry with exponential backoff and jitter: increase the delay on each successive failure, and add a small random offset so that many clients retrying at once don't synchronize into a new spike. If a Retry-After header is present, honor it as the minimum wait.

cURL doesn't loop on its own, so back off in your shell. This retries up to five times, honoring Retry-After when present and otherwise doubling the delay:

url="https://api.batchrouter.com/v1/batches"
delay=1
for attempt in $(seq 1 5); do
  response=$(curl -s -w "\n%{http_code}" -D /tmp/headers.txt "$url" \
    -H "Authorization: Bearer $BATCHROUTER_API_KEY")
  code=$(printf '%s' "$response" | tail -n1)
  if [ "$code" != "429" ]; then
    printf '%s\n' "$response" | sed '$d'
    break
  fi
  retry_after=$(grep -i '^retry-after:' /tmp/headers.txt | awk '{print $2}' | tr -d '\r')
  wait=${retry_after:-$delay}
  echo "429 received; waiting ${wait}s before retry $attempt" >&2
  sleep "$wait"
  delay=$((delay * 2))
done

Practical guidance

  • Batch, don't spray. Put many items into one POST /v1/batches request instead of issuing one request per item. This is the single biggest factor in staying under any limit.
  • Poll on a sensible interval. When checking batch status with GET /v1/batches/{batchId}, poll periodically (for example, every few seconds at first, then less often) rather than in a tight loop. Prefer webhooks to learn about completion instead of aggressive polling where you can.
  • Always honor Retry-After. Treat the server's wait hint as a hard minimum.
  • Add jitter. Randomize backoff slightly so concurrent workers don't resynchronize into a new burst.
  • Cap your retries. After a reasonable number of attempts, surface the failure to your own error handling rather than retrying forever.

Rate limiting (429) is distinct from a funding or quota rejection. A request that fails because your account is out of credits or hits a billing control is not a 429 — see Errors to tell the responses apart and respond appropriately.

Next steps

On this page