Live Video API
Preview
REST

Getting started

Go from zero to a working browser video session: provision a room, mint a join token on your server, and connect with the Sendexa Video Web SDK.

Enable Live Video

Turn on Live Video for your business in the dashboard and copy your Basic Auth token.

Create a room

POST /v1/video/rooms from your backend with optional name, capacity, and record flag.

Issue join tokens

Mint short-lived host/participant/viewer tokens per user — never expose REST credentials.

Embed the Web SDK

Load the Sendexa Video client, pass roomId + token, and connect with media constraints.

Base URL

api.sendexa.co

HTTPS only

Auth (REST)

Basic

Dashboard Base64 token

Client auth

JWT

Join token per identity

Time to first room

<2 min

With valid credentials

Prerequisites
  • A Sendexa business account with Live Video enabled (Preview)
  • Dashboard API token (Basic Auth) used only on the server
  • HTTPS origin for the browser page (required for getUserMedia)
  • Modern browser with WebRTC (Chrome, Firefox, Edge, Safari 14+)

Step 1 — Create a room

POST
/v1/video/rooms

Rooms are the isolation boundary for a session. Create one when a meeting, consult, or class starts. See Rooms & sessions for the full reference.

FieldTypeRequiredDescription
namestringoptionalHuman-readable label (max 128 chars). Shown in dashboard logs.
maxParticipantsintegeroptionalCapacity including host. Default 12, max 50.
recordbooleanoptionalIf true, composite cloud recording starts when the room becomes active.
metadataobjectoptionalArbitrary JSON (≤ 4 KB) echoed in GET room and webhooks.
Bash
curl -X POST 'https://api.sendexa.co/v1/video/rooms' \
-H 'Content-Type: application/json' \
-H 'Authorization: Basic YOUR_DASHBOARD_BASE64_TOKEN' \
-d '{
"name": "Onboarding Call — Ama K.",
"maxParticipants": 3,
"record": false,
"metadata": {
"appointmentId": "apt_991",
"product": "kyc-video"
}
}'
JSON
{
"success": true,
"code": "VIDEO_ROOM_CREATED",
"data": {
"roomId": "rm_8f3a2c1b0e9d",
"name": "Onboarding Call — Ama K.",
"status": "ready",
"maxParticipants": 3,
"participantCount": 0,
"record": false,
"region": "af-west",
"metadata": {
"appointmentId": "apt_991",
"product": "kyc-video"
},
"createdAt": "2026-07-12T11:00:00.000Z",
"emptyTimeoutSeconds": 300
}
}

Step 2 — Issue a join token

POST
/v1/video/rooms/:roomId/tokens

Tokens authorize a single identity to join a specific room with a role and expiry. Generate them only on your backend after authenticating the end user. Full docs: Tokens & auth.

FieldTypeRequiredDescription
identitystring
required
Stable user identifier in your system (e.g. user_42). Max 64 chars, unique per concurrent join.
rolestring
required
One of: host | participant | viewer.
ttlintegeroptionalLifetime in seconds. Default 3600. Min 60, max 86400.
Bash
curl -X POST 'https://api.sendexa.co/v1/video/rooms/rm_8f3a2c1b0e9d/tokens' \
-H 'Content-Type: application/json' \
-H 'Authorization: Basic YOUR_DASHBOARD_BASE64_TOKEN' \
-d '{
"identity": "user_ama",
"role": "participant",
"ttl": 1800
}'
JSON
{
"success": true,
"code": "VIDEO_TOKEN_ISSUED",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"roomId": "rm_8f3a2c1b0e9d",
"identity": "user_ama",
"role": "participant",
"expiresAt": "2026-07-12T11:30:00.000Z",
"ttl": 1800
}
}

Step 3 — Embed the Web SDK

The browser client never calls the room management API. It only needs roomId and the join token from your app backend.

HTML embed snippet
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Sendexa Live Video</title>
<script src="https://cdn.sendexa.co/video/v1/sendexa-video.min.js"></script>
<style>
#stage { width: 100%; max-width: 960px; aspect-ratio: 16/9; background: #0b0f19; }
#local, #remote-grid video { width: 100%; height: 100%; object-fit: cover; }
</style>
</head>
<body>
<div id="stage">
<video id="local" autoplay muted playsinline></video>
<div id="remote-grid"></div>
</div>
<button id="join">Join</button>
<button id="leave">Leave</button>
<button id="toggle-mic">Mic</button>
<button id="toggle-cam">Camera</button>
<button id="share">Share screen</button>
<script>
// Injected securely from your backend (do not hardcode secrets)
const ROOM_ID = "rm_8f3a2c1b0e9d";
const TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...";
const room = new SendexaVideo.Room({
roomId: ROOM_ID,
token: TOKEN,
// Optional: prefer a region if the room was created without sticky pin
// region: "af-west",
media: {
audio: true,
video: {
width: { ideal: 1280 },
height: { ideal: 720 },
frameRate: { ideal: 24, max: 30 },
facingMode: "user"
}
}
});
room.on("localTrack", ({ track, kind }) => {
if (kind === "video") {
track.attach(document.getElementById("local"));
}
});
room.on("participantConnected", (participant) => {
participant.tracks.forEach((pub) => {
if (pub.track) attachRemote(pub.track, participant.identity);
});
participant.on("trackSubscribed", (track) => {
attachRemote(track, participant.identity);
});
});
room.on("disconnected", (reason) => {
console.log("left room", reason);
});
document.getElementById("join").onclick = () => room.connect();
document.getElementById("leave").onclick = () => room.disconnect();
document.getElementById("toggle-mic").onclick = () => room.localParticipant.setMicrophoneEnabled(
!room.localParticipant.isMicrophoneEnabled
);
document.getElementById("toggle-cam").onclick = () => room.localParticipant.setCameraEnabled(
!room.localParticipant.isCameraEnabled
);
document.getElementById("share").onclick = () => room.localParticipant.setScreenShareEnabled(true);
function attachRemote(track, identity) {
if (track.kind !== "video" && track.kind !== "audio") return;
let el = document.getElementById("remote-" + identity);
if (!el) {
el = document.createElement(track.kind === "video" ? "video" : "audio");
el.id = "remote-" + identity;
el.autoplay = true;
el.playsInline = true;
document.getElementById("remote-grid").appendChild(el);
}
track.attach(el);
}
</script>
</body>
</html>
NPM / bundler usage
Bash
npm install @sendexa/video-client
JavaScript
import { Room } from '@sendexa/video-client';
const room = new Room({
roomId,
token,
media: {
audio: { echoCancellation: true, noiseSuppression: true },
video: { width: 1280, height: 720, frameRate: 24 },
},
});
await room.connect();
// room.localParticipant, room.participants, room.disconnect()

Media constraints

Constraints map to the browser MediaTrackConstraints model. The SFU may downscale or simulcast based on subscriber bandwidth; requested values are ideals, not guarantees.

Audio

echoCancellation, noiseSuppression, autoGainControl — enable for voice calls.

Video

Ideal 720p @ 24 fps for most apps; 360p for low bandwidth; max 1080p in Preview.

Screen share

Hosts and participants can publish a screen track; viewers cannot publish.

Adaptive bitrate

Simulcast layers let remote clients subscribe at a bitrate matching their network.

JavaScript
// Recommended defaults by scenario
const constraints = {
// 1:1 support / telehealth
call: {
audio: { echoCancellation: true, noiseSuppression: true, autoGainControl: true },
video: { width: { ideal: 1280 }, height: { ideal: 720 }, frameRate: { ideal: 24 } },
},
// Low bandwidth / mobile data
economy: {
audio: true,
video: { width: { ideal: 640 }, height: { ideal: 360 }, frameRate: { ideal: 15, max: 20 } },
},
// Audio-only fallback
audioOnly: {
audio: true,
video: false,
},
// Webinar host
host: {
audio: true,
video: { width: { ideal: 1920 }, height: { ideal: 1080 }, frameRate: { ideal: 30 } },
},
};
// Viewer role should join with publish disabled (SDK honors token role)
const viewerMedia = { audio: false, video: false };

Regions

At room creation, Sendexa selects a media region (or you pin one when the API supports region). All participants for that room use the same SFU cluster so mesh complexity stays low.

Region IDRecommended forNotes
af-westGhana, Nigeria, West AfricaDefault for most Sendexa accounts
af-southSouth Africa & neighboursLower RTT for ZA endpoints
eu-westEurope & UK diasporaGood cross-Atlantic compromise
us-eastAmericasUse when majority of users are in US

Choose the region closest to the majority of participants — not necessarily the host — for best average experience.

Launch checklist
  • ✓ Rooms and tokens created only from backend services
  • ✓ Join tokens short-lived; identity maps to your user IDs
  • ✓ Webhook endpoint registered for room and recording events
  • ✓ HTTPS app origin; permission UX for camera/mic denial
  • ✓ Graceful end via POST /v1/video/rooms/:roomId/end
  • ✓ Client disconnect on page unload / SPA route change