Rooms & sessions
A room is an isolated real-time session with a fixed capacity, optional cloud recording, and a media region. Manage rooms exclusively from your backend with Basic Auth.
Create on demand
Spin up a room when a session starts — no pre-provisioning required.
Inspect status
Read capacity, participant count, region, recording flag, and metadata.
Graceful end
Disconnect everyone, finalize recording, and stop usage billing.
Hard delete
Remove the room resource after archival for data hygiene.
12
maxParticipants
50
per room (Preview)
300s
auto-end if unused
Composite
optional cloud MP4
Authentication
Authorization: Basic <token>. Auth guide →Provision a new video room. The room enters ready immediately and becomes active when the first client connects successfully.
Request body
{"name": "Support Session #1042","maxParticipants": 4,"record": true,"metadata": {"ticketId": "TKT-1042","queue": "billing","agentId": "agt_22"}}
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | optional | Label for dashboards and support. Default: generated name. |
| maxParticipants | integer | optional | Hard cap on concurrent joins. Default 12, max 50. |
| record | boolean | optional | Start cloud recording when room becomes active. Default false. |
| metadata | object | optional | App-defined key/values echoed on GET and webhooks (≤ 4 KB). |
Response
{"success": true,"code": "VIDEO_ROOM_CREATED","message": "Video room created successfully.","requestId": "REQ-1782001000001","timestamp": "2026-07-12T10:15:00.000Z","data": {"roomId": "rm_8f3a2c1b0e9d","name": "Support Session #1042","status": "ready","maxParticipants": 4,"participantCount": 0,"record": true,"recordingStatus": "idle","region": "af-west","metadata": {"ticketId": "TKT-1042","queue": "billing","agentId": "agt_22"},"createdAt": "2026-07-12T10:15:00.000Z","emptyTimeoutSeconds": 300,"joinUrl": "https://video.sendexa.co/r/rm_8f3a2c1b0e9d"}}
Code examples
curl -X POST 'https://api.sendexa.co/v1/video/rooms' \-H 'Content-Type: application/json' \-H 'Authorization: Basic YOUR_DASHBOARD_BASE64_TOKEN' \-d '{"name": "Support Session #1042","maxParticipants": 4,"record": true,"metadata": { "ticketId": "TKT-1042" }}'
Fetch the current state of a room. Prefer webhooks for participant join/leave; use GET for reconciliation, admin tools, and recovery after process restarts.
| Field | Type | Required | Description |
|---|---|---|---|
| roomId | path string | required | Room identifier returned at creation (e.g. rm_8f3a2c1b0e9d). |
curl -X GET 'https://api.sendexa.co/v1/video/rooms/rm_8f3a2c1b0e9d' \-H 'Authorization: Basic YOUR_DASHBOARD_BASE64_TOKEN'
{"success": true,"code": "VIDEO_ROOM_RETRIEVED","message": "Room retrieved.","requestId": "REQ-1782001000100","timestamp": "2026-07-12T10:20:00.000Z","data": {"roomId": "rm_8f3a2c1b0e9d","name": "Support Session #1042","status": "active","maxParticipants": 4,"participantCount": 2,"participants": [{"identity": "agent-ada","role": "host","joinedAt": "2026-07-12T10:16:02.000Z","publishing": { "audio": true, "video": true, "screen": false }},{"identity": "user_ama","role": "participant","joinedAt": "2026-07-12T10:16:45.000Z","publishing": { "audio": true, "video": true, "screen": false }}],"record": true,"recordingStatus": "recording","region": "af-west","metadata": { "ticketId": "TKT-1042" },"createdAt": "2026-07-12T10:15:00.000Z","startedAt": "2026-07-12T10:16:02.000Z","endedAt": null,"emptyTimeoutSeconds": 300}}
Gracefully terminate the live session: all connected clients are disconnected, media stops, and if record was enabled the composite finalizes. Status becomes ended. You can still GET the room until it is deleted.
Idempotent
/end on an already ended room returns success with the current snapshot (or 409 ROOM_ALREADY_ENDED depending on account settings). Safe to retry from webhooks or jobs.curl -X POST 'https://api.sendexa.co/v1/video/rooms/rm_8f3a2c1b0e9d/end' \-H 'Authorization: Basic YOUR_DASHBOARD_BASE64_TOKEN' \-H 'Content-Type: application/json' \-d '{}'
{"success": true,"code": "VIDEO_ROOM_ENDED","message": "Room ended. Participants disconnected.","requestId": "REQ-1782001000200","timestamp": "2026-07-12T10:45:00.000Z","data": {"roomId": "rm_8f3a2c1b0e9d","status": "ended","participantCount": 0,"record": true,"recordingStatus": "processing","startedAt": "2026-07-12T10:16:02.000Z","endedAt": "2026-07-12T10:45:00.000Z","durationSeconds": 1738}}
When recording completes, you receive video.recording.ready.
Permanently remove the room resource. Prefer ending first if the session may still be live. Deleting an active room also forces disconnect (same as end) then purges the resource.
curl -X DELETE 'https://api.sendexa.co/v1/video/rooms/rm_8f3a2c1b0e9d' \-H 'Authorization: Basic YOUR_DASHBOARD_BASE64_TOKEN'
{"success": true,"code": "VIDEO_ROOM_DELETED","message": "Room deleted.","requestId": "REQ-1782001000300","timestamp": "2026-07-12T11:00:00.000Z","data": {"roomId": "rm_8f3a2c1b0e9d","status": "deleted","deletedAt": "2026-07-12T11:00:00.000Z"}}
Recordings survive deletion
Room object fields
| Field | Type | Required | Description |
|---|---|---|---|
| roomId | string | required | Globally unique room ID (prefix rm_). |
| name | string | optional | Optional display name. |
| status | string | required | ready | active | ended | deleted |
| maxParticipants | integer | required | Configured capacity. |
| participantCount | integer | required | Current connected participants. |
| record | boolean | required | Whether recording was requested. |
| recordingStatus | string | optional | idle | recording | processing | ready | failed | none |
| region | string | required | Media region ID (e.g. af-west). |
| metadata | object | optional | Echo of create-time metadata. |
| emptyTimeoutSeconds | integer | required | Seconds before unused ready rooms auto-end. |
| createdAt / startedAt / endedAt | ISO 8601 | optional | Lifecycle timestamps. |
create ──► ready ──(first join)──► active ──(/end or empty timeout)──► ended ──(DELETE)──► deleted│ │└── emptyTimeout ─────────┘└── if record=true → recording processing → video.recording.ready
Tokens can only be issued for rooms in ready or active. Joins against ended / deleted fail at the media layer.
HTTP status codes
| Code | Status | Description |
|---|---|---|
| 200 | OK | Room returned, ended, or deleted successfully |
| 201 | Created | Room provisioned (create may return 200 or 201) |
| 400 | Bad Request | Invalid body (capacity, types, metadata size) |
| 401 | Unauthorized | Missing or invalid Basic Auth |
| 403 | Forbidden | Live Video not enabled or insufficient plan |
| 404 | Not Found | Unknown roomId |
| 409 | Conflict | Room already ended or not in expected state |
| 429 | Too Many Requests | Rate limit exceeded |
Best practices
- Create one room per logical session (appointment, ticket, class). Do not reuse rooms across days.
- Store
roomIdnext to your domain entity for audit and support. - Always
/endfrom the server when the business outcome is done (even if clients disconnect). - Keep
maxParticipantsrealistic — oversized rooms waste SFU resources and degrade quality. - After create, immediately issue tokens for known attendees rather than creating tokens hours early with long TTLs.
Next: issue join tokens →