Skip to main content
The Causeloop API enforces a sliding-window rate limit per client IP. All requests — authenticated or not — count against the limit for the originating IP address.

Limits

WindowMax requests
60 seconds600
The limit is applied per IP address (or the first value of X-Forwarded-For when the request passes through a proxy). Requests from different IPs are counted independently.
When Redis is configured (REDIS_URL), the limit is enforced across all API replicas using a shared fixed-window counter. Without Redis, the counter is per-process — a single IP hitting multiple replicas gets a higher effective limit. In production, configure Redis for consistent enforcement.

Rate limit response headers

Every response — including successful ones — carries two rate limit headers:
HeaderDescription
X-RateLimit-LimitMaximum requests allowed in the 60-second window.
X-RateLimit-RemainingRequests remaining in the current window.
When the limit is exceeded, the 429 response also includes:
HeaderDescription
Retry-AfterSeconds to wait before the next window opens.
X-RateLimit-RemainingAlways 0 on a 429.

429 response body

{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests"
  }
}
The 429 error body does not include a trace_id. Use the Retry-After header value, not a fixed delay, to determine how long to wait.

Handling rate limits

Read the X-RateLimit-Remaining header on every response. When it reaches zero or you receive a 429, back off and retry:
# Read headers from any response
curl -I https://api.causeloop.ai/v1/issues \
  -H "Authorization: Bearer $CAUSELOOP_TOKEN"

# HTTP/2 200
# x-ratelimit-limit: 600
# x-ratelimit-remaining: 598

Best practices

Read X-RateLimit-Remaining proactively. If it’s low, slow down your request rate before hitting the limit. Implement exponential backoff with jitter. Start at the Retry-After value, then double the delay on each subsequent 429. Add random jitter (±500 ms) to avoid thundering-herd when multiple clients retry in sync. Avoid polling for status. Use the WebSocket stream for real-time updates — WebSocket messages do not count against REST rate limits. For endpoints that do require polling:
EndpointSafe poll interval
GET /v1/reports/jobs/{id}Every 5 seconds
GET /v1/exports/{id}Every 10 seconds
GET /v1/me/notifications/unread-countEvery 30 seconds
GET /v1/shell/navOn app focus, not on a timer
Batch requests where possible. Filter lists server-side (?status=open) rather than fetching all records and filtering client-side.