Skip to navigation

Rate limits

Per-workspace request budgets, the headers that describe them, and how to back off.

View as Markdown

Rate limits protect your workspace and the platform. REST API limits are counted per workspace once the request is authenticated: every API key of the same workspace shares the same budgets, and there is no per-IP limit in front of /api/*, so many workspaces calling from one egress IP do not share a budget. The public endpoints that are not tied to a workspace (the MCP endpoint, the web chat widget, Zapier) are counted per client IP.

All limits use a 60-second window. The counter starts with the first request in the window and resets when the window ends. Each limiter that applies to a request counts it once.

General API limit

/api/* routes are behind a general limit that scales with your plan. The exceptions are /api/whatsapp and /api/billing, which use only their own limits below.

PlanRequests per minute
No active plan120
Starter120
Growth200
Business300
Enterprise600

Stricter limits on specific routes

Some routes carry a stricter limit. Where it is added on top of the general limit, a request must pass both. WhatsApp and billing routes are governed by their own limit instead of the general one.

RoutesLimitNotes
Outbound: POST /api/calls, POST /api/calls/{callId}/transfer, POST /api/email/send and everything under /api/whatsapp20 / minThese routes share one budget per workspace. Placing a call, starting a transfer and sending an email also count against the general limit. Listing calls, reading a call, downloading its audio, hanging up, completing or canceling a transfer, and reading or saving email settings use only the general limit.
Mutations on agents, campaigns, webhooks and other configuration (for example POST /api/agents, POST /api/campaigns, PATCH /api/campaigns/{campaignId}/activate, POST /api/webhooks)10 / minThese routes share one budget per workspace.
Contact imports: POST /api/campaigns/{campaignId}/contacts/bulk, .../upload-preview and .../upload-confirm5 / minThese three routes share one budget per workspace. Listing contacts, adding a single contact and downloading the CSV template use only the general limit.
Analytics endpoints under /api/analytics30 / minOne budget for every analytics route, including /api/analytics/analysis/*, KPIs and events.
Audit log under /api/audit20 / min
Billing under /api/billing15 / min

Loading many contacts? Use a single POST /api/campaigns/{campaignId}/contacts/bulk request (up to 5,000 contacts) instead of one request per contact.

The outbound limit fails closed: if Jelliu cannot count requests reliably, the routes it covers answer 429 until it can, so that outbound spend is never uncapped. Reads such as listing calls are not affected.

Response headers

Responses from rate-limited routes include:

HeaderMeaning
RateLimit-LimitRequests allowed in the current window.
RateLimit-RemainingRequests left in the current window.
RateLimit-ResetSeconds until the window resets.
RateLimit-PolicyThe policy, in the form limit;w=60.
Retry-AfterSent with 429: seconds to wait before retrying.

When several limits apply to one request, the RateLimit-* headers describe one of them. Always rely on Retry-After when you receive a 429.

When you hit a limit

The API answers 429 Too Many Requests with code RATE_LIMIT_EXCEEDED:

HTTP/1.1 429 Too Many Requests
Retry-After: 42
RateLimit-Limit: 120
RateLimit-Remaining: 0
RateLimit-Reset: 42
Content-Type: application/json
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests, please slow down"
}
}

The message differs between limits (for example Rate limit exceeded for outbound operations or Too many agent operations, please slow down); the code is always RATE_LIMIT_EXCEEDED.

Handling 429 responses

async function jelliuFetch(url, init, attempts = 5) {
for (let i = 0; i < attempts; i++) {
const res = await fetch(url, init);
if (res.status !== 429 && res.status !== 503) return res;
const retryAfter = Number(res.headers.get('Retry-After'));
const waitMs = Number.isFinite(retryAfter) && retryAfter > 0
? retryAfter * 1000
: 2 ** i * 1000;
await new Promise((resolve) => setTimeout(resolve, waitMs));
}
throw new Error('Rate limited: retries exhausted');
}

Other limits

  • MCP server. The MCP endpoint allows 120 requests per minute per client IP. Each tool the assistant calls is an API request and also counts against your workspace limits above.
  • Zapier and inbound webhooks. /zapier/* and the webhook receivers share 200 requests per minute per client IP. See Zapier.
  • Web chat widget. Public widget traffic is limited per visitor IP, per widget (its rate_limit_rpm setting, 30 by default) and per workspace (300 per minute across all widgets). See Web chat widget.
  • Plan capacity such as concurrent calls, and budgets you configure on agents, are not rate limits. They return their own codes (MAX_CONCURRENT_CALLS_REACHED, AGENT_BUDGET_EXCEEDED); see Errors.