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_botevents 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 setrecord_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.
⚠️ 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.
What you'll need
- A Zoom account with access to the Zoom App Marketplace 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
- In the Zoom App Marketplace, create a user-managed General app.
- 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
- US:
- 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.
- In the app, turn on Event Subscription.
- 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'srecording_id, sendsRECORDING_READYand moves the bot toDONE - under Recording, Recording transcript files have completed (
recording.transcript_completed): sendsRECORDING_READYagain once the transcript is ready. Zoom offers this on Business, Education and Enterprise plans.
- under RTMS, RTMS started in Meeting (
- Set the endpoint URL to this integration's webhook URL, with your workspace ID:
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
- In the Unified app, open Integrations and activate Zoom (meeting bot).
- Enter your Zoom app's Client ID and Client Secret.
- 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:
- 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.
- 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
- Create a
calendar_boton the connection with the meeting's join link (meeting_url), or with theidof acalendar_eventlisted on the same connection (event_id, the Zoom meeting ID). The bot isREADY. - Create a native webhook for
calendar_botevent/createdon the same connection. - Start the meeting and start RTMS. You should receive a
BOT_STATUS_CHANGEtoIN_CALL_RECORDING, then captions and participant events. - End the meeting. You should receive a
BOT_STATUS_CHANGEtoCALL_ENDED. - If the meeting was recorded to the cloud, you should receive
RECORDING_READYand aBOT_STATUS_CHANGEtoDONE(sub_coderecording_ready) once Zoom finishes the recording.
Limits
- Unsupported features return
501(Not supported by this integration: …):join_at(scheduled joins),record_audio,record_videoandrecord_screenshare. - Other errors on create:
400for malformed input, such as a link that isn't a Zoom meeting link or a transcription provider other thanMEETING_CAPTIONS;404when the meeting doesn't exist;422when 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_ENDEDbot is still waiting for its recording, so create the next occurrence's bot only after the previous bot reachesDONE. 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,DONEorFATAL) returns409. meeting_urlcan't change after creation: an update that changes it returns400. You can updatename,event_idandrecording_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
FATALwith sub-codertms_connection_lost. - Chat: only new messages sent to everyone; private messages aren't reported.
- Speaking: you get
PARTICIPANT_SPEECH_ONwhen the active speaker changes; there is noPARTICIPANT_SPEECH_OFF. - Deleting a bot stops the stream. You receive a
BOT_STATUS_CHANGEtoFATAL(sub-codeuser_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_idis 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 staysREADY
❌ 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_chatisn't set on the bot'srecording_config- Your app doesn't have chat access in RTMS