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. Once a request is authenticated, limits are counted per workspace: every API key of the same workspace shares the same budgets. Requests that are not yet tied to a workspace 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.

General API limit

Most /api/* routes are behind a general limit that scales with your plan:

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. Calls, WhatsApp, email and billing routes are governed by their own limit instead of the general one.

RoutesLimitNotes
Everything under /api/calls, /api/whatsapp and /api/email20 / minCovers operations that place calls or send messages, and applies to reads on those paths too.
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.
Everything under /api/campaigns/{campaignId}/contacts5 / minIncludes bulk imports and CSV upload confirmation.
Analytics endpoints under /api/analytics30 / min
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 limit on /api/calls, /api/whatsapp and /api/email fails closed: if Jelliu cannot count requests reliably, those routes answer 429 until it can, so that outbound spend is never uncapped.

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.
  • 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.