Zoom Authenticated Bots (ZAK and OBF)
Host one HTTPS token URL, pass it on create_bot, and your Zoom bot joins signed in (ZAK) or on behalf of one of your users (OBF).
MeetStream does not store your users’ Zoom OAuth tokens. You run Zoom OAuth on your server, keep the refresh tokens, and expose a URL that returns a fresh token. At join time, the bot calls that URL and joins with the token it gets back.
Endpoint: POST /api/v1/bots/create_bot
Auth: Authorization: Token <your MeetStream API key>
Before you start, save your Meeting SDK app’s Client ID and Client Secret in the dashboard (Zoom Marketplace App Setup). Those credentials are the app the bot runs as. The ZAK or OBF token only says which Zoom user the join is attributed to.
1. Pick a join mode
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 use a ZAK or OBF token (Zoom: Meeting SDK authorization, Zoom: OBF FAQ). Meetings hosted by your app’s own Zoom account can still use a guest join.
2. ZAK or OBF?
OBF tokens are short-lived and single-use (Zoom: Transitioning to OBF tokens). Mint one every time MeetStream calls you; never cache or reuse it.
3. How the token fetch works
4. What you host
Two jobs, both on your HTTPS server:
- OAuth, once per Zoom user. Redirect the user to Zoom’s authorize page, receive the
codeat your callback, exchange it withPOST https://zoom.us/oauth/token(grant_type=authorization_code) and store the refresh token. Never send refresh tokens to MeetStream. - The token URL, called on every join. Refresh the user’s access token when needed (
grant_type=refresh_token, and save the new refresh token if Zoom returns one), call Zoom’s user token API, and return the token.
Encode which user in the URL (a user_id query parameter, a path segment, or a signed ID) and protect it: MeetStream sends no authentication header and does not sign token requests, so put a secret in the URL (a shared auth query parameter, an HMAC signature, or a short-lived signed URL) and treat the whole URL as a credential.
Minimal token server (Python)
jsonify sets Content-Type: application/json, which MeetStream needs to read a JSON response (see Response formats).
5. create_bot examples
Signed in (ZAK)
On behalf of (OBF)
Make sure the authorizing user has joined the Zoom meeting before you create the bot (or before join_at for a scheduled bot). Do not add meeting_number to obf_url.
URL rules checked by create_bot: https only, must include a host, at most 4096 characters, and only on Zoom meetings. The bot calls the URL from the internet, so localhost and private addresses do not work. For local development, expose your server through a public HTTPS tunnel (local webhook server guide).
6. The request MeetStream sends to your URL
When: once per join attempt, right before the bot joins the meeting. For a scheduled bot, that is shortly before join_at. If a join attempt is retried, your URL can be called again for the same bot, so always mint a fresh token.
First request: GET
What the bot does with your GET response
Fallback request: POST
meeting_number in the POST body is a JSON number. Ignore any body fields you do not use. The POST must return 2xx with a usable token, or the join fails.
Response formats
If you return JSON with a text/plain content type, the bot treats the entire JSON text as the token and Zoom rejects the join. Set Content-Type: application/json whenever you return JSON.
When the fetch fails
The bot does not fall back to a guest join. It ends with status Error and one of these messages, sent as bot.failed with status_code: 500:
Error: Failed to join meeting: ZAK token is required but could not be fetchedError: Failed to join meeting: OBF token is required but could not be fetched
MeetStream fetches the token once per join attempt and does not retry the fetch on its own.
7. Test your URL without a bot
Call your own server the way MeetStream will (replace the host, secret and meeting number):
Check the Content-Type header in the output. Then create a bot with the same URL, without meeting_number on the OBF URL.
8. Troubleshooting
Errors from create_bot (HTTP 400)
Problems at join time
All Zoom statuses and messages are listed in Zoom Meeting Bots and in Bot status and error codes.
Migrating from hosted OBF
MeetStream used to mint ZAK and OBF tokens for you. That flow is retired:
create_botrejectszoom.use_zoom_obfandzoom.zoom_oauth_connection_user_idwith HTTP 400.- The hosted token endpoints
/api/v1/zoom/zak-tokenand/api/v1/zoom/obf-tokenreturn HTTP 410 Gone with a message telling you to passzoom.zak_urlorzoom.obf_urland mint the token on your server.
To migrate: register your own OAuth redirect URL in your Zoom app (Zoom Marketplace App Setup), have your users authorize your app again through your server, deploy a token URL like the example above, and send zoom.obf_url (or zoom.zak_url) on create_bot.
Related
- Zoom Meeting Bots: admission, recording permission and every Zoom outcome
- Zoom Marketplace App Setup
- Zoom App Production Submission
- Create Bot Payload Reference
- Webhooks and events
