Rate Limits
Understand the rate limits applied to the BeeL API and how to handle them.
The BeeL API enforces rate limits to protect service stability. Limits are applied per client (identified by API key or IP address) within a 60-second rolling window.
Tiers
| Tier | Limit | Period | Applied to |
|---|---|---|---|
| Standard | 100 requests | 60 seconds | All resource endpoints |
| Global | 1,000 requests | 60 seconds | All /api endpoints combined |
All limits apply simultaneously. A request to /api/v1/invoices counts against both the Standard tier (100/min) and the Global tier (1,000/min).
Rate-Limited Endpoints
Standard (100 req/min)
| Endpoint | Method | Description |
|---|---|---|
/api/v1/invoices/** | ANY | All invoice operations (CRUD, bulk, PDF, email) |
/api/v1/customers/** | ANY | All customer operations (CRUD, bulk) |
/api/v1/nif/validate | POST | NIF/CIF validation |
/api/v1/subscriptions/checkout | POST | Subscription checkout |
/api/v1/public/metrics | GET | Public metrics |
/api/v1/me | ANY | Profile operations |
/api/v1/me/logo | POST | Logo upload |
/api/v1/companies/{id}/representation/generate | POST | Generate representation document |
/api/v1/companies/{id}/representation/submit | POST | Submit representation document |
Global (1,000 req/min)
Applied to all /api requests regardless of endpoint. This is a safety net to prevent any single client from overwhelming the system.
Client Identification
Rate limits are tracked per client:
- API key users → identified by the
Bearer beel_sk_...token - Browser/anonymous users → identified by IP address
Each client has its own independent quota for each tier.
Excluded Endpoints
| Endpoint | Reason |
|---|---|
/api/webhooks/stripe | Stripe signs webhook requests; rejecting them causes retries |
Response Headers
When a rate limit is hit, the API returns 429 Too Many Requests with these headers:
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 60
RateLimit-Limit: 100
RateLimit-Remaining: 0
RateLimit-Reset: 60{
"error": "Rate limit exceeded. Try again in a minute."
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before retrying |
RateLimit-Limit | Maximum requests allowed in the window |
RateLimit-Remaining | Requests remaining in the current window |
RateLimit-Reset | Seconds until the window resets |
Handling Rate Limits
Retry with backoff
async function requestWithRetry(fn: () => Promise<any>, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (error.status === 429) {
const retryAfter = parseInt(error.headers?.['retry-after'] || '60');
await new Promise(r => setTimeout(r, retryAfter * 1000));
continue;
}
throw error;
}
}
throw new Error('Max retries exceeded');
}Best practices
- Use bulk endpoints when operating on multiple resources — one bulk request instead of N individual requests
- Cache responses where possible to avoid unnecessary API calls
- Respect
Retry-Afterheaders instead of retrying immediately - Use idempotency keys so retried requests don't create duplicates
API Status
Check status.beel.es for real-time API uptime, incident reports, and scheduled maintenance.
Need Higher Limits?
If the standard limits don't fit your use case, contact us and we'll work out a plan:
📧 Request a rate limit increase →