Rate limits
Four tiers, applied by endpoint group.
| Endpoints | Limit |
|---|---|
Authentication — /auth/login, /auth/register, /auth/refresh | 10 requests / 15 minutes |
Widget chat — /chat/:id/message | 20 requests / minute |
| Ingestion and uploads — adding sources, refreshing, recrawling, image uploads | 15 requests / minute |
Everything else under /api | 120 requests / minute |
Exceeding a limit returns 429 Too Many Requests.
Why authentication is so tight
Ten attempts per fifteen minutes is deliberately restrictive — it is the defence against password guessing.
Do not build a retry loop against /auth/login. If a login fails, the credentials
are wrong; retrying will lock you out of the endpoint without ever succeeding.
Log in once and reuse the session cookies for the rest of your run.
Request size caps
| Limit | Value |
|---|---|
| JSON and form request bodies | 1 MB |
| Document upload | 25 MB |
| Image upload | 2 MB |
The 1 MB body cap applies to JSON. File uploads use multipart/form-data and are
governed by their own limits, not this one.
A very long pasted-text source can exceed 1 MB. Split it into several sources — which is better practice anyway, because focused sources retrieve more accurately than one enormous one.
Handling a 429
Back off and retry. Do not retry immediately in a tight loop.
async function withRetry(fn, attempts = 4) {
for (let i = 0; i < attempts; i++) {
const res = await fn();
if (res.status !== 429) return res;
// 1s, 2s, 4s, 8s
await new Promise(r => setTimeout(r, 1000 * 2 ** i));
}
throw new Error('Rate limited after retries');
}
Staying under the limits
Bulk-loading content. Ingestion allows 15 requests per minute. Adding fifty sources means pacing them — roughly one every four seconds, or batches with a pause between.
Polling for training status. GET /chatbots/:id/status
falls under the general 120/minute limit, so once every few seconds is
comfortable. Crawls take minutes; polling more often than every five seconds
tells you nothing new.
Fetching leads or history on a schedule. Once every few minutes is ample. A tight loop wastes your allowance on unchanged data.
Message allowance is not a rate limit
Separately from these per-minute limits, your account has a monthly message allowance from your plan.
When it runs out, widget messages fail with 429 Message limit reached. Unlike a
rate limit, waiting does not clear this — it resets with your billing period, or
when you upgrade.
The two are distinguishable by the error message:
| Message | Meaning | Fix |
|---|---|---|
Message limit reached | Monthly allowance exhausted | Upgrade, or wait for the reset |
| (rate limiter response) | Too many requests too quickly | Back off and retry |
Chatbot limit
Creating a chatbot beyond your plan's allowance returns
403 Chatbot limit reached for your plan. That is a 403, not a 429 — it is a
permission outcome, not a throughput one, and retrying never helps.