OAuth Token Rate Limiting
This guide explains how rate limiting works on the Billabex Public API
(/api/public/v1/*) and how your client should behave to integrate
reliably and predictably.
Overview
Rate limiting is enforced per OAuth Bearer access token.
This model is designed to provide clear and deterministic behavior for integrations:
- One token = one shared quota across all public endpoints
- Tokens are isolated from each other
- Sliding window enforcement smooths short traffic bursts
If multiple systems or threads use the same token, they also share the same rate limit.
Rate-Limiting Model
| Aspect | Behavior |
|---|---|
| Scope | Per OAuth access token |
| Window type | Sliding window |
| Window duration | 60 seconds |
| Limit | 300 requests per window |
| Applies to | All OAuth-protected public endpoints |
| Exceeded behavior | 429 Too Many Requests + Retry-After |
Why Per-Token Limiting?
This design choice ensures:
- Fairness between independent integrations
- Isolation between tokens
- Predictable capacity planning on the client side
What this means for you
- Treat each access token as a shared, limited resource
- Centralize outgoing requests per token
- Avoid uncontrolled concurrency using the same token
Where Rate Limiting Applies
This model applies to all OAuth-protected endpoints under:
/api/public/v1/*
Examples:
GET /api/public/v1/accountsGET /api/public/v1/invoicesGET /api/public/v1/organizations
Rate Limit Response Headers
Every rate-limited response includes the following headers. These headers are your source of truth.
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed per window |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp (seconds) when the window resets |
Example Response
HTTP/1.1 200 OK
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 258
X-RateLimit-Reset: 1738859285
When the Limit Is Exceeded (429)
When the quota is exhausted, the API responds with:
- HTTP status
429 Too Many Requests - A
Retry-Afterheader indicating when it is safe to retry
Example 429 Response
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1738859285
Retry-After: 12
Content-Type: application/json
{
"statusCode": 429,
"message": "Too many requests",
"retryAfter": 12
}
Important
- Always respect
Retry-After - Do not retry immediately or use hardcoded delays
- Repeated violations may lead to additional protections
Recommended Client Behavior
To work reliably with the API, your client should:
- Centralize all outgoing requests per access token
- Monitor
X-RateLimit-Remainingand slow down proactively - On
429, wait forRetry-Afterbefore retrying - Cap retries and surface errors when limits are repeatedly hit
Reference Retry Pattern (JavaScript)
async function fetchWithTokenRateLimit(url, options = {}, maxRetries = 3) {
let attempt = 0;
while (attempt <= maxRetries) {
const response = await fetch(url, options);
// Success or non-rate-limit error
if (response.status !== 429) {
return response;
}
const retryAfterSeconds = Number(response.headers.get('Retry-After') || '1');
// Safety floor to avoid immediate retries
const waitMs = Math.max(1000, retryAfterSeconds * 1000);
if (attempt === maxRetries) {
return response;
}
await new Promise((resolve) => setTimeout(resolve, waitMs));
attempt += 1;
}
}
Best Practices
- Prefer pagination and batching to reduce request count
- Use a per-token request queue or throttler
- Keep concurrency controlled, especially for write-heavy flows
- Avoid large parallel bursts using the same token
- If you rotate tokens, remember that quotas are tracked per token
Next Steps
- Getting Started – End-to-end integration flow
- OAuth Authentication – Token lifecycle and OAuth flow
- Pagination – Reducing request volume
- API Reference – Endpoint details and examples
Support
Questions about OAuth token rate limiting?
Contact us via the website contact form.