Webhooks API

リアルタイムミーティングイベント通知

Webhooks API は、ミーティングイベントのリアルタイム通知を有効にし、ミーティングの開始、完了、文字起こしイベントなどに関するアップデートをアプリケーションが受信できるようにします。

  • リアルタイムのミーティング通知を受信する
  • 既存のworkflowツールと統合する
  • ミーティングイベント用のカスタムイベントハンドラーを構築する
  • ミーティング後のプロセスを自動化する

Webhookは、常時ポーリングを行わずにミーティングのライフサイクルイベントに反応するレスポンシブなアプリケーションを構築するための強力な手段を提供し、CRM、分析プラットフォーム、その他のビジネスシステムとの効率的な統合を実現します。

主な機能

  • ミーティングライフサイクルイベント: ミーティングの開始、完了、失敗の通知を受信する
  • 文字起こしイベント: 文字起こしが利用可能または更新された際にアップデートを取得する
  • カレンダーイベント: カレンダーの変更と同期の通知
  • 再試行メカニズム: 失敗したwebhook配信を再試行するAPI endpoint
  • カスタマイズ可能なEndpoint: 異なるイベントタイプに異なるwebhook URLを設定する
  • イベントフィルタリング: 通知をトリガーするイベントを制御する

Webhookイベントタイプ

Meeting BaaSのwebhookは以下のイベントタイプを配信します:

  • meeting.started: botがミーティングへの参加に成功した
  • meeting.completed: ミーティングが終了し、録画が利用可能になった
  • meeting.failed: botがミーティングへの参加に失敗した
  • transcription.available: 初期文字起こしが利用可能になった
  • transcription.updated: 文字起こしが更新または修正された
  • calendar.synced: カレンダーが同期された
  • event.added: 新しいカレンダーイベントが検出された
  • event.updated: カレンダーイベントが更新された
  • event.deleted: カレンダーイベントが削除された

セットアップと設定

Webhook Endpointの設定

ミーティングイベント用のwebhook URLを設定する方法の例を以下に示します:

このJSON設定は、Meeting BaaSアカウントでwebhook endpointをセットアップする方法を示しています。

webhook_config.json
{
  "webhook_url": "https://your-app.com/webhooks/meetingbaas",
  "events": [
    "meeting.started",
    "meeting.completed",
    "meeting.failed",
    "transcription.available"
  ],
  "secret": "your-webhook-secret-key",
  "enabled": true
}

Webhook Endpointの一覧表示

list_webhooks.sh
curl -X GET "https://api.meetingbaas.com/bots/webhooks/bot" \
  -H "x-meeting-baas-api-key: <token>"

Webhookイベントフォーマット

webhook event payloadの例を以下に示します:

これらのJSONの例は、ミーティング開始および完了イベント通知のフォーマットを示しています。

ミーティング完了イベント

meeting_completed.json
{
  "event": "complete",
  "data": {
    "bot_id": "123e4567-e89b-12d3-a456-426614174000",
    "transcript": [
      {
        "speaker": "John Doe",
        "offset": 1.5,
        "words": [
          {
            "start": 1.5,
            "end": 1.9,
            "word": "Hello"
          },
          {
            "start": 2.0,
            "end": 2.4,
            "word": "everyone"
          }
        ]
      }
    ],
    "speakers": [
      "Jane Smith",
      "John Doe"
    ],
    "mp4": "https://storage.example.com/recordings/video123.mp4?token=abc",
    "event": "complete"
  }
}

ミーティング失敗イベント

meeting_failed.json
{
  "event": "failed",
  "data": {
    "bot_id": "123e4567-e89b-12d3-a456-426614174000",
    "error": "meeting_not_found",
    "message": "Could not join meeting: The meeting ID was not found or has expired"
  }
}

文字起こし完了イベント

transcription_complete.json
{
  "event": "transcription_complete",
  "data": {
    "bot_id": "123e4567-e89b-12d3-a456-426614174000"
  }
}

実装例

Python Webhookハンドラー

webhook_handler_flask.py
from flask import Flask, request, jsonify
import hmac
import hashlib

app = Flask(__name__)
WEBHOOK_SECRET = "your-webhook-secret-key"

def verify_signature(payload, signature):
    expected_signature = hmac.new(
        WEBHOOK_SECRET.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected_signature)

@app.route('/webhooks/meetingbaas', methods=['POST'])
def webhook_handler():
    signature = request.headers.get('X-MeetingBaas-Signature')
    payload = request.get_data()
    
    if not verify_signature(payload, signature):
        return jsonify({"error": "Invalid signature"}), 401
    
    event_data = request.json
    
    if event_data['event'] == 'complete':
        # Handle meeting completion
        bot_id = event_data['data']['bot_id']
        transcript = event_data['data']['transcript']
        recording_url = event_data['data']['mp4']
        
        # Process the meeting data
        process_meeting_completion(bot_id, transcript, recording_url)
        
    elif event_data['event'] == 'failed':
        # Handle meeting failure
        bot_id = event_data['data']['bot_id']
        error = event_data['data']['error']
        message = event_data['data']['message']
        
        # Log the failure
        log_meeting_failure(bot_id, error, message)
    
    return jsonify({"status": "success"}), 200

def process_meeting_completion(bot_id, transcript, recording_url):
    # Your custom logic here
    print(f"Meeting {bot_id} completed")
    print(f"Recording available at: {recording_url}")

if __name__ == '__main__':
    app.run(debug=True, port=5000)
webhook_handler_fastapi.py
from fastapi import FastAPI, Request, HTTPException, Header
import hmac
import hashlib
from typing import Optional

app = FastAPI()
WEBHOOK_SECRET = "your-webhook-secret-key"

def verify_signature(payload: bytes, signature: str) -> bool:
    expected_signature = hmac.new(
        WEBHOOK_SECRET.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected_signature)

@app.post("/webhooks/meetingbaas")
async def webhook_handler(
    request: Request,
    x_meetingbaas_signature: Optional[str] = Header(None)
):
    payload = await request.body()
    
    if not x_meetingbaas_signature:
        raise HTTPException(status_code=401, detail="Missing signature")
    
    if not verify_signature(payload, x_meetingbaas_signature):
        raise HTTPException(status_code=401, detail="Invalid signature")
    
    event_data = await request.json()
    
    # Process different event types
    if event_data['event'] == 'complete':
        await handle_meeting_completion(event_data['data'])
    elif event_data['event'] == 'failed':
        await handle_meeting_failure(event_data['data'])
    elif event_data['event'] == 'transcription_complete':
        await handle_transcription_complete(event_data['data'])
    
    return {"status": "success"}

async def handle_meeting_completion(data):
    bot_id = data['bot_id']
    transcript = data['transcript']
    recording_url = data['mp4']
    
    # Your custom logic here
    print(f"Meeting {bot_id} completed")
    print(f"Recording available at: {recording_url}")

async def handle_meeting_failure(data):
    bot_id = data['bot_id']
    error = data['error']
    message = data['message']
    
    # Your custom logic here
    print(f"Meeting {bot_id} failed: {error} - {message}")

async def handle_transcription_complete(data):
    bot_id = data['bot_id']
    
    # Your custom logic here
    print(f"Transcription completed for meeting {bot_id}")

Node.js Webhookハンドラー

webhook_handler_node.js
const express = require('express');
const crypto = require('crypto');
const app = express();

const WEBHOOK_SECRET = 'your-webhook-secret-key';

app.use(express.json());

function verifySignature(payload, signature) {
  const expectedSignature = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(payload)
    .digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

app.post('/webhooks/meetingbaas', (req, res) => {
  const signature = req.headers['x-meetingbaas-signature'];
  const payload = JSON.stringify(req.body);
  
  if (!verifySignature(payload, signature)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  
  const eventData = req.body;
  
  switch (eventData.event) {
    case 'complete':
      handleMeetingCompletion(eventData.data);
      break;
    case 'failed':
      handleMeetingFailure(eventData.data);
      break;
    case 'transcription_complete':
      handleTranscriptionComplete(eventData.data);
      break;
    default:
      console.log(`Unknown event: ${eventData.event}`);
  }
  
  res.json({ status: 'success' });
});

function handleMeetingCompletion(data) {
  const { bot_id, transcript, mp4 } = data;
  console.log(`Meeting ${bot_id} completed`);
  console.log(`Recording available at: ${mp4}`);
  
  // Your custom logic here
  // e.g., save to database, send notifications, etc.
}

function handleMeetingFailure(data) {
  const { bot_id, error, message } = data;
  console.log(`Meeting ${bot_id} failed: ${error} - ${message}`);
  
  // Your custom logic here
  // e.g., retry logic, alert notifications, etc.
}

function handleTranscriptionComplete(data) {
  const { bot_id } = data;
  console.log(`Transcription completed for meeting ${bot_id}`);
  
  // Your custom logic here
  // e.g., process transcript, update database, etc.
}

app.listen(3000, () => {
  console.log('Webhook server running on port 3000');
});

ベストプラクティス

セキュリティ

  • 常にwebhookの署名を検証する
  • HTTPSのendpointを使用する
  • rate limitingを実装する
  • イベントデータを検証する

信頼性

  • 200ステータスコードを迅速に返す
  • 冪等性を実装する
  • 重複イベントを処理する
  • 監視とアラートを設定する

エラーハンドリング

  • すべてのwebhookイベントをlogに記録する
  • 失敗に対する再試行ロジックを実装する
  • デッドレターキューを設定する
  • webhookの配信状況を監視する
Meeting BaaS API Preview Features

はじめに

リアルタイムのミーティング通知を統合する準備はできましたか?包括的なリソースをご確認ください: