> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thunderphone.com/llms.txt
> Use this file to discover all available pages before exploring further.

# telephony.incoming / web.incoming

> 受信通話の設定をリアルタイムで構成するブロッキングWebhook。

着信電話が**エージェントが割り当てられていない**番号に到達した場合、またはウェブウィジェットセッションが
`mode="webhook"` の公開可能キーで開始された場合、ThunderPhone は
[レガシー webhook URL](/api-reference/organizations#legacy-single-url-webhook) に **ブロッキング**
`telephony.incoming` / `web.incoming` リクエストを送信し、設定レスポンスを最大 **10 秒間**待機します。この
やり取りを使用して、通話ごとにプロンプト、音声、ツールを動的に選択できます。エンドツーエンドのパターンについては、
[動的通話設定ガイド](/ja/guides/dynamic-call-config)を参照してください。

<Note>
  登録済みの [webhook エンドポイント](/ja/webhooks/endpoints)も
  `telephony.incoming` / `web.incoming` を受信します。対象はエージェント設定の有無にかかわらず、**すべての**
  着信通話およびウェブセッションです。ただし、これらの配信は `event_id` を含む
  fire-and-forget 通知であり、ブロッキングではありません。
  このページの設定やり取りを処理するのは、レガシーの単一 URL webhook のみです。エンドポイント通知の形式については、
  [イベントカタログ](/ja/webhooks/events)を参照してください。
</Note>

このブロッキング処理にはフォールバックがありません。ハンドラーが
2xx 以外のステータスを返した場合、タイムアウトした場合、または検証に失敗する設定を返した場合、
通話は拒否されます（電話は接続されず、ウィジェットセッションリクエストは `502`/`422` で失敗します）。
迅速に応答してください。判断中、発信者には呼び出し音が聞こえています。

## リクエストペイロード

電話通話（`telephony.incoming`）の場合：

```json theme={null}
{
  "type": "telephony.incoming",
  "data": {
    "call_id":     987654321,
    "from_number": "+14155550199",
    "to_number":   "+15551234567"
  }
}
```

| フィールド         | 型       | 説明                                   |
| ------------- | ------- | ------------------------------------ |
| `call_id`     | integer | 通話 ID — この通話のすべてのイベントで一貫した値          |
| `from_number` | string  | E.164 形式の発信者番号                       |
| `to_number`   | string  | E.164 形式の宛先番号（ThunderPhone の番号のいずれか） |

ウェブウィジェットセッション（`web.incoming`）では、`data` は電話番号ではなく
埋め込みページを識別します：

```json theme={null}
{
  "type": "web.incoming",
  "data": {
    "call_id": 987654322,
    "origin_domain": "https://example.com",
    "publishable_key_prefix": "pk_live_a1b2"
  }
}
```

| フィールド                          | 型       | 説明                                |
| ------------------------------ | ------- | --------------------------------- |
| `call_id`                      | integer | 通話 ID                             |
| `origin_domain`                | string  | ウィジェットをホストするページのオリジン              |
| `publishable_key_prefix`       | string  | セッションを開始した公開可能キーの先頭文字列            |
| `language`, `primary_language` | string  | ウィジェットセッションで言語オーバーライドが要求された場合に存在  |
| `voice`                        | string  | ウィジェットセッションで音声オーバーライドが要求された場合に存在  |
| `website_context`              | string  | ウィジェットがセッションごとのページコンテキストを渡した場合に存在 |

<Note>
  webhook モードのウィジェットは、設定されている場合は公開可能キー自身の
  `webhook_url` にこのリクエストを配信し、設定されていない場合は組織レベルの
  webhook URL にフォールバックします。いずれの場合も、組織 webhook の `secret` で署名されます。
</Note>

***

## レスポンススキーマ

この通話のエージェント設定を記述する JSON オブジェクトを返します。
`prompt` と `voice` は必須で、その他はすべて任意です。

```json theme={null}
{
  "prompt":  "You are a helpful booking assistant for Acme Restaurant.",
  "voice":   "john",
  "product": "spark",
  "background_track": null,
  "tools":   []
}
```

| フィールド                         | 型               | 必須  | 説明                                                                                                                           |
| ----------------------------- | --------------- | --- | ---------------------------------------------------------------------------------------------------------------------------- |
| `prompt`                      | string          | はい  | エージェントを動作させるシステムプロンプト                                                                                                        |
| `voice`                       | string          | はい  | [`GET /v1/voices`](/api-reference/agents#voices) の音声 ID。例: `john`。`voice_name` はエイリアスとして受け付けられます。不明な音声はバリデーションに失敗し、通話は拒否されます |
| `product`                     | string          | いいえ | デフォルトは `spark`。使用可能: `spark`、`bolt`、`storm-base`、`storm-base-with-ack`、`storm-extra`、`storm-extra-with-ack`                  |
| `thinking_level`              | string          | いいえ | `minimal`、`base`（デフォルト）、または `extra`。Storm 製品では上書きされます。`storm-extra*` は `extra` を強制し、その他の `storm-*` は `base` を強制します           |
| `audio_context_mode`          | string          | いいえ | `full`（デフォルト）または `reduced`                                                                                                   |
| `watchdog_enabled`            | boolean         | いいえ | この通話の監視を有効にします。デフォルトは `false`                                                                                                |
| `storm_feedback_mode`         | string          | いいえ | `none`、`acknowledgement`（デフォルト）、または `tick`                                                                                   |
| `language`                    | string          | いいえ | `primary_language` の短縮指定                                                                                                     |
| `primary_language`            | string          | いいえ | 正規化された言語コード（デフォルトは `en`）。解決できないコードでは通話は拒否されます                                                                                |
| `has_additional_languages`    | boolean         | いいえ | デフォルトは `false`                                                                                                               |
| `additional_languages`        | array of string | いいえ | エージェントが切り替え可能な追加言語                                                                                                           |
| `background_track`            | string \| null  | いいえ | 環境音オーディオ ID または `null`                                                                                                       |
| `acknowledgement_prompt_mode` | string          | いいえ | `auto`（デフォルト）または `manual`（Storm-with-ack 製品）                                                                                 |
| `acknowledgement_prompt`      | string          | いいえ | `acknowledgement_prompt_mode="manual"` の場合に使用されます                                                                            |
| `silence_interval_seconds`    | integer \| null | いいえ | 5～120。発信者が無音になってから確認を行うまでの秒数                                                                                                 |
| `silence_max_checkins`        | integer \| null | いいえ | 1～10                                                                                                                         |
| `silence_checkins_enabled`    | boolean         | いいえ | デフォルトは `true`                                                                                                                |
| `connect_tone_enabled`        | boolean         | いいえ | デフォルトは `false`                                                                                                               |
| `voicemail_action`            | string          | いいえ | `prompt`（デフォルト）、`hangup`、または `message`                                                                                       |
| `voicemail_message`           | string          | いいえ | `voicemail_action="message"` の場合に使用されます                                                                                      |
| `agent_name`                  | string          | いいえ | ダッシュボードとウィジェットに表示される表示名                                                                                                      |
| `org_name`                    | string          | いいえ | エージェントのペルソナに使用する組織の表示名                                                                                                       |
| `tools`                       | array           | いいえ | インライン関数ツールスキーマ（[関数ツール](/ja/tools/overview)を参照）                                                                               |
| `call_id`                     | integer         | いいえ | リクエストの通話 ID を任意でエコーします。無視されます                                                                                                |

<Note>
  不明なトップレベルキーは暗黙的に**無視**されます。フィールド名を
  誤記しても設定は拒否されず、単に適用されません。発話順序と
  `max_hold_seconds` はここでは受け付けられません。これらは
  [エージェント](/api-reference/agents)自体でのみ設定できます。
</Note>

`prompt` と `voice` は必須であるため、`{}` またはバリデーションに失敗する
レスポンスを返すと、通話は `422` で拒否されます。このパスでは
静的エージェントへのフォールバックはありません（Webhook モードの
番号またはキーには、エージェントが割り当てられていません）。

***

## ハンドラーの例

<CodeGroup>
  ```python Python (FastAPI) theme={null}
  import hashlib
  import hmac
  import json
  import os

  from fastapi import FastAPI, HTTPException, Request

  app = FastAPI()
  WEBHOOK_SECRET = os.environ["THUNDERPHONE_WEBHOOK_SECRET"]

  def verify(body: bytes, signature: str) -> bool:
      expected = hmac.new(WEBHOOK_SECRET.encode(), body, hashlib.sha256).hexdigest()
      return hmac.compare_digest(expected, signature or "")

  @app.post("/thunderphone-webhook")
  async def webhook(request: Request):
      body = await request.body()
      if not verify(body, request.headers.get("X-ThunderPhone-Signature", "")):
          raise HTTPException(status_code=401)

      event = json.loads(body)
      if event["type"] == "telephony.incoming":
          caller = event["data"]["from_number"]
          prompt = (
              "Greet the caller as a San Francisco local…"
              if caller.startswith("+1415")
              else "You are a friendly customer support agent…"
          )
          return {
              "prompt": prompt,
              "voice": "john",
              "product": "spark",
          }
      if event["type"] == "web.incoming":
          return {
              "prompt": "You are the website's helpful voice assistant…",
              "voice": "john",
              "product": "spark",
          }
      return {}
  ```

  ```javascript Node.js (Express) theme={null}
  import crypto from "node:crypto";
  import express from "express";

  const app = express();
  const SECRET = process.env.THUNDERPHONE_WEBHOOK_SECRET;

  function verify(body, signature) {
    const expected = crypto
      .createHmac("sha256", SECRET)
      .update(body)
      .digest("hex");
    return signature &&
      crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
  }

  app.post(
    "/thunderphone-webhook",
    express.raw({ type: "application/json" }),
    (req, res) => {
      if (!verify(req.body, req.header("X-ThunderPhone-Signature"))) {
        return res.sendStatus(401);
      }
      const event = JSON.parse(req.body.toString("utf8"));

      if (event.type === "telephony.incoming" || event.type === "web.incoming") {
        const caller = event.data.from_number || "web";
        const prompt = caller.startsWith("+1415")
          ? "Greet the caller as a San Francisco local…"
          : "You are a friendly customer support agent…";
        return res.json({
          prompt,
          voice: "john",
          product: "spark",
        });
      }
      res.json({});
    },
  );
  ```
</CodeGroup>

***

## 関数ツールを含むレスポンス

AI が会話中に API を呼び出せるよう、ツールを追加します。

```json theme={null}
{
  "prompt":  "You are a booking assistant. Use the available tools to help customers schedule appointments.",
  "voice":   "john",
  "product": "spark",
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "search_appointments",
        "description": "Find available appointment slots",
        "parameters": {
          "type": "object",
          "properties": {
            "date": { "type": "string", "description": "YYYY-MM-DD" },
            "service": { "type": "string" }
          },
          "required": ["date"]
        }
      },
      "endpoint": {
        "url": "https://api.example.com/appointments/search",
        "method": "POST",
        "headers": {
          "X-Api-Key": "your-key"
        }
      }
    }
  ]
}
```

<Tip>
  ツールエンドポイントへのリクエストは、この交換を署名したものと**同じ組織の Webhook
  シークレット**で署名されます。正確な形式と署名付きリクエストの
  形式については、[関数ツール](/ja/tools/overview)を参照してください。
</Tip>

***

## プロダクトティア早見表

| プロダクト                  | レイテンシ | 推論   | 確認応答       |
| ---------------------- | ----- | ---- | ---------- |
| `spark`                | 最低    | 基本   | —          |
| `bolt`                 | 低     | 改善済み | —          |
| `storm-base`           | 中     | 高度   | —          |
| `storm-base-with-ack`  | 中     | 高度   | 推論中の自動フィラー |
| `storm-extra`          | 高     | 深い   | —          |
| `storm-extra-with-ack` | 高     | 深い   | 推論中の自動フィラー |

***

## 関連

<CardGroup cols={2}>
  <Card title="telephony.complete / web.complete" icon="phone-slash" href="/ja/webhooks/call-complete">
    通話終了時のノンブロッキングイベント。
  </Card>

  <Card title="関数ツール" icon="screwdriver-wrench" href="/ja/tools/overview">
    `tools[]` の完全なJSONスキーマと署名付きエンドポイント契約。
  </Card>

  <Card title="Webhookエンドポイント" icon="bolt" href="/ja/webhooks/endpoints">
    複数のURLを `telephony.incoming` / `web.incoming` に登録。
  </Card>

  <Card title="動的な通話設定" icon="wand-magic-sparkles" href="/ja/guides/dynamic-call-config">
    発信者ごとのプロンプト、ツール、A/Bテストのパターン。
  </Card>
</CardGroup>
