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

クイックスタート

const ws = new WebSocket(
  `wss://api.cartesia.ai/agents/stream/${agentId}`,
  {
    headers: {
      Authorization: `Bearer ${accessToken}`,
      "Cartesia-Version": "2025-04-16",
    },
  }
);

// Initialize the stream
ws.onopen = () => {
  ws.send(JSON.stringify({
    event: "start",
    config: { input_format: "pcm_44100" },
  }));
};

// Handle agent audio
ws.onmessage = (msg) => {
  const data = JSON.parse(msg.data);
  if (data.event === "media_output") {
    playAudio(atob(data.media.payload));
  }
};

// Send user audio
function sendAudio(audioData) {
  ws.send(JSON.stringify({
    event: "media_input",
    stream_id: streamId,
    media: { payload: btoa(audioData) },
  }));
}
/access-token エンドポイント からアクセストークンを取得します。詳細は クライアントアプリの認証 を参照してください。

接続

WebSocket エンドポイントに接続します:
wss://api.cartesia.ai/agents/stream/{agent_id}
ヘッダー:
ヘッダー
AuthorizationBearer {token}
Cartesia-Version2025-04-16

プロトコル概要

WebSocket 接続は、制御イベントには JSON メッセージ、メディアには Base64 エンコードされた音声を使用します。 クライアントが start イベントを送信すると、サーバーは ack で応答します。その後、両者は接続が閉じるまで音声と制御イベントを交換します。

クライアントイベント

Start イベント

音声ストリームの構成を初期化します。
  • config はエージェントのデフォルトの入力音声設定を上書きします
  • stream_id は任意です。指定されない場合、サーバーが生成して ack イベントで返します
これは最初に送信するメッセージである必要があります。
{
  "event": "start",
  "stream_id": "unique_id",
  "config": {
    "input_format": "pcm_44100",
    "voice_id": "a0e99841-438c-4a64-b679-ae501e7d6091"
  },
  "agent": {
    "introduction": "Hello, I'm an AI assistant",
    "system_prompt": "### Your Role \n You are a helpful assistant"
  },
  "metadata": {
    "to": "user@example.com",
    "from": "+1234567890"
  }
}
フィールド:
  • stream_id(任意): ストリーム識別子。指定されない場合はサーバーが生成
  • config.input_format: クライアント音声入力の音声形式(mulaw_8000pcm_16000pcm_24000pcm_44100
  • config.voice_id(任意): エージェントのデフォルト TTS ボイスを上書き
  • agent(任意): API 経由で個別のエージェント通話を構成し、本番環境に公開せずに introduction やプロンプトの変更をプレビュー可能
  • metadata(任意): カスタムメタデータオブジェクト。これらはエージェントコードに渡されますが、特別なフィールドも使用できます:
    • to(任意): コールルーティング用の宛先識別子(デフォルトはエージェント ID)
    • from(任意): 通話の発信元識別子(デフォルトは「websocket」)

Media Input イベント

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

DTMF イベント

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

Custom イベント

エージェントにカスタムメタデータを送信します。
{
  "event": "custom",
  "stream_id": "example_id",
  "metadata": {
    "user_id": "user123",
    "session_info": "custom_data"
  }
}
フィールド:
  • stream_id: ストリーム識別子
  • metadata: カスタムデータのキーと値のペアを含むオブジェクト

サーバーイベント

Ack イベント

ストリーム構成を確認します。start イベントで stream_id が指定されなかった場合、サーバーが生成した stream_id を返します。
{
  "event": "ack",
  "stream_id": "example_id",
  "config": {
    "input_format": "pcm_44100",
    "voice_id": "a0e99841-438c-4a64-b679-ae501e7d6091"
  },
  "agent": {
    "system_prompt": "### Your Role \n You are a helpful assistant",
    "introduction": "Hello, I'm an AI assistant"
  }
}

Media Output イベント

サーバーがエージェントの音声レスポンスを送信します。payload は Base64 エンコードされた音声データです。
{
  "event": "media_output",
  "stream_id": "example_id",
  "media": {
    "payload": "base64_encoded_audio_data"
  }
}

Clear イベント

エージェントが現在の音声ストリームをクリア/中断したいことを示します。
{
  "event": "clear",
  "stream_id": "example_id"
}

Transfer Call イベント

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

接続の管理

無操作タイムアウト

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

Ping/Pong キープアライブ

無音期間中の無操作タイムアウトを防ぐため、定期的なキープアライブとして標準の WebSocket ping フレームを使用します:
# Client sends ping to reset inactivity timer
pong_waiter = await websocket.ping()
latency = await pong_waiter
// Requires the Node.js `ws` library — the browser WebSocket API does not expose ping()
setInterval(() => {
  if (websocket.readyState === WebSocket.OPEN) {
    websocket.ping();
  }
}, 60000); // Send ping every 60 seconds
サーバーは ping フレームに自動的に pong フレームで応答し、いずれかのメッセージを受信すると無操作タイマーをリセットします。

接続の終了

接続はクライアントまたはサーバーのどちらからでも WebSocket クローズフレームを使って閉じることができます。 クライアント開始のクローズ:
await websocket.close(code=1000, reason="session completed")
サーバー開始のクローズ: エージェントが通話を終了すると、サーバーは次のように接続を閉じます:
  • コード: 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 イベントを再送してください。