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 or Crestron 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.
If you are using an AI coding assistant, copy the text below into it and add a sentence describing what you want to build. AI assistants accessing this page receive a separate, token-optimized version of our full developer documentation, specifically tailored by our engineers for AI coding assistants.
Before writing any code, read this page:
https://www.veeting.com/en/developer-documentation/room-system-control
It documents the Veeting Rooms room system control API. Keep these
six rules in mind:
1. Ask me for my Veeting domain and my credentials before you write
any code, unless I have already given them to you. Do not guess
either one.
2. A call succeeded only if the HTTP status is 200 AND the body has
responseCode 0. Check both. A 402 is a refusal, not a server
fault, and retrying it will not help.
3. Use the 24 character meeting "id" in the URL, never the dashed
meeting token from the join link.
4. Commands only work while the meeting is running. There is no
command that starts one.
5. presentation.nextSlide and presentation.previousSlide need a
presentation that somebody has already opened in the meeting.
6. Command names and tool ids are identifiers. Never translate them
and never invent one. Use only the values listed on this page.
What I want to build: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.
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 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.
| 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):
{
"command": "tool.activate",
"parameters": {
"toolId": "vr-whiteboard"
}
}Omit parameters for commands that require none. All four routes return the state object described below.
| 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. |
| 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. |
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.
toolId accepts these values and nothing else. They are identifiers, not labels, and they are the same in every interface language.
Custom tools are vr-custom-tool-0 through vr-custom-tool-5. See Meeting room widgets 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.
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.
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. |
Put the whiteboard on every screen:
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:
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:
curl "https://<DOMAIN-NAME>/api/v6/meeting-room/<MEETING-ID>/room-system/moderator/state" \
-H "X-MODERATOR-TOKEN: <MODERATOR-TOKEN>"A successful response:
{
"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 }
]
}
}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.
With 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.
id.responseCode. Check both.presentation.nextSlide before anyone has opened a document./moderator/ in the path, where it is ignored.Contact our team to discuss the details.