Rate limits
Default limits
Section titled “Default limits”Values confirmed in the backend (payments/settings.py, key REST_FRAMEWORK.DEFAULT_THROTTLE_RATES):
| Throttle | Limit | Scope |
|---|---|---|
anon — requests per day | 2000/day | Anonymous requests and those authenticated via X-Device-Id. |
anon_minute — requests per minute | 60/min | General requests. |
anon_minute_strict — strict minute | 15/min | Critical endpoints marked with @custom_throttle_strict. |
anon_day_strict — strict day | 200/day | Critical endpoints. |
user — authenticated users | 2000/day | For session-based flows; does not apply to integrators using X-Device-Id. |
Limits are cumulative: hitting any one returns HTTP 429 Too Many Requests.
Retry-After header
Section titled “Retry-After header”When you receive HTTP 429, B4bit Pay includes the Retry-After header with the number of seconds you must wait before retrying:
HTTP/1.1 429 Too Many RequestsRetry-After: 42Recommendations
Section titled “Recommendations”- Exponential backoff — start with the
Retry-Aftervalue and double on each consecutive 429. - Random jitter — add ±20% variation to avoid thundering herd.
- Batch your queries — group
GET /orders/by range instead of fetching individual orders. - Prefer webhooks over polling — webhooks do not consume quota.
429 handler example
Section titled “429 handler example”async function fetchWithBackoff(url, init, maxRetries = 5) { let delay = 1000; for (let i = 0; i < maxRetries; i++) { const res = await fetch(url, init); if (res.status !== 429) return res; const retryAfter = Number(res.headers.get('retry-after')) * 1000 || delay; const jitter = Math.floor(Math.random() * retryAfter * 0.2); await new Promise((r) => setTimeout(r, retryAfter + jitter)); delay *= 2; } throw new Error('Rate limit excedido tras reintentos.');}