setup-zoom-websockets について
Zoomの永続的なイベントストリームを実装する開発者向けのリファレンススキルです。WebhooksよりWebSocketsが適する場面を示し、設定と接続管理を解説します。
主な機能
- 01WebSocketsとWebhooksの比較
- 02Server-to-Server OAuthの前提条件
- 03イベントサブスクリプション設定
- 04ハートビートと再接続の案内
- 05Zoomイベントのリファレンス
活用シーン
- 01低遅延の会議イベント受信
- 02公開Webhookエンドポイントの回避
- 03WebSocketsとWebhooksの選択
- 04Zoomイベント接続の維持
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ anthropics/ knowledge-work-plugins --skill setup-zoom-websocketsインストール後、Claude Code で/setup-zoom-websocketsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
RUNBOOK.mdreferences/connection.mdenvironment-variables.mdevents.mdtroubleshooting/common-issues.md詳細
/setup-zoom-websockets
永続的な Zoom イベントストリームに関する背景情報です。まずワークフローによるルーティングを優先し、WebSockets のほうが適している可能性がある場合に、このファイルを参照してください。
WebSockets と Webhooks の比較
| 項目 | WebSockets | Webhooks |
|---|---|---|
| 接続 | 永続的な双方向接続 | 1 回限りの HTTP POST |
| 遅延 | 低い(HTTP のオーバーヘッドなし) | 高い(イベントごとに新しい接続) |
| セキュリティ | 直接接続のため、エンドポイントを公開しない | エンドポイントの検証と IP の許可リスト登録が必要 |
| モデル | プル(Zoom に接続します) | プッシュ(Zoom から接続します) |
| 状態 | ステートフル(接続を維持) | ステートレス(各イベントは独立) |
| セットアップ | より複雑(アクセストークンと接続が必要) | より簡単(エンドポイント URL のみ) |
次の場合は WebSockets を選択してください:
- リアルタイムで低遅延の更新が重要な場合
- セキュリティが最優先の場合(銀行、医療、金融)
- パブリックエンドポイントを公開したくない場合
- 双方向通信が必要な場合
次の場合は Webhooks を選択してください:
- より簡単なセットアップを優先する場合
- イベント通知の数が少ない場合
- 既存の HTTP インフラストラクチャを利用する場合
前提条件
- Zoom Marketplace の Server-to-Server OAuth アプリ
- アカウント ID、クライアント ID、クライアントシークレット
- イベントを有効にした WebSocket サブスクリプション
S2S OAuth についてサポートが必要ですか? 認証フローの詳細については、zoom-oauth スキルを参照してください。
すぐにトラブルシューティングを始めましょう: 詳細なデバッグを行う前に、5-Minute Runbook を使用してください。
クイックスタート
1. Server-to-Server OAuth アプリを作成する
- Zoom Marketplace に移動します
- Server-to-Server OAuth アプリを作成します
- アカウント ID、クライアント ID、クライアントシークレットをコピーします
2. WebSocket サブスクリプションを有効にする
- アプリで Feature → Event Subscriptions に移動します
- イベントサブスクリプションを追加します
- 方法の種類として WebSockets を選択します
- サブスクライブするイベントを選択します(例:
meeting.created、meeting.started) - 保存すると、エンドポイント URL が生成されます
3. 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();
イベント形式
WebSocket 経由で受信するイベントは、Webhook イベントと同じ形式です。
{
"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"
}
}
}
よく使われるイベント
| イベント | 説明 |
|---|---|
meeting.created | ミーティングがスケジュールされた |
meeting.updated | ミーティングの設定が変更された |
meeting.deleted | ミーティングが削除された |
meeting.started | ミーティングが開始する |
meeting.ended | ミーティングが終了する |
meeting.participant_joined | 参加者がミーティングに参加する |
meeting.participant_left | 参加者がミーティングから退出する |
recording.completed | クラウド録画の準備が完了した |
user.created | 新しいユーザーが追加された |
user.updated | ユーザー情報が変更された |
接続管理
キープアライブ
WebSocket 接続では、定期的なハートビートが必要です。Zoom はアイドル状態の接続を終了します。
// Send ping every 30 seconds
setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.ping();
}
}, 30000);
再接続
信頼性を高めるため、自動再接続を実装してください。
function connectWithReconnect() {
const ws = connectWebSocket();
ws.on('close', () => {
console.log('Connection lost. Reconnecting in 5 seconds...');
setTimeout(connectWithReconnect, 5000);
});
return ws;
}
同時接続数の上限
重要: サブスクリプションごとに開ける WebSocket 接続は一度に 1 つだけです。新しい接続を開くと、既存の接続は終了します。
詳細情報
- references/connection.md - 接続のライフサイクル、認証、エラー処理
- references/events.md - イベントの種類に関する完全なリファレンス
トラブルシューティング
- troubleshooting/common-issues.md - サブスクリプション URL の混同、切断、イベントが届かない場合のデバッグ
サンプルリポジトリ
公式/コミュニティ
| 種類 | リポジトリ | 説明 |
|---|---|---|
| Node.js | just-zoomit/zoom-websockets | S2S OAuth を使用した WebSocket のサンプル |
WebSockets と RTMS の違い
WebSockets と RTMS(リアルタイムメディアストリーム)を混同しないでください。
| 機能 | WebSockets | RTMS |
|---|---|---|
| 目的 | イベント通知 | メディアストリーム |
| データ | ミーティングイベント、ユーザーイベント | 音声、動画、文字起こし |
| ユースケース | Zoom イベントへの対応 | AI/ML、リアルタイム文字起こし |
| スキル | このスキル | rtms |
リアルタイムの音声/動画/文字起こしデータには、代わりに rtms スキルを使用してください。
リソース
- WebSockets のドキュメント: https://developers.zoom.us/docs/api/websockets/
- Webhook との比較: https://www.zoom.com/en/blog/a-guide-to-webhooks-and-websockets/
- 開発者フォーラム: https://devforum.zoom.us/
環境変数
- 標準化された
.envキーと各値の確認場所については、references/environment-variables.md を参照してください。