Rate limits
Lane.Chat rate-limits its public endpoints with fixed windows. When you exceed a limit you get an HTTP 429 with a Retry-After header and rate-limit metadata (see Error codes).
Public REST API
Limits are applied per endpoint group. The window is in seconds.
| Endpoint(s) | Limit | Window |
|---|---|---|
/v1/chat (session init) | 30 | 60s |
/v1/send-message | 60 | 60s |
/v1/upload | 10 | 60s |
/v1/forms/submit | 30 | 60s |
/v1/widget/* group | 60 | 60s |
/v1/knowledge/* (public read/search) | 120 | 60s |
/v1/binding/telegram/generate | 10 | 60s |
Native SDK
The SDK endpoints use a per-app fixed hourly window:
| Endpoint(s) | Limit | Window |
|---|---|---|
/api/v1/sdk/sessions | 10,000 | 1 hour |
/api/v1/sdk/events | 100,000 | 1 hour |
/api/v1/sdk/identify and /api/v1/sdk/push/register are not separately rate-limited.
Handling 429
- Respect the
Retry-Afterheader (seconds) before retrying. - Use exponential backoff with jitter for automated clients.
- Read
X-RateLimit-Remainingto slow down before you hit the wall.
js
async function postWithRetry(url, body, headers, attempt = 0) {
const res = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json', ...headers },
body: JSON.stringify(body),
})
if (res.status === 429 && attempt < 5) {
const wait = Number(res.headers.get('Retry-After') || 2 ** attempt)
await new Promise((r) => setTimeout(r, wait * 1000))
return postWithRetry(url, body, headers, attempt + 1)
}
return res.json()
}Limits can change
These values reflect the current server configuration. Treat 429 + Retry-After as the source of truth in production rather than hard-coding assumptions.