Skip to content
Server

Seats and speakers

The seat, speak request and invitation endpoints for audio rooms.

These routes apply to audio_room rooms. Paths start with https://stream.zavryn.online/api/v1/rooms/:room_name, and they take the user_token as a bearer.

Actions marked "host or admin" return 403 Only host or admin can perform this action otherwise. An admin can't act on a host.

Seat modes

  • free: anyone can take an open, unlocked seat.
  • request: everyone else must request to speak and be approved, or be invited.

Read and configure

GET /seats returns the seats and pending requests:

{
  "seats": [
    { "index": 0, "identity": "host-1", "name": "Host", "locked": false, "reserved_for": "host-1", "attributes": { "avatar": "" } },
    { "index": 1, "identity": null, "name": null, "locked": false, "reserved_for": null, "attributes": null }
  ],
  "seat_count": 9,
  "seat_mode": "request",
  "mode_id": null,
  "requests": [{ "id": 12, "identity": "user-7", "created_at": "2026-06-08T10:00:00.000Z" }]
}

POST /seats/setup reconfigures them, for a host or admin:

{ "identity": "host-1", "seat_count": 6, "seat_mode": "request", "mode_id": "game-mode" }

Changing mode_id rebuilds the seats, and non-host speakers lose their seats.

Seat actions

In the actions marked "actor", identity is the person doing it.

EndpointBodyWhoCommon errors
POST /seats/:index/takeidentityAnyone, subject to the mode409 Already seated, 409 Seat is not available, 403 Seat is reserved, 403 Speaker request not approved. Request to speak first.
POST /seats/leaveidentityThe occupant404 Not seated
POST /seats/moveidentity, target_seatThe occupant409 Seat is locked, 409 Target seat was taken, 403 Seat is reserved
POST /seats/:index/kickidentity (actor)Host or admin404 Seat is empty, 403 Cannot kick from a reserved seat
POST /seats/:index/lockidentity (actor)Host or admin403 Cannot lock a reserved seat
POST /seats/:index/unlockidentity (actor)Host or admin404 Seat not found or not locked
POST /seats/:index/muteidentity (actor)Host or admin
POST /seats/:index/unmuteidentity (actor)Host or admin

Force-mute someone

PUT /participants/:identity/media, where the path has the target and the body has the actor:

{ "identity": "host-1", "audio": true, "video": false, "muted": true }

Speak requests

EndpointBodyWhoCommon errors
POST /speakers/requestidentityAnyone400 Room is in free mode. Take a seat directly., 409 Request already pending
DELETE /speakers/requestidentityThe requester404 No pending request found
GET /speakers/requestsAnyone
POST /speakers/requests/:id/approveidentity (actor)Host or admin404 Request not found or already resolved
POST /speakers/requests/:id/rejectidentity (actor)Host or admin

Invitations

EndpointBodyWhoCommon errors
POST /speakers/inviteidentity, target_identity, optional seat_indexHost or admin404 Target user not in room, 409 Invitation already pending
POST /speakers/invitations/:id/acceptidentityThe target409 Target seat is occupied
POST /speakers/invitations/:id/declineidentityThe target

Lock chat

POST /comments/lock
POST /comments/unlock

Send { "identity": "host-1" }, for a host or admin. Both are safe to repeat. While chat is locked, only hosts and admins can post, and gifts and likes keep working.

The kits honor the lock. If you use the media client, your app must honor it too, because the lock applies through room state rather than permissions. Read chat_locked from the room, and listen for the _chat_lock data message.

Updates in the room

Clients receive seat changes in the room metadata, under _seats, and as data messages: _seat_update, _mode_change, _custom_command, _speaker_request, _speaker_request_approved, _speaker_request_rejected, _speaker_invitation, _speaker_invitation_accepted, _speaker_invitation_declined and _chat_lock.