# Room system control

Source: https://www.veeting.com/en/developer-documentation/room-system-control

## Overview

The room system control lets a device in the physical meeting room drive a running meeting. The control system can be a wall panel, a [Q-SYS](https://www.qsys.com/) or [Crestron](https://www.crestron.com/) processor, or any other device that can make an HTTPS request. With HTTPS requests, the control system controls what is shown on the screens in the room, and how and when the meeting ends. These are the same actions a moderator can perform manually in the browser application. With the controls below, you operate a room from a panel instead of from a browser.

**Base URL:** `https://<DOMAIN-NAME>/api/v6`

`<DOMAIN-NAME>` is your own web meeting domain. Use the domain your instance runs on.

**Content type:** `application/json` on every POST.

The room system API consists of a command endpoint and a state endpoint. You send a command, and every response carries the state of the meeting after the command. The state endpoint lets you fetch the current state at any time, for example to light the buttons on the panel.

You cannot start a meeting with the room system commands. For that, use the standard [REST APIs](/en/developer-documentation/api-usage).

## Enabling the feature

The room system control is off by default. A white-label administrator can switch it on under `Enable room system features` in the system settings. While the setting is off, the endpoints below return 402.

## Authentication

There are three ways to authenticate, and they differ in which meetings they reach.

| Method                 | Header              | Reaches                                                        |
| ---------------------- | ------------------- | -------------------------------------------------------------- |
| Account-level API key  | `X-API-KEY`         | every running meeting of the account the key belongs to        |
| Instance-level API key | `X-API-KEY`         | every running meeting of the white-label instance              |
| Moderator token        | `X-MODERATOR-TOKEN` | one specific running meeting, on the `/moderator/` routes only |

**An API key is the normal choice for a room system.** You create an account-level key in `Account Settings`. It is restricted to meeting endpoints, which makes it safe to install in a room. An instance-level key reaches every account and must never be given to a customer. See [API usage](/en/developer-documentation/api-usage) for how keys are issued and how they act on behalf of a user.

**A moderator token** is created fresh for each meeting and is valid only for that meeting. With a moderator token, the room system must be used via the `/moderator/` variants of the two routes. Send it as a header rather than in the URL, so it stays out of proxy and browser logs.

## Endpoints

| Method | Path                                                        | Purpose                                 |
| ------ | ----------------------------------------------------------- | --------------------------------------- |
| POST   | `/meeting-room/<MEETING-ID>/room-system/commands`           | run one command                         |
| GET    | `/meeting-room/<MEETING-ID>/room-system/state`              | read the meeting state                  |
| POST   | `/meeting-room/<MEETING-ID>/room-system/moderator/commands` | run one command, with a moderator token |
| GET    | `/meeting-room/<MEETING-ID>/room-system/moderator/state`    | read the state, with a moderator token  |

`<MEETING-ID>` is the 24-character `id` of the meeting, the value the meeting API returns when you create a meeting, for example _6a9e7e89813a920f5679188f_. It is **not** the dashed `meetingId` from the meeting link.

The request body of a command is the same in both variants (API key and moderator token):

```json
{
  "command": "tool.activate",
  "parameters": {
    "toolId": "vr-whiteboard"
  }
}
```

Omit `parameters` for commands that require none. All four routes return the state object described below.

## Commands

| Command                      | Required        | Optional     | What it does                                                                                                                                              |
| ---------------------------- | --------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tool.activate`              | `toolId`        |              | Puts a tool on every participant's screen. This is what the `take` button does in the meeting room: it moves everybody, whether or not "Follow me" is on. |
| `presentation.goToSlide`     | `page`          | `documentId` | Turns the open presentation to an absolute page number, counted from 1.                                                                                   |
| `presentation.nextSlide`     |                 | `documentId` | Turns to the page after the current one.                                                                                                                  |
| `presentation.previousSlide` |                 | `documentId` | Turns to the page before the current one. Stops at page 1.                                                                                                |
| `screen.assignTool`          | `toolId`        | `tvChannel`  | Assigns a tool to a TV channel. Leave `tvChannel` out to clear the assignment.                                                                            |
| `screen.pinParticipant`      | `participantId` | `tvChannel`  | Pins a participant to a TV channel. Leave `tvChannel` out to unpin them.                                                                                  |
| `presentationMode.enable`    |                 |              | Turns presentation mode on.                                                                                                                               |
| `presentationMode.disable`   |                 |              | Turns presentation mode off.                                                                                                                              |
| `waitingRoom.lock`           |                 |              | Sends new arrivals to the waiting room.                                                                                                                   |
| `waitingRoom.unlock`         |                 |              | Lets new arrivals in again.                                                                                                                               |
| `chat.clear`                 |                 |              | Clears the group chat for everyone, including in the meeting summary.                                                                                     |
| `screensharing.forceStop`    |                 |              | Stops the screen share that is running.                                                                                                                   |
| `meeting.close`              |                 |              | Ends the meeting for everyone.                                                                                                                            |

### Parameters

| Parameter       | Type    | Notes                                                                                                                           |
| --------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `toolId`        | string  | One of the tool identifiers below. Any other value is refused.                                                                  |
| `page`          | integer | 1 or greater.                                                                                                                   |
| `documentId`    | string  | The presentation you believe is open. If another one is open, the command is refused rather than applied to the wrong document. |
| `tvChannel`     | integer | 0 or greater. Leave it out to clear an assignment.                                                                              |
| `participantId` | string  | The `participantId` of a participant, from the state object.                                                                    |

### Notes that will save you time

**Your panel does not have to count pages.** The platform resolves `presentation.nextSlide` and `presentation.previousSlide` against the page the meeting is currently on, so your control system does not have to count pages itself. Read `presentation.currentPage` from the state if you want to display it.

**A presentation has to be open first.** Somebody in the meeting has to open a presentation before you can control it. Without such a document, these commands return 402.

## Tool identifiers

`toolId` accepts these values and nothing else. They are identifiers, not labels, and they are the same in every interface language.

- vr-agenda
- vr-assistant
- vr-chat
- vr-dialin-numbers
- vr-documents
- vr-lobby-management
- vr-minutes
- vr-notes
- vr-participants
- vr-polls
- vr-screensharing
- vr-settings
- vr-tv-channel-manager
- vr-video
- vr-webinar-configuration
- vr-webinar-questions
- vr-whiteboard

Custom tools are `vr-custom-tool-0` through `vr-custom-tool-5`. See [Meeting room widgets](/en/developer-documentation/custom-tools) for how they are configured.

Which tools a participant can see is a separate question, decided by the meeting permissions of the account. Activating a tool a participant is not allowed to use does not make it appear for them.

## The state object

Returned by the state endpoints and by every command.

| Field                    | Type    | Description                                                                           |
| ------------------------ | ------- | ------------------------------------------------------------------------------------- |
| `activeToolId`           | string  | The tool currently on screen, or absent if nobody has chosen one.                     |
| `presentation`           | object  | `documentId` and `currentPage` of the open presentation, or `null` when none is open. |
| `presentationModeActive` | boolean | Whether presentation mode is on.                                                      |
| `waitingRoomActive`      | boolean | Whether new arrivals go to the waiting room.                                          |
| `followMeActive`         | boolean | Whether a participant is leading the room with "Follow me".                           |
| `recordingState`         | string  | `stopped`, `requested`, or `started`.                                                 |
| `participants`           | array   | Everyone in the meeting, except participants who joined invisibly.                    |

Each participant carries `participantId`, `name`, `isModerator`, and `handRaised`, plus `tvChannel` when the participant is assigned to a TV channel.

## Status codes and errors

Every response uses the same envelope as the REST API: `{ "responseCode": 0, "responseMessage": "", "data": { ... } }`.

| HTTP Status | `responseCode` | Meaning                                                                                                                                                                                 |
| ----------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 200         | 0              | The command ran. `data` holds the state.                                                                                                                                                |
| 401         | -99            | You are not authorized, for example because credentials are missing or invalid.                                                                                                         |
| 402         | -33            | The room system feature is not enabled; the meeting is not running or is not yours; a required parameter is missing; no presentation is open; or the participant is not in the meeting. |
| 422         | -44            | An unknown command, an unknown `toolId`, or a page below 1.                                                                                                                             |

## Examples

Put the whiteboard on every screen:

```bash
curl -X POST "https://<DOMAIN-NAME>/api/v6/meeting-room/<MEETING-ID>/room-system/commands" \
  -H "X-API-KEY: <API-KEY>" \
  -H "Content-Type: application/json" \
  -d '{"command":"tool.activate","parameters":{"toolId":"vr-whiteboard"}}'
```

Next slide:

```bash
curl -X POST "https://<DOMAIN-NAME>/api/v6/meeting-room/<MEETING-ID>/room-system/commands" \
  -H "X-API-KEY: <API-KEY>" \
  -H "Content-Type: application/json" \
  -d '{"command":"presentation.nextSlide"}'
```

Read the state, with a moderator token instead of a key:

```bash
curl "https://<DOMAIN-NAME>/api/v6/meeting-room/<MEETING-ID>/room-system/moderator/state" \
  -H "X-MODERATOR-TOKEN: <MODERATOR-TOKEN>"
```

A successful response:

```json
{
  "responseCode": 0,
  "responseMessage": "",
  "data": {
    "activeToolId": "vr-documents",
    "presentation": { "documentId": "6710a2b4c81e4a6c8b0d2f4a", "currentPage": 7 },
    "presentationModeActive": true,
    "waitingRoomActive": false,
    "followMeActive": false,
    "recordingState": "stopped",
    "participants": [
      { "participantId": "a1b2c3", "name": "Anna Meier", "isModerator": true, "handRaised": false, "tvChannel": 1 }
    ]
  }
}
```

### Wiring it to a panel

A control system usually needs two things: a button that sends a command, and a light that shows what the room is doing.

For the button, send the command and check that the HTTP status is 200 **and** that `responseCode` is 0. For the light, poll the state endpoint on a timer. Because every command also returns the state, you can render the state from the API response as well.

Keep the API key in the control system's configuration rather than in the button's script, so that replacing a key does not mean editing every button.

## Other useful ways to control a room

With [query parameters](/en/developer-documentation/query-parameters) you can, for example, decide whether a given browser receives audio at all. That matters most for sessions running in TV mode.

When several screens run from the same machine in kiosk mode, make sure there is no echo in the room. That is why it makes sense to receive audio in only one browser instance.

## Common mistakes

- Using the dashed meeting token from the join link instead of the 24-character meeting `id`.
- Checking only the HTTP status, or only `responseCode`. Check both.
- Sending a command to a meeting that has not started yet. Nothing is queued.
- Calling `presentation.nextSlide` before anyone has opened a document.
- Sending the moderator token to the routes without `/moderator/` in the path, where it is ignored.
- Inventing a tool ID or translating one. The identifiers are English in every language.
- Leaving the feature switched off on the instance and reading the resulting 402 as a broken key.

---

## The rest of this documentation

- [Custom tools](https://www.veeting.com/en/developer-documentation/custom-tools)
- [External meeting authorization service](https://www.veeting.com/en/developer-documentation/external-meeting-authorization-service)
- [iFrame and Web Components](https://www.veeting.com/en/developer-documentation/iframe-and-web-components)
- [JavaScript APIs](https://www.veeting.com/en/developer-documentation/javascript-apis)
- [Query parameters](https://www.veeting.com/en/developer-documentation/query-parameters)
- [Veeting Blocks - Components](https://www.veeting.com/en/veeting-blocks/components)
- [Veeting Blocks - Introduction](https://www.veeting.com/en/veeting-blocks/introduction)
- [Veeting Blocks - JavaScript and Typescript APIs](https://www.veeting.com/en/veeting-blocks/apis)
- [Veeting Rooms REST APIs](https://www.veeting.com/en/developer-documentation/api-usage)
- [Video display calculator](https://www.veeting.com/en/developer-documentation/video-display-calculator)
- [Web hooks](https://www.veeting.com/en/developer-documentation/web-hooks)

All of it in one file: https://www.veeting.com/llms-full.txt
