Waiting rooms
Getting a parked participant in once they are admitted.
If a room has a waiting room enabled, an ATTENDEE/VIEWER join returns
token: null and waitingForApproval: true — the participant must be
admitted before a token exists. While parked, the join response's joinUrl
points at the …/join?status=waiting park screen.
A host admits a parked participant with
POST /rooms/{roomId}/participants/{participantId}/approve (tenant key, from
your backend), and that response returns the participant's token directly
— the simplest path is to relay it to the waiting client.
There is intentionally no public "am I admitted yet?" endpoint: a parked participant holds no credential to authenticate one with, and an endpoint keyed by participant id would turn that id into a capability. Three supported patterns, all backend-side:
Preferred — react to the webhook
Subscribe to participant.joined (Webhooks) and
re-call /rooms/{id}/join once the admission lands.
Poll the admission endpoint
GET /rooms/{roomId}/participants/{participantId}/admission (tenant key,
permission participants.read; the participantId comes from the parked join
response) returns { "status": "waiting" | "admitted" | "denied" }. Once
admitted, the response includes fresh token, livekitUrl, and joinUrl —
re-navigate the participant's tab and you're done. This is a cheap read: it
never re-opens an ended room and never re-notifies hosts, so it is the
safe thing to leave on a timer.
Fallback — poll /join
Re-calling /rooms/{id}/join with the same externalUserId is idempotent
and safe: an already-admitted participant is not sent back to the waiting
room, and repeat calls do not re-notify hosts. Poll every 3 seconds and
open /join as soon as token !== null.
Two limits to respect when polling:
- The rate limit is per API key across your whole tenant, not per room — a 3-second poll is 20 requests/minute, so on FREE (60/min) about three concurrent polls exhaust your budget; back off on 429.
/join(unlike the admission endpoint) re-opens anENDEDroom, so a poll left running after the host ends the meeting will resurrect it and resume billing. Always bound the loop (5 minutes is a sane ceiling) and stop onroom.finished.
The park screen
While the participant waits, you can park their browser on
…/join?status=waiting (no token), which shows a "waiting for the host"
screen. That page never polls on its own — your backend owns the poll and
re-navigates the tab to …/join?token=…&url=… once it has a token.