Skip to content

Rate limits and concurrency

Two limits apply to each organization. Both are shared by all of the organization’s keys.

Limit Default What it counts
Requests per minute 30 Every authenticated request to the API, in fixed 60 second windows.
Concurrent live calls 2 Calls placed with POST /calls that are queued, dialing or in_progress.

These are the defaults. If you need higher limits, email sales@sahay.io.

The window is fixed, not sliding: it lasts 60 seconds from its first request, and the count resets when it ends. A request that carries a valid key counts against the limit even if it later fails. Requests with a missing, malformed, unknown or revoked key are not counted.

When you go over the limit, the API answers 429 with the code rate_limited and a Retry-After header:

{
"error": {
"code": "rate_limited",
"message": "Rate limit of 30 requests per 60s exceeded."
}
}

Wait Retry-After seconds before you try again.

Successful responses carry these headers. The three X-RateLimit headers are also on a 429.

Header Meaning
X-RateLimit-Limit Requests allowed per window.
X-RateLimit-Remaining Requests left in the current window.
X-RateLimit-Reset When the window resets, as a Unix timestamp in seconds.
Retry-After On a 429 rate_limited only: seconds to wait.

POST /calls is refused with 429 live_call_limit when your organization already has its maximum number of API calls in progress. This response has no Retry-After header. Retry when a call has ended, which you can detect with the call.completed webhook or by reading the call.

Notes:

  • Only calls placed through POST /calls count. Campaign calls do not use this limit.
  • A call that has stayed queued, dialing or in_progress for more than 60 minutes no longer holds a slot.
  • Use webhooks instead of polling GET /calls/{call_id}.
  • Page lists with limit and cursor rather than requesting many small pages.
  • Add contacts in batches of up to 500 per request.
  • Back off on 429 and honor Retry-After.