A rate limit caps how many requests you can make in a time window. It protects Livqeno, and your project, from runaway loops and leaked keys.
You mostly meet rate limits in one place: your backend minting tokens. For example, if 100 students click "Join class" at 9:00, your backend makes 100 token requests in a few seconds with the same API key. This page tells you whether that fits, and what to do when it doesn't.
The window is 60 seconds by default (RATE_LIMIT_WINDOW_SECONDS).
Limited endpoints
These are the limits on endpoints your backend calls:
| Endpoint | Requests per window | When your backend calls it |
|---|---|---|
POST /v1/rooms/{roomId}/rtc-tokens | 60 | Each time a user joins a call |
DELETE /v1/rooms/{roomId}/rtc-tokens/{tokenId} | 60 | When you revoke a token |
POST /v1/live-streams | 30 | When a host schedules or starts a stream |
POST /v1/live-streams/{streamId}/hosts | 60 | When you add a host or co-host |
POST /v1/live-streams/{streamId}/viewer-tokens | 120 | Each time a viewer opens a stream |
The Limits & quotas page has the same table, generated from the code.
Who the limit counts against
Livqeno counts requests against the most specific identity it has, in this order:
- The API key. Each key has its own limit. Two keys in one project don't share it, so one busy (or leaked) key can't use up another's.
- The logged-in user, for dashboard endpoints.
- The IP address, only when there's no identity yet (like sign-up and login).
Once there is an identity, the IP address is not used. So:
- Someone switching IPs is still one identity, and still limited.
- Many real users behind one office network don't share one limit.
Handling a 429
When you go over, the request fails with HTTP 429 and this body:
{
"code": "RAVEN_RATE_LIMITED",
"message": "Too many requests — please try again later",
"retryAfterSeconds": 42,
"requestId": "req_9f2c41ab77e0c3d5b1a4e8f2"
}On your backend:
- Wait for
retryAfterSeconds, then retry. Don't use a fixed delay. - If your user is waiting (for example, on a "Joining…" screen), keep them on that screen while you wait, instead of showing an error.
If you hit the limit often during normal use, look at your join flow. A common cause is minting a new token on every page render instead of once per join.
Chat and signaling have their own limits
These limits apply to your users' apps, not your backend:
- Chat limits sending, reacting, typing, subscribing, and connecting. They count per user, because a chat token always has one.
- RTC signaling (the connection an app opens to join a call) limits new WebSocket connections per IP. This check happens before the token is read, so there's no identity yet.
For the close code a chat limit produces, see WebSocket Protocol.
Next steps
- Limits & quotas: every limit, with its default.
- Errors: what
RAVEN_RATE_LIMITEDand the WebSocket close codes mean.