Skip to content
Esc
↑↓navigate↵open⌘Jpreview
On this page

Configuration

Every option, the environment variable behind it, and what happens when one is missing.

createZoomAdapter() reads everything from the environment, so most apps call it with no arguments at all:

const adapter = createZoomAdapter();

Anything you pass explicitly wins over the environment:

createZoomAdapter({
  clientId: "your-client-id",
  clientSecret: "your-client-secret",
  accountId: "your-account-id",
  robotJid: "bot-jid@xmpp.zoom.us",
  webhookSecretToken: "your-secret-token",
});

Options

Option Environment variable Required Notes
clientId ZOOM_CLIENT_ID Yes From the Server-to-Server OAuth app
clientSecret ZOOM_CLIENT_SECRET Yes From the same app
accountId ZOOM_ACCOUNT_ID Yes Sent with message calls, not with the token request
robotJid ZOOM_ROBOT_JID Yes The Bot JID from Team Chat Subscription
webhookSecretToken ZOOM_WEBHOOK_SECRET_TOKEN Yes Signs webhooks and the setup challenge
userName ZOOM_BOT_USERNAME No Defaults to zoom-bot
markdownSupport ZOOM_MARKDOWN_SUPPORT No Defaults to true. Sends is_markdown_support: true and a Zoom Markdown body; false falls back to structured segments
logger — No Defaults to a console logger at info, tagged zoom

A missing credential throws a ValidationError the moment the adapter is constructed, naming the variable to set. That is a setup problem surfacing early, not a runtime bug — the app will not start until it is fixed.

Marketplace setup shows where each value lives in the Zoom dashboard.

Formatting mode

markdownSupport defaults to true, which sends is_markdown_support: true with a Zoom Markdown body. That is the only mode that renders links, strikethrough, block quotes, and images. In this mode Zoom ignores the structured style field, so all emphasis has to live in the text.

Set it to false to send structured plain-text segments instead. That mode bolds a paragraph only when the whole paragraph is bold, and flattens inline bold and italic; links, strikethrough, quotes, and images keep their text but lose their formatting. Formatting has the token-by-token comparison.

createZoomAdapter({ markdownSupport: false });

Logging

Pass your own logger to route adapter output into whatever you already use:

createZoomAdapter({ logger: myLogger.child("zoom") });

Debug level is where the useful detail goes — Zoom’s error response bodies, dropped events, and the body hex written when a signature comparison fails.

Authentication

The adapter fetches a Server-to-Server OAuth token with the client_credentials grant and keeps it in memory, refreshing a minute before it expires. A failed fetch throws an AuthenticationError carrying the HTTP status.

The cache belongs to the adapter instance, so build one adapter and keep it — constructing a new one per request means a new token fetch every time.

Was this page helpful?