Skip to main content
WebSocket 経由でアプリケーションと音声エージェントの間で音声をストリーミングします。Web アプリ、モバイルアプリ、または独自のテレフォニープロバイダーをブリッジするのに使用できます。

クイックスタート

/access-token エンドポイント からアクセストークンを取得します。詳細は クライアントアプリの認証 を参照してください。

接続

WebSocket エンドポイントに接続します:
ヘッダー:

プロトコル概要

WebSocket 接続は、制御イベントには JSON メッセージ、メディアには Base64 エンコードされた音声を使用します。新しいサーバーイベントの種類は今後追加される可能性があります。前方互換性を保つため、認識できないイベントはエラーとして扱わずに無視してください。 セッションは 4 つのフェーズを経て進行します:
  1. Start(開始)。 音声設定を含む start イベントを送信します。
  2. Ready(準備完了)。 エージェントのパイプラインが準備できると、サーバーは ack で応答します。
  3. Converse(会話)。 ユーザー音声を media_input としてストリーミングし、media_output からエージェント音声を再生します。並行して、サーバーは会話の進行を表す会話イベントturn_startedturn_output_text_deltaturn_ended)をプッシュします。
  4. End(終了)。 クライアントまたはサーバーのいずれからでも接続を閉じることができます。サーバーのクローズ理由は通話が終了した理由を伝えます(接続の管理を参照)。
通話後は、ack で受け取った call_id を使って通話 APIからセッションの完全なレコードを取得できます。

クライアントイベント

セッションの開始(start

音声ストリームの構成を初期化します。
  • config はエージェントのデフォルトの入力音声設定を上書きします
  • stream_id は任意です。指定されない場合、サーバーが生成して ack イベントで返します
これは最初に送信するメッセージである必要があります。
フィールド:
  • stream_id(任意): ストリーム識別子。指定されない場合はサーバーが生成
  • config.input_format: クライアント音声入力の音声形式(mulaw_8000pcm_16000pcm_24000pcm_44100
  • config.output_audio_delivery(任意): サーバーがエージェント音声を配信する方法。speaking_pace(デフォルト)は再生速度に合わせて音声をペーシングします。as_available はモデルが生成し次第送信するため、ローカルでバッファリングするクライアントは独自のクロックで再生でき、低遅延を実現できます。エージェントがバックグラウンド音声を使用する場合はサポートされません。
  • config.voice_id(任意): エージェントのデフォルト TTS 音声を上書き
  • agent(任意): API 経由で個別のエージェント通話を構成し、本番環境に公開せずに introduction やプロンプトの変更をプレビュー可能
  • metadata(任意): カスタムメタデータオブジェクト。これらはエージェントコードに渡されますが、次のように利用できる特別なフィールドもあります:
    • to(任意): コールルーティング用の宛先識別子(デフォルトはエージェント ID)
    • from(任意): 通話の発信元識別子(デフォルトは「websocket」)

ユーザー音声のストリーミング(media_input

クライアントからサーバーに送信される音声データです。payload の音声データは Base64 エンコードする必要があります。
フィールド:
  • stream_id: ack レスポンスから取得したストリームの一意の識別子
  • media.payload: start イベントで指定された形式の Base64 エンコードされた音声データ

DTMF トーンの送信(dtmf

DTMF(デュアルトーン多重周波数)トーンを送信します。
フィールド:
  • stream_id: ストリーム識別子
  • dtmf: DTMF 桁(0〜9、*、#)

カスタムメタデータの送信(custom

エージェントにカスタムメタデータを送信します。
フィールド:
  • stream_id: ストリーム識別子
  • metadata: カスタムデータのキーと値のペアを含むオブジェクト

サーバーイベント

セッションの準備完了(ack

エージェントのパイプラインが音声を受信できる状態になると start に応答して送信されます。ストリーム構成を確認し、start イベントで指定されなかった場合はサーバー生成の stream_id を返します。
フィールド:
  • call_id: このセッションに対して作成された通話レコードの識別子。通話 API と組み合わせて、通話終了後に録音とトランスクリプトを取得できます

エージェント音声の受信(media_output

エージェントの発話です。payloadstart イベントの config.input_format で指定された形式の Base64 エンコード音声です。

会話イベント

会話そのものを表す 3 つのイベントがあります:turn_startedturn_output_text_deltaturn_ended。すべてのターンは、両ロールで共有される単一のカウンターから id を受け取ります。この id は 1 から始まり、通話全体を通じて厳密に単調増加するため、id だけでターンを一意に特定できます。 1 つのターンに関するイベントは、常に次の順序で到着します:turn_started、続いてゼロ個以上の turn_output_text_delta、最後に turn_ended。サーバーは会話の進行に合わせてこれらをプッシュし、音声の配信タイミングとは独立しています。これらのイベントを使ってトランスクリプトや発話中インジケーターを制御できます。コード例は ライブトランスクリプトを構築する を参照してください。

ターンの開始時(turn_started

ユーザーが話し始めた、またはエージェントが応答を開始したときに送信されます。
フィールド:
  • stream_id: ストリーム識別子
  • turn_started.id: ターンのインデックス。通話全体を通じて一意
  • turn_started.role: user または assistant
  • turn_started.start_timestamp: 通話開始からの経過秒数(おおよそクライアントが ack を受信した時点)

エージェントテキストのストリーミング(turn_output_text_delta

エージェントが発話する各単語ごとに、発話とほぼ同時に送信されます。エージェント側のトランスクリプトを 1 単語ずつ描画するために使用します。
フィールド:
  • stream_id: ストリーム識別子
  • turn_output_text_delta.id: このテキストが属するターンの id と一致
  • turn_output_text_delta.role: 常に assistant
  • turn_output_text_delta.text: 追加する厳密な部分文字列。区切りのスペースも含まれるため、buffer[id] += text の形で連結してテキストを構築してください
これらのデルタはエージェントの発話のみをカバーします。ユーザーの発話は単語単位ではストリーミングされず、ユーザーのターンが終了したときに turn_ended イベントの確定テキストとして届きます。

ターンの終了時(turn_ended

ターンが終了したときに送信されます。ターンの完全な確定テキストを含み、ターン終了後に保存・表示すべきバージョンです。
フィールド:
  • stream_id: ストリーム識別子
  • turn_ended.id: 対応する turn_started イベントの id と一致
  • turn_ended.role: user または assistant
  • turn_ended.text: ターンの確定テキスト。ユーザーのターンでは書き起こされた発話、アシスタントのターンではエージェントが実際に発話したテキスト
  • turn_ended.was_interrupted: アシスタントのターンでは、ユーザーがターンを中断したときに true。ユーザーのターンでは、ターンの途中で通話が終了したときにのみ true
  • turn_ended.start_timestampturn_ended.end_timestamp: 通話開始からの経過秒数
  • turn_ended.tool_calls: ターン中に行われたツール呼び出し。各エントリは namearguments、および任意で resultid を持ちます
エージェントがターンの途中で通話を切った場合、最後の turn_ended を送信せずに接続が閉じられます。接続が閉じたときは、開いているターンが終了したものとして扱ってください。

中断の処理(clear

エージェントが現在の音声ストリームをクリア/中断したいことを示します。

通話の転送(transfer_call

エージェントが通話を電話番号に転送したいことを示します。クライアントは自身のテレフォニー側で転送を開始する責任があります。
フィールド:
  • stream_id: ストリーム識別子
  • transfer.target_phone_number: 通話を転送する E.164 形式の電話番号

ライブトランスクリプトを構築する

ライブトランスクリプトは、進行中の会話を UI に表示する機能で、エージェントの発話がライブキャプションのように 1 語ずつ現れます。
2 つのロールはテキストの届き方が異なるため、描画方法も分けます。ユーザーのターンでは、ターン開始時に発話中インジケーターを表示し、turn_ended が届いた時点でテキストを埋めます。エージェントのターンでは、各単語をデルタが届くたびに表示し、発話ペースに合わせて応答が積み上がるようにします。

接続の管理

無操作タイムアウト

サーバーは 180 秒 後にアイドル接続を閉じます。クライアントからのメッセージがあるたびにタイマーがリセットされます:
  • アプリケーションメッセージ(media_input、dtmf、custom イベント)
  • 標準の WebSocket ping フレーム
  • その他の有効な WebSocket メッセージ
タイムアウトが発生すると、接続は次のように閉じられます:
  • コード: 1000(Normal Closure)
  • 理由: "connection idle timeout"

Ping/Pong キープアライブ

無音期間中の無操作タイムアウトを防ぐため、定期的なキープアライブとして標準の WebSocket ping フレームを使用します:
サーバーは ping フレームに自動的に pong フレームで応答し、いずれかのメッセージを受信すると無操作タイマーをリセットします。

接続の終了

接続はクライアントまたはサーバーのどちらからでも WebSocket クローズフレームを使って閉じることができます。 クライアント開始のクローズ:
サーバー開始のクローズ: エージェントが通話を終了すると、サーバーは次のように接続を閉じます:
  • コード: 1000(Normal Closure)
  • 理由: "call ended by agent"、または追加のコンテキストが利用可能な場合は "call ended by agent, reason: {specific_reason}"

ベストプラクティス

  1. 最初に start を送信start より前に他のイベントが送信されると接続は閉じられます。
  2. 適切な音声形式を選択 — ソースに合わせて形式を選択してください:テレフォニーには mulaw_8000、Web クライアントには pcm_44100
  3. クローズを適切に処理 — デバッグやリカバリのため、常にクローズコードと理由をキャプチャしてください。
  4. 接続を維持 — 180 秒の無操作タイムアウトを回避するため、60〜90 秒ごとに WebSocket ping フレームを送信してください。
  5. ストリーム ID を管理 — システム全体のオブザーバビリティ(可観測性)を高めるため、独自の stream_id 値を指定してください。
  6. アイドルタイムアウトから復旧1000 / connection idle timeout の場合、再接続して start イベントを再送してください。