1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Zoom Developer】ZoomとLINE公式チャンネルをリアルタイム連携するメッセージ転送システムを作ってみた

Last updated at Posted at 2025-06-23

はじめに

こんにちは!今回は、LINEで受信したメッセージを自動的にZoomチャンネルに転送するシステムを作ってみました。

企業でのSlack連携はよく見かけますが、ZoomのTeam Chat機能を使った連携事例はまだ少ないのではないでしょうか?そこで実際に動くシステムを構築してみたので、その実装方法をご紹介します!

作ったもの

  • LINEでメッセージを送ると、Zoomの指定チャンネルに自動転送
  • Zoomでスレッド返信すると、元のLINEユーザーに自動返信
  • 非同期処理によるレスポンシブな応答
  • モジュール化された保守しやすいアーキテクチャ
  • メッセージID管理による双方向突合機能

システム構成

📱 LINE公式アカウント
    ↓ Webhook (メッセージ送信)
🔧 Node.js Express Server
    ↓ Zoom API (メッセージ投稿)
💬 Zoom Team Chat
    ↓ Webhook (返信通知)
🔧 Node.js Express Server
    ↓ LINE Push API (返信転送)
📱 LINE公式アカウント
  • LINE → Zoom への転送だけでなく
  • Zoom → LINE への返信転送も実現

ディレクトリ構成

📁 zoom-line-bridge/
├── 📄 app.js                    # メインエントリーポイント
├── 📁 routes/
│   └── 📄 webhook.js             # LINE Webhook処理
├── 📁 services/
│   ├── 📄 messageProcessor.js    # メイン処理ロジック
│   ├── 📄 lineApi.js             # LINE API通信
│   ├── 📄 externalApi.js         # Zoom API通信
│   └── 📄 messageMappingService.js # メッセージID管理
├── 📁 utils/
│   └── 📄 formatter.js           # メッセージ整形
└── 📄 .env                       # 環境変数

技術的なポイント

1. Reply API + Push API のハイブリッド構成

LINEのメッセージ応答では、Reply API(無料・即座)とPush API(有料・非同期)を使い分けることで、ユーザー体験とコストを最適化できます。

// 即座に応答(Reply API)
await lineApi.replyMessage(replyToken, 'メッセージありがとうございます!返信まで今しばらくお待ちください。');

// 長時間処理後に結果送信(Push API)
await lineApi.pushMessage(userId, resultMessage);

2. Zoom OAuth認証の自動化

Zoom APIでは今回、Server-to-Server OAuthを使用しています。ユーザー認証なしで自動的にアクセストークンを取得できます。(条件あり)

3. 双方向通信のためのWebhook連携

さらにZoomのWebhook機能を活用してチャット返信イベントを検知し、LINEに自動転送する機能が実装できます。

// Zoomからの返信を検知
if (event === 'chat_message.replied') { //chat_message.replied イベント利用
  const message = payload.object.message;
  const parentMsgId = payload.object.parent_msg_id;
  
  // メッセージIDマッピングから元のLINEユーザーを特定
  const mappedData = messageMap.get(parentMsgId);
  if (mappedData) {
    // LINEにPush APIで返信転送
    await lineApi.pushMessage(mappedData.userId, message);
  }
}

4. MessageMappingによる突合管理

ZoomメッセージIDとLINEユーザーIDのマッピングを管理することで、双方向通信や確実な個別返信を実現できます。この辺りは実装方法も人それぞれになるかなと思います。あえて詳細を記載しませんが、信頼性や実装の複雑性、実装フェーズなどに応じてマッピング機能を実装します。

セットアップ手順

1. Zoom App作成

  1. Zoom Marketplace でDeveloper Accountを作成
  2. 「Build App」→「Server-to-Server OAuth」を選択
  3. 必要なスコープを設定:
    • chat_channel:read(チャンネル一覧取得)
    • chat_message:write(メッセージ送信)
  4. Client ID、Client Secret、Account IDを取得

双方向通信のためのWebhook設定:
5. 「Event Subscriptions」を有効化
6. Webhook URLを設定(https://your-domain.com/zoom-webhook
7. 「Chat Message Events」でchat_message.repliedを選択
8. Webhook Tokenを取得

2. LINE Developers設定

  1. LINE Developers Console でChannelを作成
  2. Webhook URLを設定(https://your-domain.com/webhook
  3. Channel Access Tokenを取得

LINE Developerによると複数の種類のChannel Access Tokenがあるようです。セキュリティポリシーに応じて検討してください。v2.1でも問題なく投稿できました。

実装

1. 環境変数設定

# .env
# LINE Bot設定
CHANNEL_ACCESS_TOKEN=your_line_channel_access_token

# Zoom API設定
ZOOM_CLIENT_ID=your_zoom_client_id
ZOOM_CLIENT_SECRET=your_zoom_client_secret
ZOOM_ACCOUNT_ID=your_zoom_account_id
ZOOM_WEBHOOK_TOKEN=your_zoom_webhook_token

2. LINE Webhook受信

// routes/webhook.js
router.post('/webhook', async (req, res) => {
  try {
    const event = req.body.events[0];
    const message = event.message.text;
    const userId = event.source.userId;
    const replyToken = event.replyToken;
    
    // すぐに200 OKを返す
    res.status(200).json({ message: 'OK' });
    
    // 非同期処理開始
    messageProcessor.processMessage(userId, message, replyToken);
    
  } catch (error) {
    console.error(error);
    res.status(500).json({ error: 'Internal Server Error' });
  }
});

3. Zoom API連携

Zoom Team Chat への送信には、 /v2/chat/users/{userId}/messages エンドポイントを利用します。userIdに特定のユーザーを入れることで、そのユーザーからの発信という形で投稿が可能です。以下の例では、PoC的に /me/ を入れています。これは、この Server-to-Server OAuth アプリを作ったユーザーになります。

// services/externalApi.js
  async sendToZoomChannel(inputData) {
    const messageText = `新着メッセージ:${inputData}`;
    const response = await axios.post('https://api.zoom.us/v2/chat/users/me/messages', {
      to_channel: generalChannel.id,
      message: messageText
    }, {
      headers: { 
        Authorization: `Bearer ${this.zoom.accessToken}`,
        'Content-Type': 'application/json' 
      }
    });
    return {
      channelId: generalChannel.id,
      channelName: generalChannel.name,
      messageId: response.data.id
    };
  }
}

このメソッドを呼び出し、投稿に成功するとレスポンスとして以下のような message_id が取得できます。

{
  "id": "8cfaf567-bf5a-4acc-b4f2-88b3d371aca5"
}

このIDは後ほどメッセージの返信マッピングを行うにあたって使うので、別途保存しておきます。

4. Zoom Webhook受信

先ほど掲載したものの再掲になりますが、chat_message.replied を受けてpayloadから

  • 誰に対する返信か(parent_msg_id)
  • メッセージの内容(message

を取得し parent_msg_id と、上述のプロセスで取得していたメッセージのIDと突合します。

router.post('/zoom-webhook', async (req, res) => {
  try {
    const event = req.body.event;
    const payload = req.body.payload;
    
    if (event === 'endpoint.url_validation') {/* 省略 */}

    if (event === 'chat_message.replied') {
      const message = payload.object.message;
      const parentMsgId = payload.object.parent_msg_id;

      // parent_msg_idが一致する場合、LINEにメッセージを送信
      const mappedData = messageMap.get(parentMsgId);
      if (mappedData) {
        const replyMessage = message;
        
        try {
          await lineApi.pushMessage(mappedData.userId, replyMessage);
          
        } catch (error) {
          console.error(error);
        }
      } else {
        //マッピングがなかった場合の処理
      }
    }

    res.status(200).json({ message: 'OK' });
  } catch (error) {
    console.error(error);
    res.status(500).json({ error: 'Internal Server Error' });
  }
});

5. デプロイ

ざっくりですが、それぞれの設定が完了後、冒頭の環境変数を準備します。

# 依存関係インストール
npm install express axios dotenv

# 環境変数設定
nano .env
# .envファイルを編集

# サーバー起動
npm start

応用アイデア

  • 画像・ファイルの転送対応
  • メンション機能: @指定でZoom内の特定ユーザーに通知
  • 自動翻訳機能: 多言語チーム対応
  • チャンネル振り分け: メッセージ内容に応じて送信先変更

要検討事項

今回の実装はあくまでPoCなので、実際に活用していくにあたっては権限管理や、監査、ロギング、またAPIなどのエラーハンドリングやAPIのRate Limitへのケアなどが必要です。状況に応じてご検討ください。

まとめ

顧客サポート、社内ヘルプデスク、チーム間連携など、様々な用途で活用できるシステムです。企業のコミュニケーションツール統合に興味がある方は、ぜひ試してみてください!


参考リンク

LINE Developersに加えて、こちらの資料は大変参考になりました。有名かもしれませんが、リンク貼っておきます。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?