Skip to Content

Rate Limits

API requests are rate-limited per organisation per minute. The limit depends on the organisation’s active plan.


Limits by plan

PlanRequests per minute
Free60
Starter300
Professional1,000
Enterprise5,000

All tokens belonging to the same organisation share one rate-limit bucket — a service account and a PAT from the same org count against the same limit.


Rate-limit headers

Every authenticated response includes these headers:

HeaderExampleDescription
X-RateLimit-Limit300Requests allowed per minute
X-RateLimit-Remaining247Requests remaining in current window
X-RateLimit-Reset1745427600Unix timestamp when the window resets

Handling 429

When the limit is exceeded, the server returns:

HTTP/1.1 429 Too Many Requests Retry-After: 37 Content-Type: application/problem+json
{ "type": "https://problems.eunifyer.com/rate_limit_exceeded", "title": "Too Many Requests", "status": 429, "detail": "Rate limit exceeded", "code": "rate_limit_exceeded", "limit": 300, "reset_in_seconds": 37 }

Wait Retry-After seconds before retrying.


Retry with exponential backoff

Do not hammer the API after a 429. Use exponential backoff:

import time, httpx def call_with_retry(client: httpx.Client, method: str, url: str, **kwargs) -> httpx.Response: for attempt in range(5): r = client.request(method, url, **kwargs) if r.status_code == 429: wait = int(r.headers.get("Retry-After", 2 ** attempt)) time.sleep(wait) continue return r raise RuntimeError("Exceeded retry budget")
async function fetchWithRetry(url: string, options: RequestInit, maxRetries = 5): Promise<Response> { for (let attempt = 0; attempt < maxRetries; attempt++) { const resp = await fetch(url, options); if (resp.status === 429) { const retryAfter = parseInt(resp.headers.get("Retry-After") ?? String(2 ** attempt)); await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000)); continue; } return resp; } throw new Error("Exceeded retry budget"); }

Best practices

  • Monitor X-RateLimit-Remaining — throttle your request rate proactively rather than waiting for 429s.
  • Use cursor pagination efficiently — fetching large datasets with limit=100 uses fewer API calls than limit=20.
  • Batch creates — use Idempotency-Key on create operations so you can safely retry without double-creating on transient errors.
  • Use delta sync for Drive — the /drive/sync/delta endpoint is designed for sync clients and is more efficient than polling individual file endpoints.
  • Cache tokens — re-issuing a Keycloak token on every request is wasteful and will hit rate limits faster. Cache the access token and re-grant when it expires.