コンテンツにスキップ

OpenClaw音声通話プラグイン導入ガイド:Twilio/Telnyx対応

電話機能をアプリケーションに組み込むのは、いつも骨の折れる作業ですよね。API の複雑な仕様を読み込み、Webhook のセキュリティを確保し、さらには音声の遅延対策まで……。開発者が直面するこうした課題を解決するために、OpenClaw の Voice Call プラグインは設計されました。

このプラグインを使えば、OpenClaw を通じてアウトバウンドの通知や、インバウンドポリシーに基づいたマルチターンの会話を簡単に実現できます。

現在サポートされているプロバイダーは以下の通りです:

  • twilio (Programmable Voice + Media Streams)
  • telnyx (Call Control v2)
  • plivo (Voice API + XML transfer + GetInput speech)
  • mock (開発用、ネットワーク接続なし)

基本的な流れ:

  • プラグインをインストール
  • Gateway を再起動
  • plugins.entries.voice-call.config で設定
  • openclaw voicecall ... コマンドまたは voice_call ツールを使用

実行環境(ローカル vs リモート)

Section titled “実行環境(ローカル vs リモート)”

Voice Call プラグインは Gateway プロセス内で動作します。

リモートの Gateway を使用している場合は、Gateway が動作しているマシンにプラグインをインストール・設定し、Gateway を再起動して読み込んでください。

オプション A: npm からインストール(推奨)

Section titled “オプション A: npm からインストール(推奨)”
Terminal window
openclaw plugins install @openclaw/voice-call

インストール後、Gateway を再起動してください。

オプション B: ローカルフォルダからインストール(開発用)

Section titled “オプション B: ローカルフォルダからインストール(開発用)”
Terminal window
PLUGIN_SRC=./path/to/local/voice-call-plugin
openclaw plugins install "$PLUGIN_SRC"
cd "$PLUGIN_SRC" && pnpm install

インストール後、Gateway を再起動してください。

plugins.entries.voice-call.config の下に設定を記述します:

{
plugins: {
entries: {
"voice-call": {
enabled: true,
config: {
provider: "twilio", // or "telnyx" | "plivo" | "mock"
fromNumber: "+15550001234",
toNumber: "+15550005678",
twilio: {
accountSid: "ACxxxxxxxx",
authToken: "...",
},
telnyx: {
apiKey: "...",
connectionId: "...",
// Telnyx webhook public key from the Telnyx Mission Control Portal
// (Base64 string; can also be set via TELNYX_PUBLIC_KEY).
publicKey: "...",
},
plivo: {
authId: "MAxxxxxxxxxxxxxxxxxxxx",
authToken: "...",
},
// Webhook server
serve: {
port: 3334,
path: "/voice/webhook",
},
// Webhook security (recommended for tunnels/proxies)
webhookSecurity: {
allowedHosts: ["voice.example.com"],
trustedProxyIPs: ["100.64.0.1"],
},
// Public exposure (pick one)
// publicUrl: "https://example.ngrok.app/voice/webhook",
// tunnel: { provider: "ngrok" },
// tailscale: { mode: "funnel", path: "/voice/webhook" }
outbound: {
defaultMode: "notify", // notify | conversation
},
streaming: {
enabled: true,
streamPath: "/voice/stream",
preStartTimeoutMs: 5000,
maxPendingConnections: 32,
maxPendingConnectionsPerIp: 4,
maxConnections: 128,
},
},
},
},
},
}

注意点:

  • Twilio/Telnyx/Plivo を使用する場合、外部からアクセス可能な Webhook URL が必要です。
  • mock はローカル開発用のプロバイダーで、ネットワーク通信を行いません。
  • Telnyx では、skipSignatureVerification が true でない限り telnyx.publicKey(または TELNYX_PUBLIC_KEY)が必要です。
  • skipSignatureVerification はローカルテスト専用の設定です。
  • ngrok の無料プランを使用する場合は、publicUrl に正確な ngrok の URL を設定してください。署名検証は常に強制されます。
  • tunnel.allowNgrokFreeTierLoopbackBypass: true を設定すると、tunnel.provider="ngrok" かつ serve.bind がループバック(ngrok ローカルエージェント)の場合に限り、署名が無効な Twilio Webhook を許可します。これはローカル開発でのみ使用してください。
  • ngrok の無料プランの URL は変更されたり、途中に確認画面が挟まったりすることがあります。publicUrl がずれると Twilio の署名検証に失敗するため、本番環境では固定ドメインや Tailscale Funnel の利用をおすすめします。
  • ストリーミングのセキュリティ初期設定:
    • streaming.preStartTimeoutMs: 有効な start フレームを送信しないソケットを閉じます。
    • streaming.maxPendingConnections: 認証前の保留状態ソケットの総数を制限します。
    • streaming.maxPendingConnectionsPerIp: 送信元 IP ごとの認証前保留ソケット数を制限します。
    • streaming.maxConnections: オープンなメディアストリームソケット(保留中 + アクティブ)の総数を制限します。

停滞したコールの自動終了(Stale call reaper)

Section titled “停滞したコールの自動終了(Stale call reaper)”

staleCallReaperSeconds を使用すると、終了の Webhook が届かないコール(例:完了しない通知モードのコールなど)を強制終了できます。デフォルトは 0(無効)です。

推奨される設定値:

  • 本番環境: 通知スタイルのフローでは 120〜300 秒。
  • 通常のコールが完了できるように、maxDurationSeconds よりも大きな値を設定してください。maxDurationSeconds + 30–60 秒程度が目安です。

例:

{
plugins: {
entries: {
"voice-call": {
config: {
maxDurationSeconds: 300,
staleCallReaperSeconds: 360,
},
},
},
},
}

Gateway の前にプロキシやトンネルがある場合、プラグインは署名検証のために公開 URL を再構成します。以下のオプションで、どの転送ヘッダーを信頼するかを制御できます。

webhookSecurity.allowedHosts は、転送ヘッダー内のホストを許可リストで制限します。

webhookSecurity.trustForwardingHeaders は、許可リストなしで転送ヘッダーを信頼します。

webhookSecurity.trustedProxyIPs は、リクエストの送信元 IP がリストに一致する場合のみ転送ヘッダーを信頼します。

Twilio と Plivo では Webhook のリプレイ保護が有効です。リプレイされた有効なリクエストは、受信確認は行われますが、実際の処理はスキップされます。

Twilio の会話ターンでは、<Gather> コールバックにターンごとのトークンが含まれます。これにより、古い、またはリプレイされた音声コールバックが新しいターンの回答として処理されるのを防ぎます。

プロバイダーが必要とする署名ヘッダーがない未認証のリクエストは、ボディを読み込む前に拒否されます。

Voice Call は、通話中のストリーミング音声にコア設定の messages.tts を使用します。プラグイン設定内で同じ形式で記述することで、設定を上書き(ディープマージ)できます。

{
tts: {
provider: "elevenlabs",
providers: {
elevenlabs: {
voiceId: "pMsXgVXv3BLzUgSXRplE",
modelId: "eleven_multilingual_v2",
},
},
},
}

注意点:

  • プラグイン設定内の古い形式(tts.openai など)は、読み込み時に tts.providers.openai へ自動移行されます。今後は providers 形式での記述を推奨します。
  • Microsoft の音声は Voice Call では無視されます(電話音声には PCM が必要ですが、現在の Microsoft の実装では対応していないためです)。
  • Twilio のメディアストリーミングが有効な場合はコア TTS が使用され、そうでない場合はプロバイダー標準の音声にフォールバックします。
  • Twilio メディアストリームがアクティブな場合、TwiML の <Say> へのフォールバックは行われません。TTS が利用できない場合は、再生リクエストが失敗します。
  • フォールバックが発生した際は、デバッグ用にプロバイダーの試行チェーンがログに記録されます。

コア TTS をそのまま使用する場合(上書きなし):

{
messages: {
tts: {
provider: "openai",
providers: {
openai: { voice: "alloy" },
},
},
},
}

通話時のみ ElevenLabs を使用する場合:

{
plugins: {
entries: {
"voice-call": {
config: {
tts: {
provider: "elevenlabs",
providers: {
elevenlabs: {
apiKey: "elevenlabs_key",
voiceId: "pMsXgVXv3BLzUgSXRplE",
modelId: "eleven_multilingual_v2",
},
},
},
},
},
},
},
}

通話時のみ OpenAI のモデルを変更する場合(ディープマージの例):

{
plugins: {
entries: {
"voice-call": {
config: {
tts: {
providers: {
openai: {
model: "gpt-4o-mini-tts",
voice: "marin",
},
},
},
},
},
},
},
}

着信ポリシーのデフォルトは disabled です。着信を有効にするには以下を設定します:

{
inboundPolicy: "allowlist",
allowFrom: ["+15550001234"],
inboundGreeting: "Hello! How can I help?",
}

inboundPolicy: "allowlist" は発信者番号(Caller-ID)による簡易的なフィルタリングです。Webhook の検証によってプロバイダーからの正当なリクエストであることは保証されますが、PSTN/VoIP の発信者番号自体の所有権を証明するものではありません。

自動応答は Agent システムを使用します。以下の項目で調整可能です:

  • responseModel
  • responseSystemPrompt
  • responseTimeoutMs

自動応答の際、Voice Call はシステムプロンプトに以下の厳格な出力規約を追加します:

  • {"spoken":"..."}

プラグインは以下の方法で音声を抽出します:

  • 思考プロセス(reasoning)やエラー内容は無視します。
  • JSON 直接、フェンス付き JSON、またはインラインの "spoken" キーを解析します。
  • プレーンテキストの場合は、計画やメタ的な導入文を除去して抽出します。

これにより、発信者に不要な思考プロセスを聞かせることなく、適切な応答のみを再生します。

アウトバウンドの conversation コールでは、最初のメッセージ処理は再生状態と連動します:

  • 最初の挨拶を再生している間は、割り込み(Barge-in)キューのクリアや自動応答が抑制されます。
  • 再生に失敗した場合、コールは listening 状態に戻り、メッセージはリトライのためにキューに残ります。

Twilio のメディアストリームが切断された場合、Voice Call は 2000ms 待機してからコールを終了します:

  • 猶予期間内に再接続されれば、終了処理はキャンセルされます。
  • 再接続されない場合は、アクティブなコールが残るのを防ぐために終了処理が行われます。
Terminal window
openclaw voicecall call --to "+15555550123" --message "Hello from OpenClaw"
openclaw voicecall start --to "+15555550123" # alias for call
openclaw voicecall continue --call-id <id> --message "Any questions?"
openclaw voicecall speak --call-id <id> --message "One moment"
openclaw voicecall end --call-id <id>
openclaw voicecall status --call-id <id>
openclaw voicecall tail
openclaw voicecall latency # summarize turn latency from logs
openclaw voicecall expose --mode funnel

latency コマンドは calls.jsonl から統計を読み取ります。--file でパスを指定したり、--last <n> で直近のレコード数を制限したりできます。p50/p90/p99 のレイテンシを確認するのに便利です。

ツール名: voice_call

アクション:

  • initiate_call (message, to?, mode?)
  • continue_call (callId, message)
  • speak_to_user (callId, message)
  • end_call (callId)
  • get_status (callId)

対応するスキル定義は skills/voice-call/SKILL.md にあります。

  • voicecall.initiate (to?, message, mode?)
  • voicecall.continue (callId, message)
  • voicecall.speak (callId, message)
  • voicecall.end (callId)
  • voicecall.status (callId)

{
plugins: {
entries: {
"voice-call": {
config: {
publicUrl: "https://voice.example.com/voice/webhook",
webhookSecurity: {
allowedHosts: ["voice.example.com"],
},
},
},
},
},
}
OpenClaw

OpenClaw Expert

まだ解決しませんか?

このページで解決しない場合は、OpenClaw Expertに直接質問してください。