Server SDK (Node.js)
Manage rooms, tokens, recordings, streaming, and ingress from your backend
Overview
The BaxCloud Server SDK (@baxcloud/server-sdk) is a Node.js/TypeScript library for server-side operations. Use it to create rooms, generate access tokens, manage recordings, stream to external platforms, create ingress endpoints, and verify webhooks — all from your backend server.
Room & Token Management
Create rooms, generate tokens, manage participants
Recording & Streaming
Record rooms, stream to YouTube/Twitch, auto-stream config
Webhooks
Verify webhook signatures, parse events, Express middleware
Installation
1npm install @baxcloud/server-sdkRequirements
fetch). TypeScript 5+ recommended.Quick Start
1import { BaxCloudClient } from '@baxcloud/server-sdk';
2
3const client = new BaxCloudClient({
4 apiKey: process.env.BAXCLOUD_API_KEY!,
5 // baseUrl: 'https://api.baxcloud.io', // default
6 // timeout: 30000, // default 30s
7});
8
9// Create a room
10const room = await client.createRoom({
11 name: 'my-meeting',
12 maxParticipants: 50,
13 enableRecording: true,
14});
15
16// Generate access token for a participant
17const { token } = await client.generateToken({
18 roomName: 'my-meeting',
19 participantIdentity: 'user-123',
20 participantName: 'John Doe',
21 ttl: 3600, // 1 hour
22 grants: {
23 canPublish: true,
24 canSubscribe: true,
25 canPublishData: true,
26 },
27});
28
29// Send token to the client
30console.log('Token:', token);Room Management
1// Create a room
2const room = await client.createRoom({
3 name: 'team-standup',
4 maxParticipants: 20,
5 emptyTimeout: 300, // Close after 5 min empty
6 metadata: '{"type": "standup"}',
7 enableRecording: true,
8});
9
10// List all rooms
11const rooms = await client.listRooms();
12
13// Get room details
14const roomDetails = await client.getRoom('team-standup');
15
16// Update room metadata
17await client.updateRoomMetadata('team-standup', '{"status": "active"}');
18
19// Delete a room
20await client.deleteRoom('team-standup');Token Generation
Tokens authenticate participants when they join a room. Always generate tokens on your server — never expose your API key to the client.
1// Full-access participant (host)
2const hostToken = await client.generateToken({
3 roomName: 'my-room',
4 participantIdentity: 'host-1',
5 participantName: 'Room Host',
6 ttl: 7200,
7 grants: {
8 canPublish: true,
9 canSubscribe: true,
10 canPublishData: true,
11 canUpdateOwnMetadata: true,
12 },
13});
14
15// View-only participant (viewer)
16const viewerToken = await client.generateToken({
17 roomName: 'my-room',
18 participantIdentity: 'viewer-42',
19 participantName: 'Viewer',
20 ttl: 3600,
21 grants: {
22 canPublish: false, // Cannot send audio/video
23 canSubscribe: true, // Can receive audio/video
24 canPublishData: true, // Can send chat messages
25 },
26});Security
Participant Management
1// List participants in a room
2const participants = await client.listParticipants('my-room');
3
4for (const p of participants) {
5 console.log(`${p.name} (${p.identity}) - ${p.state}`);
6}
7
8// Remove a participant
9await client.removeParticipant('my-room', 'user-123');
10
11// Update participant metadata
12await client.updateParticipantMetadata(
13 'my-room',
14 'user-123',
15 '{"role": "moderator"}'
16);Recording
See also: Recording Guide
1// startRecord — start cloud recording
2const recording = await client.startRecord({
3 roomName: 'my-room',
4 fileType: 'MP4',
5});
6console.log('Recording ID:', recording.id);
7console.log('Egress ID:', recording.egressId);
8
9// stopRecord — stop an active recording
10await client.stopRecord(recording.egressId);
11
12// listRecordings — list all recordings
13const { items } = await client.listRecordings({
14 status: 'completed',
15 page: 1,
16 limit: 20,
17});
18
19// listActiveRecordings — list currently running recordings
20const active = await client.listActiveRecordings('my-room');
21
22// getRecording — get recording details
23const rec = await client.getRecording(recording.id);
24
25// getRecordingDownloadUrl — get temporary download URL
26const { downloadUrl, expiresIn } = await client.getRecordingDownloadUrl(
27 recording.id,
28 3600 // expires in 1 hour
29);Stream Out (Egress)
See also: Stream Out Guide
1// Stream to YouTube + Twitch simultaneously
2const stream = await client.startStream({
3 roomName: 'my-room',
4 mode: 'both', // Record + Stream
5 layout: 'speaker',
6 quality: '1080p',
7 file: { fileType: 'MP4' },
8 stream: {
9 urls: [
10 'rtmp://a.rtmp.youtube.com/live2/YOUTUBE_KEY',
11 'rtmp://live.twitch.tv/app/TWITCH_KEY',
12 ],
13 },
14});
15
16// Stop streaming
17await client.stopStream(stream.id);
18
19// Configure auto-streaming
20await client.updateAutoStreamConfig({
21 enabled: true,
22 mode: 'record',
23 quality: '720p',
24 minParticipants: 2,
25});Stream In (Ingress)
See also: Stream In Guide
1// Create RTMP ingress (for OBS Studio)
2const ingress = await client.startStreamIn({
3 inputType: 'RTMP_INPUT',
4 roomName: 'my-room',
5 participantIdentity: 'obs-streamer',
6 participantName: 'OBS Studio',
7 enableTranscoding: true,
8});
9
10console.log('RTMPS URL:', ingress.rtmpsUrl);
11console.log('Stream Key:', ingress.streamKey);
12
13// Create WHIP ingress (for browser/OBS 30+)
14const whip = await client.startStreamIn({
15 inputType: 'WHIP_INPUT',
16 roomName: 'my-room',
17 participantIdentity: 'whip-streamer',
18 bypassTranscoding: true,
19});
20
21console.log('WHIP URL:', whip.whipUrl);
22console.log('Bearer Token:', whip.token);
23
24// List ingress endpoints
25const { items } = await client.listStreamIn({ roomName: 'my-room' });
26
27// Delete ingress
28await client.stopStreamIn(ingress.id);Webhook Verification
Verify webhook signatures to ensure events are genuinely from BaxCloud:
1import express from 'express';
2import { webhookMiddleware } from '@baxcloud/server-sdk';
3
4const app = express();
5
6// Use the middleware — it verifies the signature and parses the event
7app.post('/webhooks/baxcloud',
8 express.raw({ type: 'application/json' }),
9 webhookMiddleware({
10 webhookSecret: process.env.BAXCLOUD_WEBHOOK_SECRET!,
11 }),
12 (req, res) => {
13 const event = req.body; // Parsed & verified event
14
15 switch (event.event) {
16 case 'room.started':
17 console.log('Room started:', event.data.roomName);
18 break;
19 case 'participant.joined':
20 console.log('Participant joined:', event.data.identity);
21 break;
22 case 'egress.ended':
23 console.log('Recording completed:', event.data.egressId);
24 break;
25 }
26
27 res.json({ received: true });
28 }
29);Complete Method Reference
| Category | Method | Description |
|---|---|---|
| Rooms | ||
| Rooms | createRoom(options) | Create a new room |
| Rooms | getRoom(name) | Get room details |
| Rooms | listRooms() | List all rooms |
| Rooms | deleteRoom(name) | Delete a room |
| Rooms | updateRoomMetadata(name, metadata) | Update room metadata |
| Tokens | ||
| Tokens | generateToken(options) | Generate participant access token |
| Participants | ||
| Participants | listParticipants(roomName) | List participants in a room |
| Participants | removeParticipant(room, identity) | Kick a participant |
| Participants | updateParticipantMetadata(...) | Update participant metadata |
| Recording | ||
| Recording | startRecord(roomName, options?) | Start cloud recording for a room |
| Recording | stopRecord(egressId) | Stop an active recording |
| Recording | listRecordings(options?) | List all recordings with filters |
| Recording | listActiveRecordings(roomName?) | List currently running recordings |
| Recording | getRecording(recordingId) | Get recording details |
| Recording | getRecordingDownloadUrl(id, expiresIn?) | Get temporary download URL |
| Stream Out (Egress) | ||
| Egress | startStream(options) | Start stream, recording, or both (mode: record|stream|both) |
| Egress | stopStream(egressId) | Stop active stream/recording |
| Egress | getStreamStatus(egressId) | Get stream details and status |
| Egress | listStreams(options?) | List streams with filters (roomName, status, page) |
| Egress | deleteStream(egressId) | Delete a stream record |
| Egress | getAutoStreamConfig() | Get auto-stream configuration |
| Egress | updateAutoStreamConfig(options) | Configure auto-streaming rules |
| Ingress (Stream In) | ||
| Ingress | startStreamIn(options) | Create RTMP/WHIP ingress endpoint |
| Ingress | listStreamIn(options?) | List ingress endpoints |
| Ingress | getStreamIn(id) | Get ingress details |
| Ingress | stopStreamIn(id) | Delete an ingress endpoint |
Webhook Events Reference
All webhook events sent by BaxCloud
| Event | Category | Description |
|---|---|---|
| Rooms | ||
| room.started | Rooms | Room created and active |
| room.finished | Rooms | Room closed (empty timeout or deleted) |
| Participants | ||
| participant.joined | Participants | Participant joined a room |
| participant.left | Participants | Participant left a room |
| Recording | ||
| recording.started | Record | Cloud recording started for a room |
| recording.completed | Record | Recording finished, file available for download |
| recording.failed | Record | Recording failed (error details in payload) |
| Stream Out (Egress) | ||
| stream.started | Stream Out | RTMP stream to YouTube/Twitch/etc. started |
| stream.updated | Stream Out | Stream status changed (destination connected, etc.) |
| stream.completed | Stream Out | Stream to external platform completed |
| stream.failed | Stream Out | Stream to external platform failed |
| Stream In (Ingress) | ||
| live.started | Stream In | Ingress stream from OBS/encoder started |
| live.updated | Stream In | Ingress state changed (BUFFERING → ACTIVE) |
| live.ended | Stream In | Ingress stream ended (encoder disconnected) |
| live.failed | Stream In | Ingress stream failed |
| Tracks | ||
| track.published | Tracks | Participant published audio/video track |
| track.unpublished | Tracks | Participant unpublished a track |