LiveKit rooms
Audio and video rooms through the livekit/* endpoints - token minting, room lifecycle, and reserve-then-settle billing.
On this page
Audio/video - voice chat, video calls, watch-together rooms, real-time transcription - runs on LiveKit through the livekit/* integration endpoints. The SDK's role is deliberately narrow: it is a room-lifecycle proxy - create, list, and delete rooms; mint access tokens. There is no useMediaRoom hook and no media Durable Object class. The client-side WebRTC plumbing is yours to wire with LiveKit's own SDK.
Skip this page for text-only collaborative apps - live sync, presence, and messaging need none of it.
Install the client SDK yourself#
The LiveKit JS SDK is not bundled with deepspace. Install it as your own dependency:
npm i livekit-client
# or, for React-shaped components:
npm i @livekit/components-react @livekit/components-styles livekit-client
DeepSpace handles the auth and room-lifecycle proxy; connecting, publishing tracks, and rendering participants belong to the LiveKit client API - use LiveKit's own documentation for that surface.
The five endpoints#
Billing varies by endpoint - read this table before touching src/integrations.ts:
| Endpoint | Required inputs | Returns | Billing |
|---|---|---|---|
livekit/generate-token | roomName (optional displayName, ttlSeconds 60-86400, default 3600) | { token, url, roomName } | Free. The room auto-creates when the first participant connects. No participant or duration caps. |
livekit/create-room | roomName (optional maxParticipants 1-100 default 10, durationMinutes 1-1440 default 60, metadata) | { roomSid, roomName, roomSessionId, adminToken, livekitUrl, expiresAt, maxParticipants, durationMinutes } | Billable. Reserves the worst case - maxParticipants × durationMinutes × $0.0005 × 1.3 (the raw LiveKit rate times the platform's 1.3× markup) - at create time, then settles down to actual usage when you call livekit/settle-room. The reservation cost is derived server-side; a client cannot supply it. |
livekit/settle-room | roomSessionId (from create-room), participantMinutes (≥ 0) | { ok, billedParticipantMinutes } | Free. Bills the reported participant-minutes clamped to the reservation cap and refunds the remainder. Idempotent per roomSessionId; creator-only. |
livekit/delete-room | roomName | { deleted, roomName } | Free. Does not settle billing, has no creator check, and under the scaffold's default developer billing no sign-in requirement either. |
livekit/list-rooms | (none) | { rooms: [...] } (LiveKit's Twirp ListRooms shape) | Free. |
Two flows - pick by whether you need caps#
Ad-hoc flow (free) - the default#
For small group calls, low-stakes voice chat, "drop into a room" UX:
Mint a token
const r = await integration.post('livekit/generate-token', { roomName, displayName })
if (!r.success) throw new Error(r.error)
const { token, url } = r.data as { token: string; url: string; roomName: string }
Connect with the LiveKit client
Pass token and url to livekit-client (or @livekit/components-react). The room auto-materializes when the first participant connects and disposes itself when empty.
No create-room call, no billing. This is the right flow unless you need participant or duration limits.
Billable flow - rooms with quotas#
For paid features, large meetings, and time-limited sessions:
Create the room (reserves the worst case)
Call integration.post('livekit/create-room', { roomName, maxParticipants, durationMinutes }). This reserves maxParticipants × durationMinutes × $0.0005 × 1.3 (raw rate times the platform markup) up front and returns an adminToken for the creator plus a roomSessionId. Persist the roomSessionId - settlement needs it.
Mint per-user tokens
Use livekit/generate-token for each participant - free; the room itself is the billed object.
Settle when the session ends
Call livekit/settle-room with the saved roomSessionId and the actual participantMinutes. Billing settles down to actual usage and the unused reservation is refunded. Optionally call livekit/delete-room to tear the room down.
Settlement rules#
- Always call
settle-roomwhen a session ends. Skip it and the full worst-case reservation is billed: a platform cron settles abandoned cloud rooms at exactly their reservation - the cap the caller authorized at create time. - Settlement is creator-only:
create-roomrecords the owner, and no other caller can settle (or under-report) someone else's room. - Settlement is idempotent per
roomSessionId- a double settle, or a settle racing the cron, nets one charge. - Reported minutes are clamped to the reservation cap - a client can never bill past what was reserved; under-reporting only reduces the charge.
- Self-hosted LiveKit is never metered. With a
LIVEKIT_URLoutside*.livekit.cloud, the reservation is voided to zero at create time.
Auth-gate the token-minting page#
A leaked generate-token token grants room access until ttlSeconds expires (default one hour) - there is no revocation. Always auth-gate the page or component that mints tokens: wrap it in useAuth().isSignedIn, or place it behind <AuthGate> when the whole page is gated. For the billable flow, gate create-room - under the default developer billing an anonymous visitor can commit billable reservations against the app owner - and gate delete-room per the warning above. settle-room needs no extra gating - it is creator-only and refund-only.
Next steps#
- External APIs - the
integration.post(...)client, billing modes, and discovery. - Integrations reference - envelope types and request options.
- Realtime rooms - the SDK's own Durable Object rooms, which handle data sync, not media.