> This is a page from the ElevenLabs documentation. For an index of the documentation, fetch https://elevenlabs.io/docs/llms.txt.

# Voximplant

> **Warning**
>
> Voximplantインテグレーションは限定提供中で、ワークスペースごとに有効化されます。顧客のトラフィックをルーティングする前に、
> ElevenLabsの担当者へお問い合わせください。

## 概要

Voximplantインテグレーションは、Voximplant Media Streamsを使用し、VoxEngineシナリオ内の通話を
WebSocket経由でElevenAgentsのエージェントに直接接続します。電話機能はVoximplantが担います。
通話の発信や応答、その後の処理を制御します。会話はElevenAgentsが担います。
SIPトランクやミドルウェアは必要ありません。

着信通話と発信通話の仕組みは同じです。通話が接続されると、シナリオは通話ごとにElevenLabsへの
WebSocketを1つ開きます。会話が終了すると、ElevenLabsは、人間の担当者に転送するか、通話を終了するか、
タイムアウトとして処理するかを示す単一の決定イベントをシナリオに送信します。

## インテグレーションの仕組み

1. VoxEngineシナリオが着信通話に応答するか、発信通話を開始します。
2. シナリオがエージェント用のElevenLabsエンドポイントへのWebSocketを開き、
   ElevenLabs APIキーをBearerトークンとして使用して認証します。
3. シナリオが`call.sendMediaTo()`でメディアストリームを開始し、任意の`customParameters`を渡します。
   ElevenLabsは各パラメーターを動的変数に変換し、独自の`start`で応答します。
4. VoximplantとElevenLabsが、`media`メッセージで8 kHzの16ビットリニアPCMオーディオを交換します。
5. 会話が終了すると、ElevenLabsはエージェントの最後のフレーズの残り、1つの
   `elevenlabs-decision`カスタムイベント、`stop`メッセージを送信します。その後、シナリオがWebSocketを閉じ、
   決定に従って処理します。

## 要件

開始する前に、以下を用意してください。

1. アプリケーション、電話番号または発信通話機能、シナリオを編集する権限があるVoximplantアカウント。
2. Voximplantインテグレーションが有効なElevenLabsワークスペース。
3. ElevenLabsエージェントと専用のAPIキー。

## ElevenLabsを設定する

#### エージェントを作成または選択する

ElevenAgentsでエージェントを作成します。通話の接続直後に話し始める必要がある場合は、最初のメッセージを設定してください。
オーディオ形式はインテグレーションによって設定されるため、エージェントに設定された形式は
Voximplant通話には使用されません。

#### 通話終了を有効にする

**エージェント → ツール → システムツール** で **通話終了** を有効にし、エージェントが会話を終了できるようにします。
エージェントが通話終了時に示した理由は、決定とともにシナリオへ送信されます。

#### Voximplant転送ルールを追加する（任意）

エージェントが発信者を人間の担当者へ転送できるようにするには、プロバイダー設定が`voximplant`の
転送ルールとともに **番号へ転送** システムツールを追加します。このルールには転送先がありません。
会話は`transfer-to-agent`の決定で終了し、シナリオが発信者をルーティングします。転送ルールは
APIで設定します。エージェントに`PATCH`を送信してツールを追加します。

```bash
curl -X PATCH "https://api.elevenlabs.io/v1/convai/agents/agent_7101k5zvyjhmfg983brhmhkd98n6" \
  -H "xi-api-key: $ELEVENLABS_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "conversation_config": {"agent": {"prompt": {"built_in_tools": {
      "end_call": {"type": "system", "name": "end_call", "description": "",
                   "params": {"system_tool_type": "end_call"}},
      "transfer_to_number": {
        "type": "system", "name": "transfer_to_number", "description": "",
        "params": {
          "system_tool_type": "transfer_to_number",
          "transfers": [],
          "transfer_rules": [{
            "condition": "the caller asks to speak with a human",
            "provider_configs": [
              {"type": "voximplant", "config": {"type": "voximplant_handoff"}}
            ]
          }]
        }
      }
    }}}}
  }'
```

`end_call`など、エージェントがすでに持っているツールを含む完全な`built_in_tools`オブジェクトを送信します。
エージェントが返す選択肢は固定トークン`voximplant`なので、ツールごとにVoximplantルールが1つあれば
十分です。他のプロバイダー向けに設定された電話番号やSIP URIは、Voximplant通話では提示されません。

> **Note**
>
> 転送ルールはAPIで管理する設定です。上記のように、転送ルールを使用するエージェントの
> **番号へ転送** ツールはAPIで設定・更新してください。ダッシュボードのツールエディターは、
> 電話番号ごとの転送リストに対応しています。

#### 専用のAPIキーを作成する

エージェントと同じワークスペースでAPIキーを作成し、スコープをElevenAgentsに設定します。
Voximplantからの接続のみを許可するには、キーで許可するIPアドレスをVoximplantのメディアサーバーに制限します。
Voximplantのメディアサーバーは
`https://api.voximplant.com/getMediaResources?with_mediaservers`に掲載されています。

#### WebSocket URLを確認する

シナリオは、エージェントIDを含むURLに接続します。

| 環境        | URL                                                                                                               |
| --------- | ----------------------------------------------------------------------------------------------------------------- |
| デフォルト     | `wss://api.elevenlabs.io/v1/convai/conversation/voximplant/agent_7101k5zvyjhmfg983brhmhkd98n6`                    |
| データレジデンシー | `wss://api.<region>.residency.elevenlabs.io/v1/convai/conversation/voximplant/agent_7101k5zvyjhmfg983brhmhkd98n6` |

エージェントのブランチを固定するには、`?branch_id=<branch_id>`を追加します。

> **Info**
>
> ElevenLabsアカウントが分離されたレジデンシー環境にある場合は、`<region>`を
> リージョンコードに置き換えてください。利用可能なリージョンについては、[データレジデンシー](/docs/ja/overview/administration/data-residency)を参照してください。

## Voximplantを設定する

#### アプリケーションを作成する

[Voximplantコントロールパネル](https://manage.voximplant.com/applications)で **アプリケーション** を開き、
**アプリケーションを作成** をクリックします。`elevenlabs-agent`などの名前を付け、
**作成** をクリックします。

![Voximplant：アプリケーションを作成](/docs/_fern-files/_img/29af341fa0a32eaaab444ade8305208121487413c5868597386a973b14fe4fe7.webp)

#### APIキーをシークレットとして保存する

アプリケーションで **シークレット** を開き、**シークレットを追加** をクリックします。名前を`ELEVENLABS_API_KEY`にし、
エージェントのワークスペース用に作成したAPIキーを **値** に貼り付けて、**シークレットを追加** をクリックします。
シナリオは`VoxEngine.getSecretValue()`でAPIキーを読み取るため、シナリオコードにキーが表示されることはありません。

![Voximplant：シークレットを追加](/docs/_fern-files/_img/ecf8be823bbc15b263e3f4838684a78de3a3594704be0055b443d15ab93e1485.webp)

#### シナリオを作成する

**シナリオ** を開いて **シナリオを作成** をクリックし、`elevenlabs_agent`という名前を付けます。以下のコードを貼り付け、
`ELEVENLABS_URL`内のエージェントIDを置き換えて、**保存** をクリックします。このシナリオは着信通話に応答し、
エージェントへストリーミングして、会話終了時に決定に従って処理します。発信通話の場合は、発信した通話の
`CallEvents.Connected`ハンドラー内でWebSocketを開きます。

```javascript maxLines=0
const ELEVENLABS_URL =
  "wss://api.elevenlabs.io/v1/convai/conversation/voximplant/agent_7101k5zvyjhmfg983brhmhkd98n6";

VoxEngine.addEventListener(AppEvents.CallAlerting, ({ call }) => {
  call.answer();
  let decision = null;

  const ws = VoxEngine.createWebSocket(ELEVENLABS_URL, {
    headers: [
      {
        name: "Authorization",
        value: `Bearer ${VoxEngine.getSecretValue("ELEVENLABS_API_KEY")}`,
      },
    ],
  });

  ws.addEventListener(WebSocketEvents.OPEN, () => {
    call.sendMediaTo(ws, {
      encoding: WebSocketAudioEncoding.PCM16_8KHZ,
      customParameters: { customer_name: "Ana", task_id: "task-7" },
    });
    ws.sendMediaTo(call);
  });

  ws.addEventListener(WebSocketEvents.MESSAGE, ({ text }) => {
    const message = JSON.parse(text);
    if (message.customEvent === "elevenlabs-decision") {
      decision = message.payload;
      Logger.write(`ElevenLabs decision: ${JSON.stringify(decision)}`);
    }
  });

  ws.addEventListener(WebSocketEvents.CLOSE, (e) => {
    Logger.write(`ElevenLabs socket closed: code=${e.code} reason=${e.reason}`);
    if (decision?.action === "transfer-to-agent") {
      // Route the caller to a human here, for example with VoxEngine.callPSTN().
      call.say("Connecting you to an agent.", { language: VoiceList.Amazon.en_US_Joanna });
      call.addEventListener(CallEvents.PlaybackFinished, () => call.hangup());
      return;
    }
    call.hangup();
  });

  call.addEventListener(CallEvents.Disconnected, () => {
    ws.close();
    VoxEngine.terminate();
  });
});
```

![Voximplant：エディター内のシナリオ](/docs/_fern-files/_img/d2e26165f57cae40fc01e8de28052fef09b2f98bd90c0e1a8779423715f61e2e.webp)

#### 通話をシナリオへルーティングする

**ルーティング** を開き、**ルールを作成** をクリックして名前を付け、`elevenlabs_agent`
シナリオを割り当てます。デフォルトのパターン`.*`では、すべての通話がシナリオ経由でアプリケーションへ送信されます。
アプリケーションが他の通話も処理する場合は、対象を電話番号に絞り込んでください。電話番号をルーティングするには、
**番号** でアプリケーションに割り当てます。

![Voximplant：ルールを作成](/docs/_fern-files/_img/bc6830b7dcd66dc0b59595456b1197bdcbb9174f15778da7ba9655ba4b93936e.webp)

#### テスト通話を発信する

電話番号がなくても、ブラウザからアプリケーションへ発信できます。

1. **ユーザー** を開き、**ユーザーを作成** をクリックして、パスワード付きのユーザーを作成します。

   ![Voximplant：新規ユーザー](/docs/_fern-files/_img/4754c9234588fd0caa336e1168e207b265557dc4e6a12b1cf8bced1275b8bae6.webp)

2. **ルーティング** で **テストツール**、**ソフトフォン** の順にクリックします。そのユーザーとしてサインインし、
   マイクへのアクセスを許可して、任意の宛先を入力して発信します。エージェントが最初のメッセージで応答します。

3. 通話が終了したら、**通話履歴** を開きます。各通話には、通話自体の横にWebSocketレッグが表示されます。
   **ログを表示** をクリックしてセッションを確認します。

   ![Voximplant：通話履歴](/docs/_fern-files/_img/4e2416ad3587bb320300173cf679f7c5d7a5e545550b0a647062a79866dac40c.webp)

   ログには、ElevenLabsが送信した決定、WebSocketの切断、その後にシナリオが実行した処理が表示されます。
   この例では発信者が人間の担当者を求めたため、決定は`transfer-to-agent`となり、
   エージェントが示した理由も含まれています。

   ![Voximplant：elevenlabs-decisionイベントを含む
   セッションログ](/docs/_fern-files/_img/f8b4602fa02cfd3c417557377aaa5dd66e2e88a67e7adf4cb037ccae1840f45c.webp)

> **Warning**
>
> `MEDIA_ENDED`ではなく、`elevenlabs-decision`イベントに基づいて処理してください。VoximplantはElevenLabsからの
> オーディオが約1秒間途切れると`MEDIA_ENDED`を発生させますが、これは会話の途中でも起こる可能性があります。

## 動的変数

`customParameters`の各キーは、同じ名前の動的変数になります。文字列でない値はテキストに変換されます。
たとえば、`true`は`"true"`になります。`customParameters`にはオブジェクトまたはJSONエンコードされた文字列を指定できます。
`system__`または`integration__`で始まるキーは予約されており、破棄されます。

## 決定イベント

会話が終了すると、ElevenLabsは`stop`メッセージの前に決定を1つだけ送信します。

```json
{ "customEvent": "elevenlabs-decision", "payload": { "action": "terminate", "reason": "under_18" } }
```

| `action`            | 送信されるタイミング                                                                              | `reason`                      |
| ------------------- | --------------------------------------------------------------------------------------- | ----------------------------- |
| `transfer-to-agent` | エージェントがVoximplant転送ルールを使用して **番号へ転送** を呼び出したとき。                                         | エージェントが示した転送理由。               |
| `timeout`           | 無音またはエージェントの最後のメッセージ後に会話がタイムアウトしたとき、あるいはエージェントの発話時間を除き、発信者が15秒間無言だったためエージェントが通話を終了したとき。 | タイムアウトメッセージ、またはエージェントが示した理由。  |
| `terminate`         | エージェントが **通話終了** で通話を終了したとき、または会話が正常に終了したとき。                                            | **通話終了** でエージェントが示した理由（ある場合）。 |
| `unexpected`        | エラーが原因で会話が終了したとき。                                                                       | エラーの説明。                       |

発信者が通話を切った場合など、シナリオが先に`stop`を送信するかWebSocketを閉じた場合、
ElevenLabsは決定を送信しません。

## オーディオ

VoximplantとElevenLabsは、双方向で8 kHzの16ビットモノラルリニアPCMを交換します。ElevenLabsは
エージェントのオーディオをほぼリアルタイムで送信するため、発信者がエージェントの発話に割り込んでも、
中断された応答が再生され続けるのは最大約0.4秒です。

## 認証エラー

`Authorization`ヘッダーがない、または形式が不正な場合、APIキーが無効または接続元IPアドレスからの使用を許可されていない場合、
キーが別のワークスペースに属している場合、あるいはキーのユーザーが認証を有効にしたエージェントへアクセスできない場合、
ElevenLabsはコード`1008`、理由`bad auth token`でWebSocketを閉じます。

## 制限事項と未対応の機能

* クライアントツールと **キーパッドのタッチトーンを再生** システムツールには対応していません。**番号へ
  転送** はVoximplant転送ルールでのみ機能し、発信者の転送先はシナリオが決定します。
* 最初のメッセージの変更など、設定のオーバーライドをシナリオから渡すことはできません。
  渡せるのは動的変数のみです。
* データ収集結果はシナリオに送信されません。結果には
  [通話後Webhook](/docs/ja/eleven-agents/workflows/post-call-webhooks)を使用してください。