Zoom Rtms
OpenAIOfficialCreated by ZoomDistributed by OpenAI
- Skill
- Tool integration
- Automation and integrations
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
The zoom-rtms skill provides the necessary protocols and architectural guidance for integrating Zoom Realtime Media Streams. It covers the WebSocket-based connection lifecycle, including signaling and media handshakes, heartbeat management, and reconnection strategies. The skill supports processing various media types such as audio, video, screen sharing, transcripts, and chat, while providing reference data for message types and event enums.
What it does
- Establishes WebSocket connections for signaling and media streams.
- Handles media handshake requests for audio, video, screen share, transcript, and chat data.
- Provides reference tables for RTMS message types and event enums.
- Defines mandatory heartbeat and reconnection logic for stream stability.
- Supports configuration for transcript language identification.
- Outlines the process for extracting stream IDs and generating HMAC-SHA256 signatures.
When to use it
- When you need to ingest raw meeting or contact center media into a backend pipeline.
- When building services for transcription, AI analysis, or recording of Zoom sessions.
- When you need to subscribe to specific meeting events or participant media streams.
- When you require programmatic access to media data without a visible participant bot.
Advantages
- Provides a structured approach to managing the complex WebSocket lifecycle.
- Includes comprehensive references for message types and event handling.
- Offers clear guidance on signature generation and security requirements.
- Enables granular control over media subscription and transcript settings.
Usage examples
- “How do I initiate a connection to an RTMS stream?”
- The agent will guide you through receiving the rtms_started webhook, generating an HMAC-SHA256 signature, and performing the signaling and media handshakes.
- “What is the correct way to handle heartbeats in RTMS?”
- The agent will explain that you must respond to msg_type 12 (Keep Alive Request) with msg_type 13 (Keep Alive Response) to maintain the connection.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/openai/zoom-rtms/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip zoom-rtms.zip -d .agents/skills
Documentation by Zoom
Zoom Realtime Media Streams
Use this skill when the integration needs real-time meeting or contact-center media as a backend stream. If the workflow needs a visible participant bot, compare against build-zoom-bot and zoom-meeting-sdk-linux before choosing RTMS.
Workflow
Confirm the source surface: Meetings RTMS, Contact Center voice media, or another documented RTMS stream.
Decide whether RTMS is sufficient or whether a Meeting SDK bot is required for participant identity, meeting controls, or UI-visible behavior.
Implement the WebSocket lifecycle first: event subscription, connection validation, media start, heartbeat, reconnect, and shutdown.
Process media types intentionally: audio, video, screen share, chat, live transcript, and metadata have different payload and timing constraints.
Design downstream pipelines for buffering, transcription, AI analysis, recording, or tool invocation.
Debug by isolating app setup, webhook/event delivery, stream authorization, network connectivity, and media payload decoding.
References
Full preserved guide: references/full-guide.md
Connection architecture: concepts/connection-architecture.md
Lifecycle flow: concepts/lifecycle-flow.md
Media types: references/media-types.md
Data types: references/data-types.md
RTMS bot example: examples/rtms-bot.md
Common issues: troubleshooting/common-issues.md
Files
- ATTRIBUTION.mdAdded by AutoGineer860 B
- LICENSELicence file added by AutoGineer1.1 KiB
- RUNBOOK.md2.6 KiB
- SKILL.md1.6 KiB
- agents/openai.yaml140 B
- concepts/connection-architecture.md9.1 KiB
- concepts/lifecycle-flow.md13.4 KiB
- examples/ai-integration.md11.3 KiB
- examples/manual-websocket.md16.8 KiB
- examples/rtms-bot.md25.9 KiB
- examples/sdk-quickstart.md9.3 KiB
- references/connection.md8.0 KiB
- references/data-types.md13.7 KiB
- references/environment-variables.md1.3 KiB
- references/full-guide.md22.9 KiB
- references/media-types.md6.0 KiB
- references/quickstart.md6.6 KiB
- references/webhooks.md7.4 KiB
- troubleshooting/common-issues.md10.4 KiB
references/webhooks.md
RTMS - Webhooks
RTMS-related webhook events and configuration.
CRITICAL: Respond 200 IMMEDIATELY!
The #1 cause of random disconnects:
If your webhook handler takes too long to respond, Zoom assumes failure and retries. The retry creates a second connection, which kicks out your first connection (only 1 connection allowed per stream).
// CORRECT: Respond first, process async
app.post('/webhook', (req, res) => {
res.status(200).send(); // IMMEDIATELY!
// Then process asynchronously
handleRTMSEvent(req.body);
});
// WRONG: Processing before responding
app.post('/webhook', async (req, res) => {
await heavyProcessing(req.body); // Zoom may retry while waiting!
res.status(200).send();
});URL Validation Challenge
When configuring your webhook URL, Zoom sends a validation challenge:
app.post('/webhook', (req, res) => {
const { event, payload } = req.body;
// Handle URL validation
if (event === 'endpoint.url_validation') {
const hash = crypto
.createHmac('sha256', process.env.ZOOM_SECRET_TOKEN)
.update(payload.plainToken)
.digest('hex');
return res.json({
plainToken: payload.plainToken,
encryptedToken: hash
});
}
res.status(200).send();
// ... handle other events
});Events
meeting.rtms_started
Sent when RTMS stream is ready for a meeting.
{
"event": "meeting.rtms_started",
"payload": {
"account_id": "account_id",
"object": {
"meeting_id": "meeting_id",
"meeting_uuid": "meeting_uuid",
"host_id": "host_user_id",
"rtms_stream_id": "stream_id",
"server_urls": "wss://rtms-sjc1.zoom.us/...",
"signature": "auth_signature"
}
}
}meeting.rtms_stopped
Sent when RTMS stream ends.
{
"event": "meeting.rtms_stopped",
"payload": {
"account_id": "account_id",
"object": {
"meeting_id": "meeting_id",
"rtms_stream_id": "stream_id"
}
}
}webinar.rtms_started
Sent when RTMS stream is ready for a webinar.
{
"event": "webinar.rtms_started",
"payload": {
"account_id": "account_id",
"object": {
"meeting_id": "meeting_id",
"meeting_uuid": "meeting_uuid",
"host_id": "host_user_id",
"rtms_stream_id": "stream_id",
"server_urls": "wss://rtms-sjc1.zoom.us/...",
"signature": "auth_signature"
}
}
}Important: Webinar payloads use
meeting_uuid, NOTwebinar_uuid. The signature and connection flow are identical to meetings.
Webinar-specific considerations:
Panelists: Full audio/video streams are available for panelists.
Attendees: View-only participants; individual streams may not be available.
Practice sessions: Not documented for RTMS.
Q&A/Polls: Not exposed via RTMS.
webinar.rtms_stopped
Sent when RTMS stream ends for a webinar.
{
"event": "webinar.rtms_stopped",
"payload": {
"account_id": "account_id",
"object": {
"meeting_id": "meeting_id",
"rtms_stream_id": "stream_id"
}
}
}session.rtms_started
Sent when RTMS stream is ready for a Video SDK session.
{
"event": "session.rtms_started",
"payload": {
"account_id": "account_id",
"object": {
"session_id": "session_id",
"rtms_stream_id": "stream_id",
"server_urls": "wss://rtms-sjc1.zoom.us/...",
"signature": "auth_signature"
}
}
}Important: Video SDK payloads use
session_idinstead ofmeeting_uuid. The HMAC signature must usesession_idin place ofmeeting_uuid.
Video SDK-specific considerations:
Uses SDK Key/Secret (not OAuth Client ID/Secret) for authentication.
Requires a Video SDK App (not a General App) in Zoom Marketplace.
Once connected, the WebSocket protocol is identical to meetings.
session.rtms_stopped
Sent when RTMS stream ends for a Video SDK session.
{
"event": "session.rtms_stopped",
"payload": {
"account_id": "account_id",
"object": {
"session_id": "session_id",
"rtms_stream_id": "stream_id"
}
}
}Screen Share Events (via msg_type 5)
Subscribe to receive SHARING_START and SHARING_STOP events when participants start/stop screen sharing.
Payload Fields
| Field | Description |
|---|---|
rtms_stream_id | Unique stream identifier |
server_urls | WebSocket signaling server URL |
meeting_uuid | Meeting unique identifier (needed for signature) |
signature | Pre-computed auth signature (alternative to self-generating) |
Server URL Geo-Routing
Server URLs contain airport/region codes:
| Code | Location |
|---|---|
sjc | San Jose, California |
iad | Washington DC |
sin | Singapore |
fra | Frankfurt, Germany |
syd | Sydney, Australia |
// Extract region from server URL
const hostname = new URL(serverUrl).hostname; // rtms-sjc1.zoom.us
const region = hostname.split('-')[1].replace(/[0-9]/g, ''); // sjcTip: For production, route webhooks to workers in the same region as the Zoom server.
Subscribing to RTMS Events
In Zoom Marketplace (General App - Meetings and Webinars)
Go to your app settings
Navigate to Features → Access
Enable Event Subscription
Click Add Event Subscription
Enter your webhook endpoint URL
Search "rtms" and select:
meeting.rtms_startedmeeting.rtms_stoppedwebinar.rtms_started(if using webinars)webinar.rtms_stopped(if using webinars)
Click Done then Save
In Zoom Marketplace (Video SDK App)
Go to your Video SDK app settings
Add Event Subscription:
session.rtms_startedsession.rtms_stopped
Required Scopes
For Meetings (Features → Scopes → Add Scopes → search "rtms"):
| Scope | Purpose |
|---|---|
meeting:read:meeting_audio | Access meeting audio |
meeting:read:meeting_video | Access meeting video |
meeting:read:meeting_transcript | Access transcripts |
meeting:read:meeting_chat | Access chat messages |
For Webinars (add these in addition to meeting scopes):
| Scope | Purpose |
|---|---|
webinar:read:webinar_audio | Access webinar audio |
webinar:read:webinar_video | Access webinar video |
webinar:read:webinar_transcript | Access webinar transcripts |
webinar:read:webinar_chat | Access webinar chat messages |
For Video SDK: Uses SDK Key/Secret credentials instead of OAuth scopes.
Products Supporting RTMS
| Product | Start Event | Stop Event | Payload ID | App Type |
|---|---|---|---|---|
| Zoom Meetings | meeting.rtms_started | meeting.rtms_stopped | meeting_uuid | General App |
| Zoom Webinars | webinar.rtms_started | webinar.rtms_stopped | meeting_uuid (not webinar_uuid!) | General App |
| Zoom Video SDK | session.rtms_started | session.rtms_stopped | session_id | Video SDK App |
| Zoom Contact Center | contactcenter.rtms_* | contactcenter.rtms_* | See Zoom docs | Contact Center App |
| Zoom Phone | phone.rtms_* | phone.rtms_* | See Zoom docs | General App |
Key differences: Meetings and webinars use a General App with OAuth credentials. Video SDK uses a Video SDK App with SDK Key/Secret. Once connected, the WebSocket protocol is identical across all products.
Resources
Event reference: https://developers.zoom.us/docs/rtms/event-reference/
RTMS docs: https://developers.zoom.us/docs/rtms/
Requirements and compatibility
Written for: OpenAI Codex
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Zoom
- Publisher
- OpenAI (Official)
- Distributed by
- OpenAI
- Source
- openai/plugins · plugins/zoom/skills/rtms · commit d420d13
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from plugins/zoom/LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Zoom or OpenAI.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download zoom-rtms.zip