API reference
Rate limits
Per-agent requests per minute, widget limits per key and per visitor, workflow limits, the X-RateLimit headers and how to retry.
Reference1 min readUpdated 23 October 2026
Limits protect your credits and the service from runaway loops. They are checked before a credit is spent, so a rejected request costs nothing.
The limits
| What | Limit | Scope |
|---|---|---|
| Chat requests | 60 a minute for new agents | Per agent, a fixed one-minute window, shared by the API, the widget and workflow Agent steps |
| Widget, per key | 120 a minute | Per publishable key |
| Widget, per visitor | 12 a minute | Per visitor IP address on that key (stored hashed) |
| Workflow runs | 30 a minute, 5 at once | Per account |
| Workflow webhook triggers | 60 a minute | Per workflow |
| Workflow emails | 100 a day | Per account |
The agent limit is shown read-only on the agent's Settings tab. It isn't a plan limit; if you need a higher one, email support.
Headers
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed per minute for this agent |
X-RateLimit-Remaining | Requests left in the current window |
X-RateLimit-Reset | Seconds until the current window resets |
Chat responses carry these on success and on 429. A chat 429 has no Retry-After: wait the number of seconds in X-RateLimit-Reset. Workflow 429s do send Retry-After (10 seconds for TOO_MANY_RUNNING).
Retrying well
- Retry
429after the reset, with a cap on attempts. Don't retry in a tight loop. - Don't retry
400,401,402,403,404or422: they won't succeed until something changes. - Retry
LLM_UNAVAILABLEandTIMEOUTonce or twice with a growing pause. - If you fan out many requests, queue them so you stay under the agent's per-minute limit.
async function chatWithRetry(body, attempt = 0) { const res = await fetch("https://api.sentientone.ai/v1/chat/stream", { method: "POST", headers: { "Content-Type": "application/json", "X-Api-Key": process.env.SENTIENTONE_API_KEY, "X-Agent-Id": process.env.AGENT_ID, }, body: JSON.stringify(body), }) if (res.status === 429 && attempt < 3) { // Chat 429s carry X-RateLimit-Reset, the seconds until the window resets (no Retry-After) const reset = Number(res.headers.get("X-RateLimit-Reset")) const waitMs = Number.isFinite(reset) && reset > 0 ? reset * 1000 : 2000 * (attempt + 1) await new Promise((r) => setTimeout(r, Math.min(waitMs, 60_000))) return chatWithRetry(body, attempt + 1) } return res}Still stuck?
Email us with what you tried and any request id. A person replies.