Bodega

Skills › Productividad

setup-zoom-websockets

Reference skill for Zoom WebSockets. Use after routing to a low-latency event workflow when persistent connections, faster event delivery, or security constraints make WebSockets preferable to webhooks.

Descargar .zipVer en GitHub
Departamento
Productividad
Fuente
Oficial · anthropics/knowledge-work-plugins › zoom-plugin
Autor
Anthropic
Licencia
Apache-2.0
Idioma
Inglés
Riesgo
Medio

Señales de riesgo

Cómo instalarla en Claude

  1. Descargue el .zip sin descomprimirlo.
  2. En Claude active Configuración › Capacidades › Crear y editar archivos.
  3. Vaya a Personalizar › Skills › Crear skill › Subir una skill y elija el archivo.

Instrucciones completas (SKILL.md)

/setup-zoom-websockets

Background reference for persistent Zoom event streams. Prefer workflow routing first, then use this file when WebSockets are plausibly better than webhooks.

WebSockets vs Webhooks

| Aspect | WebSockets | Webhooks | |--------|------------|----------| | Connection | Persistent, bidirectional | One-time HTTP POST | | Latency | Lower (no HTTP overhead) | Higher (new connection per event) | | Security | Direct connection, no exposed endpoint | Requires endpoint validation, IP whitelisting | | Model | Pull (you connect to Zoom) | Push (Zoom connects to you) | | State | Stateful (maintains connection) | Stateless (each event independent) | | Setup | More complex (access token, connection) | Simpler (just endpoint URL) |

Choose WebSockets when:

Choose Webhooks when:

Prerequisites

> Need help with S2S OAuth? See the [zoom-oauth](../oauth/SKILL.md) skill for complete authentication flows.

> Start troubleshooting fast: Use the [5-Minute Runbook](RUNBOOK.md) before deep debugging.

Quick Start

1. Create Server-to-Server OAuth App

2. Enable WebSocket Subscription

3. Connect via WebSocket

const WebSocket = require('ws');
const axios = require('axios');

// Step 1: Get access token
async function getAccessToken() {
  const credentials = Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64');
  
  const response = await axios.post(
    'https://zoom.us/oauth/token',
    new URLSearchParams({
      grant_type: 'account_credentials',
      account_id: ACCOUNT_ID
    }),
    {
      headers: {
        'Authorization': `Basic ${credentials}`,
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    }
  );
  
  return response.data.access_token;
}

// Step 2: Connect to WebSocket
async function connectWebSocket() {
  const accessToken = await getAccessToken();
  
  // WebSocket URL from your subscription settings
  const wsUrl = `wss://ws.zoom.us/ws?subscriptionId=${SUBSCRIPTION_ID}&access_token=${accessToken}`;
  
  const ws = new WebSocket(wsUrl);
  
  ws.on('open', () => {
    console.log('WebSocket connection established');
  });
  
  ws.on('message', (data) => {
    const event = JSON.parse(data);
    console.log('Event received:', event.event);
    
    // Handle different event types
    switch (event.event) {
      case 'meeting.started':
        console.log(`Meeting started: ${event.payload.object.topic}`);
        break;
      case 'meeting.ended':
        console.log(`Meeting ended: ${event.payload.object.uuid}`);
        break;
      case 'meeting.participant_joined':
        console.log(`Participant joined: ${event.payload.object.participant.user_name}`);
        break;
    }
  });
  
  ws.on('close', (code, reason) => {
    console.log(`Connection closed: ${code} - ${reason}`);
    // Implement reconnection logic
  });
  
  ws.on('error', (error) => {
    console.error('WebSocket error:', error);
  });
  
  return ws;
}

connectWebSocket();

Event Format

Events received via WebSocket have the same format as webhook events:

{
  "event": "meeting.started",
  "event_ts": 1706123456789,
  "payload": {
    "account_id": "abcD3ojkdbjfg",
    "object": {
      "id": 1234567890,
      "uuid": "abcdefgh-1234-5678-abcd-1234567890ab",
      "host_id": "xyz789",
      "topic": "Team Standup",
      "type": 2,
      "start_time": "2024-01-25T10:00:00Z",
      "timezone": "America/Los_Angeles"
    }
  }
}

Common Events

| Event | Description | |-------|-------------| | meeting.created | Meeting scheduled | | meeting.updated | Meeting settings changed | | meeting.deleted | Meeting deleted | | meeting.started | Meeting begins | | meeting.ended | Meeting ends | | meeting.participant_joined | Participant joins meeting | | meeting.participant_left | Participant leaves meeting | | recording.completed | Cloud recording ready | | user.created | New user added | | user.updated | User details changed |

Connection Management

Keep-Alive

WebSocket connections require periodic heartbeats. Zoom will close idle connections.

// Send ping every 30 seconds
setInterval(() => {
  if (ws.readyState === WebSocket.OPEN) {
    ws.ping();
  }
}, 30000);

Reconnection

Implement automatic reconnection for reliability:

function connectWithReconnect() {
  const ws = connectWebSocket();
  
  ws.on('close', () => {
    console.log('Connection lost. Reconnecting in 5 seconds...');
    setTimeout(connectWithReconnect, 5000);
  });
  
  return ws;
}

Single Connection Limit

Important: Only ONE WebSocket connection can be open per subscription at a time. Opening a new connection will close the existing one.

Detailed References

Troubleshooting

Sample Repositories

Official / Community

| Type | Repository | Description | |------|------------|-------------| | Node.js | [just-zoomit/zoom-websockets](https://github.com/just-zoomit/zoom-websockets) | WebSocket sample with S2S OAuth |

WebSockets vs RTMS

Don't confuse WebSockets with RTMS (Realtime Media Streams):

| Feature | WebSockets | RTMS | |---------|------------|------| | Purpose | Event notifications | Media streams | | Data | Meeting events, user events | Audio, video, transcripts | | Use case | React to Zoom events | AI/ML, live transcription | | Skill | This skill | rtms |

For real-time audio/video/transcript data, use the rtms skill instead.

Resources

Environment Variables