To maintain platform stability and ensure fair use, Hipcall enforces rate limits on all /api/v3/* endpoints. This page explains the limits, how to detect them, and how to handle them properly.
Which endpoints are rate limited
All endpoints under /api/v3/* enforce rate limits when authenticated with one of the following:
- OAuth access token (issued through the OAuth 2.0 flow)
- Personal API token
Other endpoints (public documentation, health checks, web session routes) are not currently rate limited, but you should not rely on that — limits may be added at any time.
Default limits
| Setting | Value |
|---|---|
| Sustained rate | 60 requests / minute |
| Burst capacity | 60 requests |
| Refill rate | 1 request / second |
The limiter uses a token bucket algorithm. You can burst up to 60 requests instantly; after that, you regain capacity at 1 request per second, up to a maximum of 60.
How requests are counted
Counting is done per caller, not globally:
| Authentication | Counting unit |
|---|---|
| OAuth access token | (OAuth app, user) pair |
| Personal API token | The API token |
Every user of an OAuth app has their own bucket. Two users of the same app do not share a quota. Different OAuth apps acting on behalf of the same user do not share a quota either.
Response headers
Every rate-limited response (successful or 429) includes the following:
| Header | Description |
|---|---|
x-ratelimit-limit |
Bucket capacity (maximum burst) |
x-ratelimit-remaining |
Number of tokens remaining in the bucket |
x-ratelimit-reset |
Unix timestamp (in seconds) at which the bucket will refill |
retry-after |
Seconds to wait before retrying. Appears exclusively on 429 responses. |
Example:
HTTP/1.1 200 OK
x-ratelimit-limit: 60
x-ratelimit-remaining: 42
x-ratelimit-reset: 1735056000
content-type: application/json
Throttled response (429)
When the bucket is empty, the API returns an HTTP 429 Too Many Requests response:
HTTP/1.1 429 Too Many Requests
x-ratelimit-limit: 60
x-ratelimit-remaining: 0
x-ratelimit-reset: 1735056001
retry-after: 1
content-type: application/json
{
"errors": {
"detail": "Rate limit exceeded. Retry after 1 seconds."
}
}
Recommended client behavior
- Honor the
retry-aftervalue. Wait at least the specified number of seconds before retrying. Do not retry immediately. - Use exponential backoff with jitter if you hit repeated 429s, to prevent a thundering herd.
- Check
x-ratelimit-remainingin advance. If it is low, slow down before you get throttled. - Cache responses when possible to reduce request volume.
- Use webhooks instead of polling for resources that emit events.
- Spread out your bursts. A single tight loop consumes the burst budget in under a second.
Reference: backoff pseudocode
attempt = 0
while True:
response = call_api()
if response.status != 429:
return response
retry_after = int(response.headers.get("retry-after", "1"))
sleep(retry_after + random(0, 1)) # jitter
attempt += 1
if attempt > MAX_RETRIES:
raise RateLimitedError()
Custom limits for OAuth apps
OAuth apps with high-volume, legitimate needs can request custom limits (capacity and per-minute rate). Contact the support team with the following information:
- The OAuth app's
client_id - Expected sustained and peak request rates
- A short description of the use case
Service degradation
If our rate limiting subsystem becomes temporarily unavailable, requests are allowed through instead of being wrongly rejected ("fail open"). During such a period, the rate limit headers may show static fallback values; this does not mean unlimited use is allowed.