Skip to navigation

Zoom Meeting Bots

Send API-controlled bots into Zoom meetings to record, transcribe, and interact

View as Markdown

Connect your Zoom app once, then send a bot into any supported Zoom meeting with a single create_bot call.

To connect multiple Zoom apps and users and use mapped PMI or scheduled meetings, see Zoom OAuth Meeting Bots.

curl -X POST "https://api.meetstream.ai/api/v1/bots/create_bot" \
-H "Authorization: Token <YOUR_API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"meeting_link": "https://zoom.us/j/123456789?pwd=AbCdEf123",
"bot_name": "Notetaker",
"video_required": false
}'

Zoom at a glance

TopicHow it works on Zoom
Join technologyZoom Meeting SDK, running as your Zoom Marketplace app
One-time setupSave default app credentials in Dashboard > Integrations > Zoom, or register and connect Zoom apps and users
Supported linkshttps://<any>.zoom.us/j/<meeting-id> with the passcode in ?pwd=
AdmissionOne timer (waiting_room_timeout, 60 to 1200 s, default 600) covers the waiting room and a host who has not started the meeting
RecordingGuest joins ask the host for recording permission; mapped OAuth meetings usually start recording without that prompt
Signed-in joinsOptional ZAK or OBF token, fetched from an HTTPS URL you host
Per-participant mediaAudio for up to 16 participants, webcam video for up to 16 participants at 180p, screen shares as separate files
Live transcriptionDeepgram, AssemblyAI, Sarvam and MeetStream streaming providers, with the speaker’s name on each utterance
Meeting scopeZoom meetings joined through /j/ invite links. The bot stays in the main meeting room

How a Zoom bot joins

MeetStream bots join Zoom through the Zoom Meeting SDK. The SDK always runs as a Zoom Marketplace app, so every Zoom bot needs a Meeting SDK app’s credentials. MeetStream uses the Client ID and Client Secret you save in the dashboard to authorize the SDK, then joins the meeting with the display name from bot_name.

1

Create a Meeting SDK app in the Zoom App Marketplace

Create a General app, turn on Meeting SDK under Features > Embed, and copy the app’s Client ID and Client Secret. The full walkthrough is in Zoom Marketplace App Setup.

2

Save the credentials in MeetStream

Open Integrations in the sidebar, select the Zoom tab, click Configure credentials (or Update credentials), paste the Client ID and Client Secret, and save. The card shows Credentials active when they are stored.

MeetStream dashboard Integrations page with the Zoom tab selected, showing the Update credentials button and masked Client ID and Client Secret fields marked Credentials active
Dashboard > Integrations > Zoom: (1) Integrations, (2) Zoom tab, (3) Configure or Update credentials, (4) the stored Client ID and Client Secret
3

Create a bot

Call POST /api/v1/bots/create_bot with a Zoom /j/ link. MeetStream detects Zoom from the link, so there is no platform field.

If no Zoom credentials are saved, create_bot returns HTTP 400 with Zoom bots require Zoom credentials in user profile (or, in a later check, Zoom bots require a connected Zoom app or Zoom credentials in the user profile). Save the credentials and retry.

Which meetings your app can join

Zoom decides which meetings a Meeting SDK app may join. Since March 2, 2026, Zoom requires Meeting SDK apps that join meetings outside the app’s own Zoom account to be reviewed by Zoom and to join with a ZAK or an OBF token (Zoom: Meeting SDK authorization, Zoom: OBF FAQ).

Meeting is hosted byApp not yet reviewed by Zoom (development)App reviewed by Zoom
The Zoom account that owns your Marketplace appGuest, ZAK or OBF joinGuest, ZAK or OBF join
Any other Zoom accountCannot joinZAK or OBF join required

When Zoom refuses a join to a meeting outside your app’s account, the bot usually ends with Stopped and the message Unable to join external meeting. To get past it, submit your app for review (Zoom App Production Submission) and use a ZAK or OBF join.

Guest, signed-in and on-behalf-of joins

zoom object on create_botJoin modeUse it when
Omitted or {}Guest: the bot joins with its bot_name and no Zoom user identityMeetings hosted by your app’s own Zoom account
{"zak_url": "https://..."}Signed in as the Zoom user whose ZAK your server returnsMeetings that require sign-in, or external meetings where you control a Zoom user
{"obf_url": "https://..."}On behalf of a Zoom user who authorized your app and is already in the meetingExternal meetings attended by one of your users

Send only one of the two URLs. MeetStream calls your URL at join time and uses the token it returns. If the call fails, the bot does not fall back to a guest join; it ends with Error: Failed to join meeting: ZAK token is required but could not be fetched (or the OBF equivalent). MeetStream’s hosted token endpoints are retired, and the old use_zoom_obf and zoom_oauth_connection_user_id fields are rejected with HTTP 400. The full contract (request headers, GET and POST behavior, response formats, test commands) is in Zoom Authenticated Bots (ZAK and OBF).

The API accepts http or https links on zoom.us, any subdomain of zoom.us (such as us05web.zoom.us or yourcompany.zoom.us) and zoomgov.com. The bot then reads the meeting ID from a /j/<meeting-id> path and the passcode from the pwd query parameter.

Link shapeExampleResult
Join link with passcodehttps://us05web.zoom.us/j/81234567890?pwd=AbCdEf123Joins
Join link without passcodehttps://zoom.us/j/81234567890Joins meetings that have no passcode
Personal meeting room linkhttps://zoom.us/my/yournameAccepted by the API, then ends with Error: Failed to join meeting: Invalid meeting_link format. Use the /j/ invite link of the meeting
Webinar linkhttps://zoom.us/w/81234567890Same result. Use the /j/ invite link of the meeting
Share and web-client linkshttps://zoom.us/s/81234567890, https://zoom.us/wc/join/81234567890Same result. Use the /j/ invite link of the meeting
App deep linkzoommtg://zoom.us/join?confno=81234567890Rejected with HTTP 400 (meeting_link must use http:// or https://.)
Zoom home, sign-in or marketing pageshttps://zoom.us/signinRejected with HTTP 400 (meeting_link looks like the Zoom site root or a marketing page, not a meeting URL: ...)
ZoomGovhttps://yourorg.zoomgov.com/j/81234567890Accepted by the API. Contact support before you send bots to ZoomGov meetings

If you only have a personal room or vanity link, open it in Zoom and copy the meeting’s invite link instead. It contains /j/<meeting-id> and, when the meeting has a passcode, ?pwd=.

There is no separate passcode field. Keep the pwd value in the link exactly as Zoom generated it. If the passcode is missing or wrong, Zoom usually leaves the bot connecting, and after 60 seconds the bot ends with Error: Failed to connect to meeting. Some passcode errors surface as Stopped with Meeting failed instead.

Joining, the waiting room and admission

Yes Token returned Call fails No Zoom refuses Zoom accepts the request Admitted, or no waiting room Not admitted and host never started,waiting_room_timeout reached Yes No Host allows Host denies No answer in time create_bot acceptedbot.joining zak_url or obf_url set? Bot calls your token URL Bot asks Zoom to join Error (bot.failed)ZAK or OBF token is required but could not be fetched Stopped, Denied or Errorsee Outcomes InWaitingRoombot.in_waiting_roomadmission timer starts InMeetingbot.inmeeting NotAllowed (bot.notallowed)Failed: Not admitted to meeting Can the bot already record? Recordingbot.recording Bot requests recording permissionrecording_permission_denied_timeout starts RecordingPermissionAllowedbot.recording_permission_allowed RecordingPermissionDeniedbot.recording_permission_denied Leaving, then Stoppedbot.leaving, bot.stopped

What to expect at each step:

  1. bot.joining is sent by the API when the bot is accepted. For scheduled bots, statuses start at the scheduled time.
  2. bot.in_waiting_room (InWaitingRoom, message Bot is waiting to be admitted) fires as soon as Zoom accepts the join request, even if the meeting has no waiting room. On Zoom it means “waiting to be let in”. If there is no waiting room, bot.inmeeting follows within seconds.
  3. The admission timer starts at the same moment and runs for automatic_leave.waiting_room_timeout seconds (60 to 1200, default 600). For a scheduled bot, the timer is extended by the time left until the scheduled start, so it effectively counts from join_at.
  4. One timer covers two situations: the bot sitting in the waiting room, and the bot waiting for a host who has not started the meeting yet. When the timer runs out in either case, the bot ends with NotAllowed and Failed: Not admitted to meeting (bot.notallowed, status_code: 500). The message is the same even when the real cause was that the host never started the meeting.
  5. bot.inmeeting (InMeeting, Bot successfully joined the meeting) fires once Zoom lets the bot in. The recording permission step follows.

Depending on how Zoom reports a meeting that has not started, the attempt can also end at once (without waiting) with Stopped and Meeting not yet started, or Meeting does not exist or host has not started it yet.

If Zoom shows a meeting reminder or disclaimer (for example a recording notice), the bot accepts it automatically.

Zoom settings that affect admission

The host manages these settings in the Zoom web portal.

Zoom settingWhere (Zoom web portal)Effect on the bot
Waiting RoomSettings > Meeting > Security > Waiting RoomWhen on, a host or co-host must admit the bot before waiting_room_timeout runs out. The options for who goes to the waiting room (for example “Everyone” or “Users not in your account”) decide whether the bot is held. Zoom help
Allow participants to join before hostSettings > Meeting > Schedule MeetingWhen off, the bot waits for the host to start the meeting, and that wait counts against waiting_room_timeout. Zoom help
Only authenticated users can join meetingsSettings > Meeting > SecurityParticipants without a Zoom account cannot join. Use a signed-in join with zak_url. Zoom help

If your Zoom account hosts the meetings, support can connect your Zoom app so that bots join with fewer prompts. Contact support to set this up.

Recording permission

Zoom only lets a Meeting SDK participant capture meeting audio and video with the host’s permission to record locally (Zoom’s record to computer permission). Zoom’s Meeting SDK review requirements expect participant apps to request that permission from the host. About one second after it is admitted, the bot checks whether it can record:

  • It can already record: recording starts and bot.recording fires. No permission events are sent.
  • It cannot record yet: the bot asks the host for permission once, through Zoom’s standard request, and starts a timer of automatic_leave.recording_permission_denied_timeout seconds (60 to 300, default 60, Zoom only).
Host actionStatus and messageWebhook events
Allows recordingRecordingPermissionAllowed: Recording permission granted by host, then recording startsbot.recording_permission_allowed, then bot.recording
Denies recordingRecordingPermissionDenied: Failed: Recording permission denied by host, then Stopped: Bot exited the call: Recording permission denied by hostbot.recording_permission_denied (status_code: 500), bot.leaving, bot.stopped
Does not answer within the timeoutRecordingPermissionDenied: Failed: Recording permission timeout, then Stopped: Bot exited the call: Recording permission timeoutbot.recording_permission_denied (status_code: 500), bot.leaving, bot.stopped

Things to know:

  • The bot asks once. It does not re-request after a denial or a timeout; it leaves.
  • If the host revokes recording permission later in the meeting, the bot stops recording and leaves the same way, with Failed: Recording permission denied by host.
  • The terminal event after a permission denial is a clean bot.stopped (bot_event: "bot.stopped"), not bot.denied. bot.denied is reserved for Zoom refusing the join itself.
  • If recording still cannot start after permission is granted (one retry after 2 seconds), the bot ends with Error: Failed to start recording.
  • While a Zoom bot records, its status (from get bot status and the dashboard) stays RecordingPermissionAllowed or InMeeting. Recording appears in the status timeline and as the bot.recording webhook.

To receive the permission events on a workspace endpoint, tick them under Zoom recording permission when you create or edit the endpoint in Webhooks.

Create New Endpoint dialog with the ZOOM RECORDING PERMISSION group highlighted, listing bot.recording_permission_allowed and bot.recording_permission_denied
Webhooks > Create New Endpoint: the Zoom recording permission events

Zoom settings that affect recording permission

Zoom settingWhere (Zoom web portal)Effect on the bot
Record to computer filesSettings > Recording (account admins: Account Settings > Recording & Transcript)Zoom’s computer (local) recording must be enabled for the host so participants can be given permission to record. Zoom help
Who can request host permission to record?Same page, under Record to computer filesChoose which participants may ask: Internal meeting participants, External meeting participants, or Meeting participants with specified domains. A guest bot is not signed in to the host’s Zoom account, so it is usually treated as an external participant.
Auto approve their permission requestsUnder each option aboveThe host is not prompted and recording starts without waiting. Depending on how Zoom grants it, you receive bot.recording_permission_allowed then bot.recording, or bot.recording alone.
Grant during the meetingIn the meeting: Participants > More next to the bot > Allow RecordLets a host grant permission manually. The bot only waits recording_permission_denied_timeout seconds, so grant it promptly. Zoom help

Outcomes: every way a Zoom bot ends

Every terminal status is preceded by Leaving (bot.leaving, Bot is leaving the meeting). On the wire, terminal webhooks carry event: "bot.stopped" plus a specific bot_event; status_code is 500 for NotAllowed, Denied and Error, and 200 for Stopped and Kicked. The full cross-platform list is in Bot status and error codes.

Some Zoom join results use Stopped with status_code: 200 (bot_event: "bot.stopped"): Meeting not yet started, Meeting does not exist or host has not started it yet, Unable to join external meeting and Meeting failed. Read the message field to find the cause.

Before the bot is admitted

Statusbot_eventMessage (exact)What happenedWhat to do
NotAllowedbot.notallowedFailed: Not admitted to meetingNobody admitted the bot, or the host never started the meeting, before waiting_room_timeoutAsk the host to admit the bot, raise waiting_room_timeout (max 1200), or use a signed-in join
Deniedbot.deniedFailed: Zoom account is restricted and not allowed to join this meetingZoom returned an account-restriction error for this meetingCheck the meeting’s authentication and domain restrictions; try a zak_url join as an allowed user
Stoppedbot.stoppedMeeting not yet startedZoom reported that the meeting has not startedStart the meeting, or schedule the bot closer to the start time
Stoppedbot.stoppedMeeting does not exist or host has not started it yetWrong meeting ID, a deleted meeting, or a meeting not startedCheck the /j/ meeting ID
Stoppedbot.stoppedUnable to join external meetingYour app is not allowed to join meetings outside its Zoom accountSee Which meetings your app can join
Stoppedbot.stoppedMeeting failedAny other Zoom join failure, including some passcode errorsCheck the passcode in pwd= and that the meeting is open to external participants
Errorbot.failedError: Failed to connect to meetingThe bot was still connecting after 60 seconds, most often because of a missing or wrong passcodeUse the full invite link with ?pwd=
Errorbot.failedError: Failed to join meeting: Invalid meeting_link formatThe link has no /j/<meeting-id> pathUse a /j/ link (Supported meeting links)
Errorbot.failedError: Failed to join meeting: ZAK token is required but could not be fetchedYour zak_url did not return a usable tokenZoom Authenticated Bots: troubleshooting
Errorbot.failedError: Failed to join meeting: OBF token is required but could not be fetchedYour obf_url did not return a usable tokenZoom Authenticated Bots: troubleshooting
Errorbot.failedError: Failed to join meeting: JoinMeeting failed with code <n>Zoom rejected the join requestRetry; if it repeats, contact support with the bot ID
Errorbot.failedError: Zoom authentication failed with result: <n>Zoom rejected your app’s Client ID and Client SecretRe-copy both values from your Marketplace app and check that Meeting SDK is on under Features > Embed

Other messages that start with Error: (for example SDK start-up errors) mean the bot could not start its Zoom session. Retry once, then contact support with the bot ID.

After the bot is in the meeting

Statusbot_eventMessage (exact)What happened
Stoppedbot.stoppedMeeting ended by hostThe host ended the meeting for everyone
Stoppedbot.stoppedMeeting ended - host never joinedZoom ended a join-before-host meeting because the host never arrived
Stoppedbot.stoppedMeeting ended - host started another meetingThe host started a different meeting, which ended this one
Stoppedbot.stoppedMeeting ended - free meeting time limit reachedThe host’s free Zoom plan time limit ended the meeting
Stoppedbot.stoppedMeeting disconnected before Zoom emitted an ended statusThe bot was disconnected and Zoom never sent an end reason within 15 seconds
Stoppedbot.stoppedMeeting endedThe meeting ended for another reason
Kickedbot.kickedBot was removed from the meeting by a participantA host or co-host removed the bot. The webhook carries bot_status: "Stopped"; the bot’s stored status is Kicked
Stoppedbot.stoppedBot exited the call: Recording permission denied by hostSee Recording permission
Stoppedbot.stoppedBot exited the call: Recording permission timeoutSee Recording permission
Stoppedbot.stoppedBot exited the call: Everyone left the meetingAuto-leave: everyone_left_timeout
Stoppedbot.stoppedBot exited the call: Maximum recording time reachedAuto-leave: in_call_recording_timeout
Stoppedbot.stoppedBot exited the call: Voice inactivity timeoutAuto-leave: voice_inactivity_timeout
Stoppedbot.stoppedBot exited the call: only other bots remain (bot_detection.using_participant_names)Auto-leave: bot detection
Stoppedbot.stoppedBot stopped via API requestYou called remove bot. The bot posts Good Bye! to the meeting chat before it leaves
Errorbot.failedError: Failed to start recordingRecording could not start after permission was granted

Errors when you create the bot (HTTP 400)

These come back from create_bot before any bot is started. The general error format is on the Errors page.

MessageFix
Zoom bots require Zoom credentials in user profileSave your Client ID and Client Secret in Integrations > Zoom
Zoom bots require a connected Zoom app or Zoom credentials in the user profileSame as above
meeting_link must use http:// or https://.Use the https:// invite link, not a zoommtg:// link
meeting_link looks like the Zoom site root or a marketing page, not a meeting URL: ...Use the meeting’s invite link
Pass only one of zoom.zak_url or zoom.obf_url, not bothSend one token URL
zoom.zak_url must use https (or zoom.obf_url ..., ... must include a host, ... exceeds maximum length of 4096)Use a public https:// URL up to 4096 characters
zoom.zak_url and zoom.obf_url are only supported for Zoom meetingsRemove the zoom object for Google Meet and Teams bots
zoom.use_zoom_obf is no longer supported. ... (or zoom.zoom_oauth_connection_user_id ...)Host your own token URL (Zoom Authenticated Bots)
waiting_room_timeout for Zoom must not exceed 1200 seconds (got <n>)Use 60 to 1200
recording_permission_denied_timeout must not exceed 300 seconds (got <n>)Use 60 to 300

Automatic leave on Zoom

Set these under automatic_leave on create_bot. Zoom applies some of them differently from Google Meet and Teams. This table shows the behavior on Zoom. The field reference is in Automatic Leave Configuration.

FieldRange and defaultBehavior on Zoom
waiting_room_timeout60 to 1200 s, default 600Enforced. Covers the waiting room and a host who has not started the meeting. Ends with NotAllowed
recording_permission_denied_timeout60 to 300 s, default 60Enforced. Zoom only. Ends with RecordingPermissionDenied, then Stopped
everyone_left_timeout60 to 1800 s, default 600Enforced once someone leaves. The countdown starts when a participant leaves and two or fewer people (including the bot) remain; when it ends, the bot leaves if it is alone, otherwise the countdown resets. For a meeting that nobody else joins, see no_one_joined_timeout
no_one_joined_timeout60 to 1800 s, default 600On Zoom, end a session that nobody else joins with in_call_recording_timeout (when the bot records video or separate streams) or with a remove_bot call from your backend
in_call_recording_timeout600 to 18000 s, default 14400Applies when the bot records video (video_required: true) or per-participant audio (audio_separate_streams: true), measured from when recording starts. For an audio-only Zoom bot, set the maximum length with a remove_bot call
voice_inactivity_timeout60 to 1800 s (600 if omitted)The countdown starts after the first speech, and meeting audio resets it. Use it together with another leave rule
bot_detection.using_participant_namesactivate_after 60 to 1800 s (default 300), timeout 5 to 300 s (default 5)Enforced. After activate_after seconds in the meeting, if every other participant’s name contains one of your matches strings (case-insensitive), the bot leaves after timeout seconds

For a fixed maximum length on Zoom, set video_required: true or audio_separate_streams: true so that in_call_recording_timeout applies, or call remove bot from your backend when your own logic decides the meeting is over.

Media, chat and interaction

CapabilityZoom support
Mixed audio recordingYes. 32 kHz mono. The bot’s own speech (for voice agents) is mixed back into the recording after the call
Per-participant audio (audio_separate_streams)Yes. A separate file for each participant (up to 16 streams), from Zoom’s per-participant audio, with an audio manifest
Per-participant video (video_separate_streams)Yes, even without a composite recording. Webcams at 180p and 15 fps for up to 16 participants, delivered as H.264 MP4 with a video manifest. When a camera is off, the file shows a black tile with the participant’s name
Screen shareCaptured as its own file for each share session when per-participant video is on, at the resolution Zoom provides
Grid and speaker view recordings (video_layout)Yes. Built after the call from the per-participant streams (grid_view is the default when video is on; speaker_view also turns on per-participant audio)
Live audio over WebSocket (live_audio_required)Yes. Frames are per speaker, 32 kHz, speech only, and carry the speaker’s ID and name
Read chatYes. Messages to everyone and direct messages to the bot, delivered as participant_events.chat_message with to set to everyone, the recipient’s name, or direct
Send chat (send_message, bot_message)Yes, to everyone. bot_message is posted once when the bot joins. Over the two-way socket (socket_connection_url), a sendmsg command with a uid sends a private message to that participant
Send images and GIFs (send_image)Yes, shown through the bot’s camera (animated GIFs loop). With display_duration, the camera returns to bot_image_url afterwards
Bot avatar (bot_image_url)Yes, shown through the bot’s camera. HTTPS PNG, JPG, GIF or WebP. The camera is only on when an image is set
Pause and resume recordingYes. While paused, audio is recorded as silence and video as black frames
Participant eventsJoin, leave and chat events. is_host is true only for the meeting host (not co-hosts). Zoom reuses a participant’s ID if they rejoin the same meeting. These events go to workspace webhook endpoints and recording_config.realtime_endpoints, not to callback_url
Speaker timelineYes, from Zoom’s active speaker signals and per-participant audio
Voice agents and two-way audio (socket_connection_url, MIA)Yes. See Meeting control and command patterns

Transcription on Zoom

Post-call transcription works on Zoom with every post-call provider (deepgram, assemblyai, jigsawstack, sarvam, meetstream). See Post-call transcription.

For live transcription, set live_transcription_required.webhook_url and one streaming provider under recording_config.transcript.provider:

Provider keyLive on Zoom
deepgram_streamingYes
assemblyai_streamingYes
sarvam_streamingYes
meetstream_streamingYes

Use one of these four providers for live transcripts on Zoom. The bot feeds the provider each participant’s speech separately, so live transcripts carry the Zoom participant’s name and ID for every utterance. Only one streaming provider runs per bot. Provider details are in Transcription providers.

Meeting scope on Zoom

  • The bot joins regular Zoom meetings from /j/ invite links and stays in the main meeting room.
  • For transcripts, use a live or post-call provider (Transcription on Zoom).
  • Contact support before you send bots to ZoomGov meetings.

Watch your Zoom bots

In the dashboard, All Bots lists every bot with its platform and status. Filter by Zoom and a status to find failed joins, and open a bot to see its status timeline and messages.

All Bots page with the All platforms filter, the All statuses filter and the Events button highlighted
All Bots: (1) filter by platform, (2) filter by status, (3) open the bot event reference

To follow a bot live from your terminal, use meetstream listen. The Debugging guide walks through reading statuses and webhooks.

Zoom FAQ

No Zoom Meeting SDK credentials are saved for your account. Create a General app with Meeting SDK enabled (Zoom Marketplace App Setup), then save its Client ID and Client Secret in Integrations > Zoom.

Zoom does not let your app join meetings hosted outside its own Zoom account. Until Zoom reviews your app, it can only join your own account’s meetings. After review, external meetings need a ZAK or OBF join. See Which meetings your app can join.

Only a host or co-host can admit the bot, and they must do it before waiting_room_timeout (default 600 s, max 1200). The same timer also runs out when the host never starts the meeting, with the same Failed: Not admitted to meeting message. Check that the host is present, raise the timeout, or change who goes to the waiting room in the host’s Zoom settings.

On Zoom, bot.in_waiting_room fires as soon as Zoom accepts the bot’s join request. It means “waiting to be let in”. Without a waiting room, bot.inmeeting follows within seconds.

Recording needs the host’s permission on Zoom. If the host denies it, or does not answer within recording_permission_denied_timeout (default 60 s, max 300), the bot leaves with bot.recording_permission_denied followed by bot.stopped. Make sure the host’s account has Record to computer files on, and consider Auto approve their permission requests for external participants.

On Zoom, Recording is written to the status timeline and sent as bot.recording, but the bot’s current status stays RecordingPermissionAllowed (or InMeeting when no permission request was needed). Treat either as “in the meeting and recording” once you have received bot.recording.

The bot was still connecting after 60 seconds. This is usually a missing or wrong passcode. Pass the full invite link, including ?pwd=, as meeting_link.

MeetStream called your obf_url and did not get a usable token: a non-2xx response, a timeout (15 s), a short or empty body, or JSON without a token, zak or obf field. Also check that you did not add meeting_number to the URL yourself. See Zoom Authenticated Bots.

On Zoom, end a session that nobody else joins with in_call_recording_timeout (when the bot records video or separate streams) or with a remove bot call from your backend. everyone_left_timeout starts after a participant leaves.

For live transcripts, use deepgram_streaming, assemblyai_streaming, sarvam_streaming or meetstream_streaming. For post-call transcripts, use any post-call provider. meeting_captions is for Google Meet and Microsoft Teams.

Not as a guest. Use a signed-in join: host a zak_url that returns a ZAK for a Zoom user who is allowed into the meeting. See Zoom Authenticated Bots.