---
title: "How to Set Up a Zoom Meeting Bot with Unified"
img: https://s3.us-east-2.amazonaws.com/unified-article-images/how_to_set_up_a_zoom_meeting_bot_with_unified-icon.png
date: 2026-11-07T20:02:00.000Z
updated: "2026-11-09T14:48:29.410Z"
tag: Guides
integrations: zoommeetingbot
description: "Zoom (meeting bot) (`zoommeetingbot`) is the integration that gives you a `calendarbot` and live `calendarbotevent`s for Zoom meetings. It is separate from the..."
url: "https://docs.unified.to/guides/how_to_set_up_a_zoom_meeting_bot_with_unified"
---

# How to Set Up a Zoom Meeting Bot with Unified
------
_November 7, 2026_

## Overview


**Zoom (meeting bot)** (`zoommeetingbot`) is the integration that gives you a `calendar_bot` and live `calendar_botevent`s for Zoom meetings. It is separate from the **Zoom** integration: your existing Zoom connections don't change, and your end users connect Zoom (meeting bot) on its own.


A Zoom meeting bot follows the meeting through Zoom's **Realtime Media Streams (RTMS)**. It does not join as a participant. When Zoom starts the meeting's realtime stream, Unified opens it and sends you, while the meeting runs:

- Zoom's own meeting captions (`TRANSCRIPT_RECEIVED`)
- in-meeting chat to everyone (`CHAT_MESSAGE_RECEIVED`, when you set `record_chat`)
- participant joined, left, speaking, webcam and screen-share events
- status changes (`BOT_STATUS_CHANGE`)

After the meeting, when Zoom finishes the cloud recording, the bot gets a `recording_id`, sends `RECORDING_READY`, and moves to `DONE`.


It does not record audio, video or screen shares itself.


The same connection also gives you Zoom's own objects: `calendar_calendar`, `calendar_event`, `calendar_recording`, `calendar_webinar`, `calendar_link`, `calendar_location`, `calendar_room` and `uc_contact`. They work as on the Zoom integration, and their scopes are requested only when you select their permissions.


For how to create bots and receive events, see [How to Build a Meeting Bot with Unified](https://docs.unified.to/guides/how_to_build_a_meeting_bot_with_unified_zoom_microsoft_teams_webex_google_meet).


---


## ⚠️ Important: you need your own Zoom app


Meeting bots need **your own Zoom Marketplace app**, with RTMS scopes, and that app's **Secret Token** saved on the integration in Unified. Unified has no shared Zoom credentials for meeting bots, and creating a bot returns `400` while the Secret Token is missing.


RTMS is available to all developers. It needs a user-managed **General app** and an active **Zoom Developer Pack** with credits, which RTMS usage draws on. Zoom's default limit is 2,000 concurrent streams (higher on request; the free trial allows 5). See Zoom's [RTMS overview](https://developers.zoom.us/docs/rtms/).


---


## What you'll need

- A Zoom account with access to the [Zoom App Marketplace](https://marketplace.zoom.us/) developer tools
- An active Zoom Developer Pack with credits for RTMS
- For recordings: cloud recording on the meeting host's Zoom account (Pro or higher)
- Your Unified workspace ID (shown in the Unified app under **Settings**)
- Your Unified region: US (`api.unified.to`), EU (`api-eu.unified.to`) or AU (`api-au.unified.to`)

---


## Step 1: Create the Zoom app

1. In the Zoom App Marketplace, create a user-managed **General app**.
2. Add the Unified redirect URL for your region:
    - US: `https://api.unified.to/oauth/code`
    - EU: `https://api-eu.unified.to/oauth/code`
    - AU: `https://api-au.unified.to/oauth/code`
3. Copy the app's **Client ID** and **Client Secret**. Unified uses them for OAuth and to sign the RTMS connection.

---


## Step 2: Add scopes


Add these scopes to the app:


| Scope                                       | Unified permission        | Why                                                                                                  |
| ------------------------------------------- | ------------------------- | ---------------------------------------------------------------------------------------------------- |
| `user:read:user`                            | `calendar_bot_write`      | Find the connected user's Zoom account when a bot is created                                         |
| `meeting:read:meeting`                      | `calendar_bot_write`      | Read the meeting when a bot is created                                                               |
| `meeting:read:meeting_transcript`           | `calendar_botevent_read`  | Receive Zoom's meeting captions over RTMS.                                                           |
| `cloud_recording:read:list_user_recordings` | `calendar_recording_read` | List recordings                                                                                      |
| `cloud_recording:read:list_recording_files` | `calendar_recording_read` | Read the recording a bot points to, by id                                                            |
| `meeting:read:list_meetings`                | `calendar_event_read`     | List meetings (`calendar_event`). Creating a bot from an `event_id` needs only `calendar_bot_write`. |
Among the RTMS scopes, select only `meeting:read:meeting_transcript`: Zoom's guidance is that an app that only needs meeting transcripts should select only that scope, and RTMS scopes can't be marked optional.


If you select other permissions (calendars, webinars, rooms, contacts), add the same scopes the Zoom integration uses for them. The sign-in scopes the Zoom integration requests (`user_profile`, `user_info:read`, `user:read`) also apply.


**Chat:** Zoom documents no separate scope name for RTMS chat, so Unified doesn't request one. `CHAT_MESSAGE_RECEIVED` events arrive only if your app has chat access in RTMS. Zoom only sends the media and session events your app's scopes allow.


---


## Step 3: Subscribe to events


Zoom has no API to register this subscription, so you set it up in the app.

1. In the app, turn on **Event Subscription**.
2. Add these events:
    - under **RTMS**, **RTMS started in Meeting** (`meeting.rtms_started`): starts the live stream
    - under **Recording**, **All Recordings have completed** (`recording.completed`): sets the bot's `recording_id`, sends `RECORDING_READY` and moves the bot to `DONE`
    - under **Recording**, **Recording transcript files have completed** (`recording.transcript_completed`): sends `RECORDING_READY` again once the transcript is ready. Zoom offers this on Business, Education and Enterprise plans.
3. Set the endpoint URL to this integration's webhook URL, with your workspace ID:

```plain text
https://api.unified.to/webhook/workspace/zoommeetingbot?workspace_id=<YOUR_WORKSPACE_ID>
```


Use `api-eu.unified.to` or `api-au.unified.to` if your workspace is in the EU or AU region.


This is the **Zoom (meeting bot)** URL. Don't use the URL of the Zoom integration.


Zoom validates the endpoint when you save it (`endpoint.url_validation`). Unified answers that challenge with your Secret Token, so **complete Step 4 before you validate the endpoint**. Zoom re-validates the endpoint every 72 hours, so keep the Secret Token in Unified current.


---


## Step 4: Enter your credentials in Unified

1. In the Unified app, open **Integrations** and activate **Zoom (meeting bot)**.
2. Enter your Zoom app's **Client ID** and **Client Secret**.
3. Enter the app's **Secret Token** in the **Secret Token** field. Unified asks for it when you activate the integration, and the instructions under the field show where to find it: in the Zoom App Marketplace, open **Manage**, select your app, go to **Features** and open the **Access** tab. The Secret Token is not the app's OAuth Client Secret.

The Secret Token verifies every delivery from Zoom: Zoom signs each one with an `x-zm-signature` header, `v0=` followed by the hex HMAC-SHA256 of `v0:{timestamp}:{body}`, and Unified also rejects deliveries older than 5 minutes. That replay window is Unified's own check; Zoom documents none. Unified never sends the Secret Token to Zoom. If you rotate the Secret Token in Zoom, update it in Unified; the change applies within about a minute, including to existing connections.


Without the Secret Token, Unified can't validate the endpoint and refuses every RTMS start.


---


## Step 5: Make sure RTMS starts in meetings


The bot waits in `READY` until Zoom starts the meeting's realtime stream. That happens when your app is started in the meeting, or when the host has chosen it to start automatically:

1. **Account level:** an account admin allows **Account Settings → Zoom Apps → Share realtime meeting content with apps**. Admins can also add your app under **Apps that access content in meetings → + Add app**.
2. **User level:** the host opens **Settings → Zoom Apps** in the Zoom web portal, goes to **Auto-start apps that access shared realtime meeting content**, selects **+ Choose an app to auto-start**, picks your app and saves.

If neither happens, the bot stays `READY` and no live events are sent.


---


## How end users connect


End users authorize **Zoom (meeting bot)** through Unified's authorization flow (embedded authorization or the authorization link), the same way they connect any other integration. They grant the scopes above. Connecting Zoom (meeting bot) doesn't change their Zoom connection, and the Zoom connection can't run meeting bots.


A bot can only follow a meeting the connected user's Zoom account can read.


---


## Test the setup

1. Create a `calendar_bot` on the connection with the meeting's join link (`meeting_url`), or with the `id` of a `calendar_event` listed on the same connection (`event_id`, the Zoom meeting ID). The bot is `READY`.
2. Create a native webhook for `calendar_botevent` / `created` on the same connection.
3. Start the meeting and start RTMS. You should receive a `BOT_STATUS_CHANGE` to `IN_CALL_RECORDING`, then captions and participant events.
4. End the meeting. You should receive a `BOT_STATUS_CHANGE` to `CALL_ENDED`.
5. If the meeting was recorded to the cloud, you should receive `RECORDING_READY` and a `BOT_STATUS_CHANGE` to `DONE` (`sub_code` `recording_ready`) once Zoom finishes the recording.

---


## Limits

- **Unsupported features return** **`501`** (`Not supported by this integration: …`): `join_at` (scheduled joins), `record_audio`, `record_video` and `record_screenshare`.
- **Other errors on create:** `400` for malformed input, such as a link that isn't a Zoom meeting link or a transcription provider other than `MEETING_CAPTIONS`; `404` when the meeting doesn't exist; `422` when the connection's Zoom account can't be resolved.
- **Captions only.** Live transcription is Zoom's meeting captions (`MEETING_CAPTIONS`).
- **Recordings need cloud recording** on the host's account. A meeting without one stays `CALL_ENDED`.
- **Reading the recording:** get it with `GET /calendar/{connection_id}/recording/{recording_id}` on the same connection.
- **Recurring meetings:** every occurrence has the same meeting ID, and a recording goes to the oldest bot that isn't finished. A `CALL_ENDED` bot is still waiting for its recording, so create the next occurrence's bot only after the previous bot reaches `DONE`. If the previous meeting has no cloud recording, delete its bot first.
- **One active bot per meeting link** per connection: creating another while an earlier bot for exactly the same link is still active (not `CALL_ENDED`, `DONE` or `FATAL`) returns `409`.
- **`meeting_url`** **can't change** after creation: an update that changes it returns `400`. You can update `name`, `event_id` and `recording_config`; a running stream keeps the media it opened with.
- **Reconnects.** If the stream drops, Unified reconnects inside Zoom's reconnect windows: about 60 seconds for the signaling connection and about 30 seconds for media. If reconnecting fails, the bot moves to `FATAL` with sub-code `rtms_connection_lost`.
- **Chat:** only new messages sent to everyone; private messages aren't reported.
- **Speaking:** you get `PARTICIPANT_SPEECH_ON` when the active speaker changes; there is no `PARTICIPANT_SPEECH_OFF`.
- **Deleting a bot** stops the stream. You receive a `BOT_STATUS_CHANGE` to `FATAL` (sub-code `user_cancelled`), then the bot is deleted.

---


## Troubleshooting


### ❌ Creating a bot returns 400 about the Secret Token


The Secret Token is missing from the Zoom (meeting bot) integration in Unified. Add it (Step 4).


### ❌ Zoom can't validate the endpoint URL

- The Secret Token in Unified doesn't match the app's Secret Token, or is missing (it is not the Client Secret)
- The URL uses the Zoom integration's path instead of `zoommeetingbot`
- `workspace_id` is missing or wrong, or the host is for another region

### ❌ The bot stays READY

- RTMS didn't start in the meeting (Step 5)
- The host hasn't chosen your app to auto-start, or the account admin hasn't allowed sharing realtime meeting content with apps (Step 5)
- Your Zoom app doesn't have the RTMS scope, or your Zoom Developer Pack has no credits left
- The **RTMS started in Meeting** event subscription isn't saved, or points at another URL
- The Secret Token in Unified doesn't match the app's: Unified rejects Zoom's RTMS start (`401`) and the bot stays `READY`

### ❌ The bot moves to FATAL with session_failed


The RTMS session failed to start or stalled. Check that your app has RTMS access and the scopes in Step 2, and that the Client ID and Client Secret in Unified are correct: Unified signs the RTMS connection with them. The Secret Token isn't involved.


### ❌ The bot stays CALL_ENDED

- The meeting wasn't recorded to the cloud, or the host's account has no cloud recording
- The **All Recordings have completed** event isn't in the app's event subscription

### ❌ No chat events

- `record_chat` isn't set on the bot's `recording_config`
- Your app doesn't have chat access in RTMS