Skip to main content
Documentation

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
bash

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:

EndpointRequired inputsReturnsBilling
livekit/generate-tokenroomName (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-roomroomName (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-roomroomSessionId (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-roomroomName{ 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 }
ts

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-room when 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-room records 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_URL outside *.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#