Skip to main content

Overview

Bipa enforces rate limits to ensure fair usage and protect the API from abuse. Rate limits are applied per API key.

Default limits

TierRequests per minuteRequests per day
Standard10010,000
Growth50050,000
EnterpriseCustomCustom
Contact sales if you need higher limits.

Rate limit headers

Every API response includes headers indicating your current rate limit status:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1705315860
HeaderDescription
X-RateLimit-LimitMaximum requests allowed per minute
X-RateLimit-RemainingRequests remaining in the current window
X-RateLimit-ResetUnix timestamp when the limit resets

Rate limit exceeded

When you exceed the rate limit, the API returns a 429 Too Many Requests response:
{
  "error": {
    "type": "rate_limit_error",
    "code": "too_many_requests",
    "message": "Rate limit exceeded. Please retry after 45 seconds."
  }
}
The Retry-After header indicates how long to wait (in seconds) before retrying:
HTTP/1.1 429 Too Many Requests
Retry-After: 45

Handling rate limits

Implement exponential backoff when you receive a 429 response:
import time
import requests

def api_request(url, max_retries=5):
    for attempt in range(max_retries):
        response = requests.get(url, headers=headers)

        if response.status_code == 200:
            return response.json()

        if response.status_code == 429:
            retry_after = int(response.headers.get("Retry-After", 60))
            print(f"Rate limited. Waiting {retry_after}s...")
            time.sleep(retry_after)
            continue

        response.raise_for_status()

    raise Exception("Max retries exceeded")

Best practices

Cache GET request responses to reduce API calls. Quotes, for example, are valid for 60 seconds.
from functools import lru_cache

@lru_cache(maxsize=100, ttl=60)
def get_quote(from_currency, to_currency, amount):
    return api_request(f"/quotes?from={from_currency}&to={to_currency}&amount_cents={amount}")
Use list endpoints instead of making individual requests:
# Instead of this:
for customer_id in customer_ids:
    customer = api_request(f"/customers/{customer_id}")

# Do this:
customers = api_request(f"/customers?ids={','.join(customer_ids)}")
Instead of polling for status changes, use webhooks to receive real-time notifications.
If you need to make many requests, spread them out rather than bursting:
import time

for item in items:
    process(item)
    time.sleep(0.6)  # ~100 requests per minute

Endpoint-specific limits

Some endpoints have additional limits:
EndpointLimitNotes
POST /quotes30/minQuote generation is rate-limited separately
POST /pix/payments60/minPix outbound payments
POST /onchain/withdrawals30/minOn-chain withdrawals
POST /lightning/payments60/minLightning payments

Monitoring usage

Track your API usage in the console:
  1. Go to SettingsAPI Usage
  2. View request counts by endpoint
  3. Set up alerts for approaching limits
Enable usage alerts to get notified before hitting rate limits.