Worked room lifecycle: create → token → record → fetch
The run-through every video integration does first: create a room, mint a join token for a participant, record the session, then read the session’s signed playback URL once the room has ended. All requests use your API key (X-API-Key) against https://api.orbit.devotel.io.
1. Create the room
POST /api/v1/video/rooms_, -, 3–200 characters).
The response returns the SFU room name plus a host token and the WebSocket
URL the host client connects to.
Request
room_name carries a server-side tenant prefix; display_name is the
label you supplied. Feed the returned token and url to a LiveKit client
SDK to pick up audio and video — token is a LiveKit access JWT, not an
HTTP bearer token.
The scheduled-room surface (recurrence, registration, simulive, webinar
layouts) is a sibling surface under POST /api/v1/video/rooms-scheduled —
its create call also mints the orbit-media egress when
recording_enabled: true, so skip step 3 for those rooms.
2. Mint a participant access token
POST /api/v1/video/rooms/{name}/tokenparticipant_name is the identity stamped on
the token; can_publish defaults to false (receive-only) and only an
owner or admin caller can set it to true. Minting a token under someone
else’s identity additionally requires impersonation_reason and an owner
or admin role, or the request is rejected with a four-hundred status.
Request
participant_tier is the finer-grained control: viewer (receive-only),
panelist (publishes audio/video), host, and hidden_supervisor. When
supplied it overrides can_publish; host and hidden_supervisor require
the owner or admin role. When omitted, the legacy can_publish boolean
controls the grant exactly as before.
3. Record the session
Recording is started by the host from inside the room (or automatically at room creation for scheduled rooms created withrecording_enabled: true),
and completed recordings are attached to the room’s session history by the
recording webhook. There is no second API call to make here — once the room
ends, the recording finalizes asynchronously. Listen for the
video.recording.completed webhook event (see
Webhook events) or poll GET /api/v1/video/sessions
until the session row appears with a non-null recording_url.
4. Fetch the recording asset
GET /api/v1/video/sessions/{id}recording_url as a time-limited signed HTTPS URL ready for a
<video> element or download, plus recording_url_expires_at so you know
when to re-fetch. A session whose recording has not finalized yet returns
recording_url: null.
recording_id is the unified-recordings primary key — use it with the
Recordings API to mint a time-limited guest share link for a non-account
viewer, or to pull the stored transcript. Treat both recording_url and
its signature as opaque and re-fetch the session when
recording_url_expires_at passes rather than re-signing it yourself.
Response envelopes
Every endpoint on this page answers in one of two envelope shapes, so one error handler covers all four steps above. Success —data carries the payload (a single object, or an array on
list endpoints such as GET /api/v1/video/sessions), and meta carries
request_id plus timestamp. List endpoints add a pagination block
under meta:
meta.pagination.has_more is true, pass meta.pagination.cursor
back as the cursor query parameter to fetch the next page — the cursor is
opaque; keep the same filters across pages and stop when has_more comes
back false.
Error — failures answer with { error, meta }, where error carries
code, status, and message. Validation failures return 422; token
privilege violations return 403 in this same shape:
403
PARTICIPANT_TIER_NOT_PERMITTED and IMPERSONATION_NOT_PERMITTED
before the generic error path — both mean the caller’s role cannot mint the
requested token, and retrying without changing the request will fail the
same way.