Billium

Rate limits

Request caps enforced by the Billium API and how to handle them.

Billium enforces two layers of rate limiting. They are additive — a request must pass both to be served.

ScopeLimitWindowKeyed on
Global (per IP)50 requests60 secondsClient IP address
Per API key300 requests60 secondsFirst 16 characters of your API key

The per-key limit is what matters for most production workloads — the global IP limit is a cheap first line of defence against abuse from a single source.

What happens when you're throttled

The API returns 429 Too Many Requests:

{
  "statusCode": 429,
  "message": "ThrottlerException: Too Many Requests",
  "error": "Too Many Requests"
}

A Retry-After header tells you how many seconds to wait before retrying.

Handling 429s

With the Node SDK (recommended). @billium/node retries 429 automatically with exponential backoff, honoring Retry-After. You do not need to write any retry logic for transient throttling.

Manually. Read Retry-After, sleep, and retry. Use jittered exponential backoff to avoid synchronising a retry storm across your fleet.

async function withBackoff<T>(fn: () => Promise<T>, attempts = 4): Promise<T> {
  for (let i = 0; i < attempts; i++) {
    try {
      return await fn();
    } catch (err) {
      if (err instanceof BilliumApiError && err.status === 429 && i < attempts - 1) {
        const delay = Math.floor(Math.random() * Math.min(500 * 2 ** i, 30_000));
        await new Promise((r) => setTimeout(r, delay));
        continue;
      }
      throw err;
    }
  }
  throw new Error('unreachable');
}

Avoiding the limit in the first place

  • Batch reads. Fetch a page of 100 invoices with limit=100 instead of 100 single-item calls.
  • Cache lookups. Static data (e.g. a product's metadata) doesn't need to be re-fetched per request.
  • Use webhooks instead of polling. If you're hitting GET /invoices/{id} in a loop waiting for status === 'PAID', switch to handling the invoice.paid webhook — that's what webhooks are for.
  • Use one key per integration. Splitting load across multiple keys gives each integration its own 300 req/min budget.

Need a higher limit?

The limits above are the defaults. If your production workload genuinely needs more headroom, email hello@billium.to with your merchant ID and a description of the traffic pattern.

On this page