Generated banner for Zoom Rtms
Generated logo for Zoom Rtms

Zoom Rtms

OpenAIOfficialCreated by ZoomDistributed by OpenAI

  • Skill
  • Tool integration
  • Automation and integrations
  • MIT
  • No issues found

From the author

Use when using RTMS.
— the description by Zoom

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

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/openai/zoom-rtms/download
  2. Unzip 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

  1. Confirm the source surface: Meetings RTMS, Contact Center voice media, or another documented RTMS stream.

  2. Decide whether RTMS is sufficient or whether a Meeting SDK bot is required for participant identity, meeting controls, or UI-visible behavior.

  3. Implement the WebSocket lifecycle first: event subscription, connection validation, media start, heartbeat, reconnect, and shutdown.

  4. Process media types intentionally: audio, video, screen share, chat, live transcript, and metadata have different payload and timing constraints.

  5. Design downstream pipelines for buffering, transcription, AI analysis, recording, or tool invocation.

  6. Debug by isolating app setup, webhook/event delivery, stream authorization, network connectivity, and media payload decoding.

References

Files

concepts/connection-architecture.md

RTMS Connection Architecture

RTMS uses a two-phase WebSocket design to separate control plane from data plane.

Overview

Multi-Product Note: The two-phase WebSocket design described here is identical for all RTMS products (meetings, webinars, and Video SDK sessions). The only difference is the initial webhook event name and payload ID field. Once connected, the signaling and media protocols are the same.

┌─────────────────────────────────────────────────────────────┐
│                    Zoom Meeting                              │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    Zoom RTMS Backend                         │
│  ┌─────────────────────┐    ┌─────────────────────────────┐ │
│  │  Signaling Server   │    │     Media Server            │ │
│  │  (Control Plane)    │    │     (Data Plane)            │ │
│  └──────────┬──────────┘    └──────────────┬──────────────┘ │
└─────────────┼───────────────────────────────┼───────────────┘
              │                               │
              ▼                               ▼
┌─────────────────────────────────────────────────────────────┐
│                      Your Server                             │
│  ┌─────────────────────┐    ┌─────────────────────────────┐ │
│  │  Signaling Socket   │    │     Media Socket            │ │
│  │  - Handshake        │    │     - Audio data            │ │
│  │  - Start/Stop       │    │     - Video data            │ │
│  │  - Heartbeat        │    │     - Transcript            │ │
│  └─────────────────────┘    └─────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

Two-Phase Design

Phase 1: Signaling WebSocket (Control Plane)

Purpose: Authentication, session control, heartbeats

ResponsibilityDescription
AuthenticationValidate signature, establish session
Media Server DiscoveryReturns media server URL in handshake response
Stream ControlStart/stop streaming commands
HeartbeatKeep connection alive (msg_type 12/13)
Event NotificationsParticipant join/leave, sharing start/stop

URL Source: From server_urls in webhook payload

Message Flow:

Client                          Signaling Server
  │                                    │
  │──── Handshake Request (1) ────────>│
  │<─── Handshake Response (2) ────────│  <- Contains media_server.server_urls
  │                                    │
  │──── Client Ready (7) ─────────────>│  <- After media handshake complete
  │                                    │
  │<─── Keep Alive Request (12) ───────│
  │──── Keep Alive Response (13) ─────>│
  │                                    │
Phase 2: Media WebSocket (Data Plane)

Purpose: Actual audio, video, transcript, chat, screen share data

ResponsibilityDescription
Media ConfigurationSet audio/video parameters (codec, resolution, fps)
Media StreamingReceive binary media data
HeartbeatKeep connection alive (msg_type 12/13)

URL Source: From signaling handshake response (media_server.server_urls.all)

Message Flow:

Client                          Media Server
  │                                    │
  │──── Media Handshake Request (3) ──>│  <- With media_params
  │<─── Media Handshake Response (4) ──│
  │                                    │
  │<─── Audio Data (14) ───────────────│
  │<─── Video Data (15) ───────────────│
  │<─── Screen Share Data (16) ────────│
  │<─── Transcript Data (17) ──────────│
  │<─── Chat Data (18) ────────────────│
  │                                    │
  │<─── Keep Alive Request (12) ───────│
  │──── Keep Alive Response (13) ─────>│
  │                                    │

Why Two Connections?

BenefitExplanation
Separation of ConcernsControl logic doesn't interfere with media streaming
Independent ScalingSignaling and media servers scale differently
Fault IsolationMedia reconnection doesn't require re-auth
Split Mode SupportEach media type can have its own connection

Connection Modes

Each media type gets its own dedicated WebSocket connection:

Signaling WS ─────┬───> Audio WS
                  ├───> Video WS
                  ├───> Transcript WS
                  └───> Screen Share WS

Advantages:

  • Independent reconnection per media type

  • Better reliability

  • Fault isolation

Unified Mode

One media WebSocket for all media types:

Signaling WS ─────> Media WS (all types)

When to use:

  • Real-time audio+video muxing where sync matters

  • Simpler implementation for small projects

Signature Generation

Both signaling and media handshakes require HMAC-SHA256 signature:

// For meetings and webinars: use meeting_uuid
const message = `${clientId},${meetingUuid},${streamId}`;
// For Video SDK: use session_id
const message = `${clientId},${sessionId},${streamId}`;

// Generic approach: use whichever ID is present
const idValue = payload.meeting_uuid || payload.session_id;
const message = `${clientId},${idValue},${streamId}`;
const signature = crypto.createHmac('sha256', clientSecret)
  .update(message)
  .digest('hex');

Important: Webinars use meeting_uuid (not webinar_uuid). Video SDK uses session_id.

Components:

  • clientId: OAuth Client ID (General App) or SDK Key (Video SDK App)

  • meetingUuid / sessionId: From webhook payload (meeting_uuid for meetings/webinars, session_id for Video SDK)

  • streamId: From webhook payload (rtms_stream_id)

  • clientSecret: OAuth Client Secret (General App) or SDK Secret (Video SDK App)

Heartbeat Protocol

CRITICAL: Both connections require heartbeat responses.

When you receive msg_type: 12 (Keep Alive Request):

// Immediately respond with msg_type: 13
ws.send(JSON.stringify({
  msg_type: 13,
  timestamp: receivedMessage.timestamp
}));

Timeout:

  • Signaling: ~60 seconds without heartbeat response

  • Media: ~65 seconds without heartbeat response

Failure to respond = connection closed!

Reconnection

RTMS does NOT auto-reconnect. You must implement:

ws.on('close', (code, reason) => {
  console.log(`Connection closed: ${code} ${reason}`);

  // Implement exponential backoff
  setTimeout(() => {
    reconnect();
  }, retryDelay);

  retryDelay = Math.min(retryDelay * 2, 30000);
});

Timeouts:

ConnectionReconnection Window
Signaling60 seconds
Media65 seconds

Server URL Geo-Routing

Server URLs contain region codes:

CodeLocation
sjcSan Jose, California
iadWashington DC
sinSingapore
fraFrankfurt, Germany
sydSydney, Australia

Example: wss://rtms-sjc1.zoom.us/...

For production, route to workers in the same region as the Zoom server for lower latency.

Next Steps

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