Room management endpoints are under /api/room/. All endpoints require authentication.

Overview

EndpointMethodDescription
/api/room/createPOSTCreate a new room
/api/room/joinPOSTJoin a room and get a LiveKit token
/api/room/listGETList available rooms
/api/room/:roomId/kick/:identityPOSTKick a participant (admin)
/api/room/:roomId/mute/:identityPOSTMute a participant (admin)
/api/room/:roomId/video/:identity/offPOSTDisable participant video (admin)

Endpoints

Create Room

Create a new meeting room. The authenticated user becomes the room admin.

POST /api/room/create

Headers: Authorization: Bearer <accessToken>

Request Body:

{
  "name": "team-standup",
  "isPublic": true,
  "mode": "standard",
  "settings": {
    "allowChat": true,
    "allowVideo": true,
    "allowAudio": true,
    "requireApproval": false,
    "e2ee": false
  }
}

Note: The name field is optional. If omitted or empty, the server will auto-generate a random URL-safe name in the format xxx-xxxx-xxx (e.g. bkf-qmzl-rja).

Room Name Rules:

Room names appear in the URL as https://bedrud.xyz/m/NAME, so they must be URL-safe:

RuleDescription
Allowed charactersLowercase letters (a-z), digits (0-9), and hyphens (-)
Minimum length3 characters
Maximum length63 characters
No special characters#, @, _, ., /, \, <, >, &, %, +, =, ;, :, ', ", ?, !, spaces, etc. are not allowed
No leading/trailing hyphens-room and room- are invalid
No consecutive hyphensroom--name is invalid
Lowercase onlyUppercase letters are rejected; input is auto-lowercased
UniqueEach room name must be unique

Response (200):

{
  "id": "uuid",
  "name": "team-standup",
  "createdBy": "user-uuid",
  "isActive": true,
  "isPublic": true,
  "maxParticipants": 0,
  "settings": {
    "allowChat": true,
    "allowVideo": true,
    "allowAudio": true,
    "requireApproval": false,
    "e2ee": false
  },
  "livekitHost": "wss://lk.bedrud.xyz",
  "mode": "standard"
}

Fields

FieldTypeRequiredDescription
namestringNoURL-safe room name (auto-generated if omitted)
isPublicbooleanNoWhether the room appears in public listings
modestringNoRoom mode (e.g. "standard")
maxParticipantsnumberNoMaximum number of participants
settings.allowChatbooleanNoWhether text chat is enabled
settings.allowVideobooleanNoWhether video is enabled
settings.allowAudiobooleanNoWhether audio is enabled
settings.requireApprovalbooleanNoWhether participants need admin approval
settings.e2eebooleanNoWhether end-to-end encryption is enabled

Join Room

Join an existing room and receive a LiveKit token for media connection.

POST /api/room/join

Headers: Authorization: Bearer <accessToken>

Request Body:

{
  "roomName": "team-standup"
}

Response (200):

{
  "id": "uuid",
  "name": "team-standup",
  "token": "eyJ...",
  "createdBy": "user-uuid",
  "adminId": "user-uuid",
  "isActive": true,
  "isPublic": true,
  "maxParticipants": 20,
  "expiresAt": "2026-02-16T12:00:00Z",
  "settings": { ... },
  "livekitHost": "wss://lk.bedrud.xyz",
  "mode": "standard"
}

The token is a signed LiveKit access token. Use it to connect to the LiveKit server via WebSocket:

import { Room } from 'livekit-client';
 
const room = new Room();
await room.connect(livekitUrl, token);

List Rooms

Get a list of rooms the user has created.

GET /api/room/list

Headers: Authorization: Bearer <accessToken>

Response (200):

[
  {
    "id": "uuid",
    "name": "team-standup",
    "createdBy": "user-uuid",
    "isActive": true,
    "maxParticipants": 20,
    "expiresAt": "2026-02-16T12:00:00Z",
    "settings": { ... },
    "mode": "standard",
    "relationship": "creator"
  }
]

Kick Participant

Remove a participant from the room. Only the room admin can do this.

POST /api/room/:roomId/kick/:identity

Headers: Authorization: Bearer <accessToken>

Response (200):

{
  "status": "success"
}

Mute Participant

Mute a participant’s microphone. Only the room admin can do this.

POST /api/room/:roomId/mute/:identity

Headers: Authorization: Bearer <accessToken>

Response (200):

{
  "status": "success"
}

Disable Participant Video

Turn off a participant’s camera. Only the room admin can do this.

POST /api/room/:roomId/video/:identity/off

Headers: Authorization: Bearer <accessToken>

Response (200):

{
  "status": "success"
}

Admin Controls

Room admin actions (kick, mute, video off) are only available to the user who created the room (adminId). Attempting these actions as a non-admin returns a 403 error.

Permissions Matrix

ActionRoom AdminSuper AdminRegular UserGuest
Create roomYesYesYesNo
Join roomYesYesYesYes
List roomsYesYesYesYes
KickYesYesNoNo
MuteYesYesNoNo
Video offYesYesNoNo

Error Responses

All errors follow a consistent format:

{
  "error": "human-readable error message"
}

Create Room Errors

StatusError MessageDescription
400"Invalid request body"Malformed JSON
400"room name must contain only lowercase letters, numbers, and hyphens"Name contains special characters (#, @, _, etc.)
400"room name must be at least 3 characters"Name too short
400"room name must be at most 63 characters"Name too long
409"a room with this name already exists"Duplicate name
500"Failed to create media room"LiveKit server error
500"Failed to create room"Database error

General Errors

StatusMeaning
400Bad request (missing/invalid data)
401Not authenticated
403Not authorized (non-admin trying admin action)
404Room not found
409Conflict (duplicate resource)
500Internal server error

See also