> ## 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.

# 関数ツール

> AIエージェントが会話中に外部APIを呼び出せるようにします

関数ツールを使用すると、AIエージェントは電話中に外部APIを呼び出せます。顧客データの検索、空き状況の確認、予約の作成、バックエンドでサポートされるあらゆるアクションの実行に使用できます。

## 仕組み

1. スキーマ（ツールが受け入れる引数）を使用してツールを定義します。
2. `endpoint` 設定（ThunderPhoneがAPIを呼び出す場所）を指定するか、省略して組織のWebhookでツール呼び出しを受信します。
3. 通話中、AIは会話に基づいてツールを使用するタイミングを判断します。
4. ThunderPhoneはツール引数を含めてエンドポイントを呼び出します。
5. APIレスポンスがAIに返され、会話を継続します。

<Note>
  関数ツールは、独自のAPIを利用するための方法です。ThunderPhoneには、エンドポイントを必要としないプラットフォーム管理ツールも用意されています。
  [アプリ接続](/ja/guides/connect-apps)（HubSpot、Salesforce、Slack、
  Google Calendar、Google Sheets、Cal.com）、
  [API接続](/ja/guides/api-connections)、および
  [MCPサーバー](/ja/guides/mcp-servers)。
</Note>

***

## ツールスキーマ

各ツールは次の構造に従います。

```json theme={null}
{
  "type": "function",
  "function": {
    "name": "search_appointments",
    "description": "Find available appointment slots for a given date",
    "parameters": {
      "type": "object",
      "properties": {
        "date": {
          "type": "string",
          "description": "Date in YYYY-MM-DD format"
        },
        "service": {
          "type": "string",
          "description": "Type of service (e.g., 'consultation', 'follow-up')"
        }
      },
      "required": ["date"]
    }
  },
  "endpoint": {
    "url": "https://api.example.com/appointments/search",
    "method": "POST",
    "headers": {
      "X-Api-Key": "your-api-key"
    }
  }
}
```

### 関数定義

| フィールド         | 型      | 必須 | 説明                        |
| ------------- | ------ | -- | ------------------------- |
| `name`        | string | はい | ツールの一意の識別子                |
| `description` | string | はい | このツールを使用するタイミングをAIに説明します。 |
| `parameters`  | object | はい | ツール引数のJSONスキーマ            |

### エンドポイント設定

| フィールド     | 型      | 必須  | 説明                      |
| --------- | ------ | --- | ----------------------- |
| `url`     | string | はい  | APIエンドポイントURL           |
| `method`  | string | いいえ | HTTPメソッド（デフォルト: `POST`） |
| `headers` | object | いいえ | 含めるカスタムヘッダー             |

<Note>
  `endpoint` 設定はAIモデルには送信されません。ThunderPhoneがツール呼び出しを実行するためにのみ使用されます。
</Note>

***

## 2つの呼び出し経路

サーバーが受信するリクエストは、ツールに
`endpoint` があるかどうかによって異なります。

|           | `endpoint` **あり**のツール                                                      | `endpoint` **なし**のツール                                                        |
| --------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| リクエストの送信先 | `endpoint.url` に直接送信                                                       | 組織の[レガシーWebhook URL](/api-reference/organizations#legacy-single-url-webhook) |
| ボディ       | **ツール引数のみ**                                                                | `telephony.tool` / `web.tool` エンベロープ                                         |
| ヘッダー      | `endpoint.headers` + `X-ThunderPhone-Call-ID` + `X-ThunderPhone-Signature` | `Content-Type` + `X-ThunderPhone-Signature`                                  |
| 署名キー      | 組織のWebhookシークレット                                                           | 組織のWebhookシークレット                                                             |

どちらの経路も**ブロッキング**です。AIは文の途中で結果を待機し、
タイムアウトは**20 秒**です。ハンドラーは高速に保ってください。
混在させることもできます。組織にWebhook URLが設定されている通話では、
`endpoint` を持つツールは直接呼び出され、残りはWebhookにフォールバックします。

## 直接エンドポイント呼び出し

AI が `endpoint` を持つツールを呼び出すと、ThunderPhone は
指定した URL にリクエストを送信します。

### リクエストヘッダー

```http theme={null}
POST /appointments/search HTTP/1.1
Host: api.example.com
Content-Type: application/json
X-ThunderPhone-Signature: abc123...
X-ThunderPhone-Call-ID: 987654321
X-Api-Key: your-api-key
```

`endpoint.headers` のカスタムヘッダーは常にそのまま含まれ、
加えて ThunderPhone 名前空間の次の 2 つのヘッダーが付与されます。

* `X-ThunderPhone-Signature` — 正確なリクエスト本文のバイト列に対する
  HMAC-SHA256。組織の **Webhook シークレット** をキーとして使用します。
* `X-ThunderPhone-Call-ID` — 現在の通話 ID

`endpoint.headers` で上書きしない限り、
`Content-Type: application/json` が設定されます。カスタムの `Content-Type`
が優先されます。

<Warning>
  署名には、[`GET /v1/webhook`](/api-reference/organizations#legacy-single-url-webhook) の
  組織レベルの Webhook シークレットがキーとして使用されます。
  組織でレガシー Webhook を一度も設定していない場合、シークレットは存在せず、
  ツール呼び出しには `X-ThunderPhone-Call-ID` **のみ**が含まれます。そのため、
  署名がない場合に即座に失敗するハンドラーはリクエストを拒否します。
  シークレットを取得するにはレガシー Webhook を設定するか、
  `endpoint.headers` に独自の共有シークレットを設定してください。
</Warning>

### リクエスト本文

`POST` / `PUT` / `PATCH` の場合、本文にはツール引数**のみ**が
含まれます（ラッパーなし）。正規形式（キーをソートし、区切り文字を圧縮）で
シリアライズされます。

```json theme={null}
{"date":"2025-01-02","service":"consultation"}
```

`GET` / `DELETE` の場合、引数は**クエリパラメーター**として送信され、
本文は空になります。この場合、署名は空のバイト文字列に対して計算されます。
[Webhook 署名を検証する](/ja/guides/verify-webhook-signatures)を参照してください。

### レスポンス

ツール結果を含む JSON レスポンスを返します。

```json theme={null}
{
  "available_slots": ["9:00 AM", "2:00 PM", "4:30 PM"],
  "timezone": "America/Los_Angeles"
}
```

レスポンスは整形され、会話を続けるために AI に渡されます。JSON 以外の
レスポンスは `{"data": "<text>"}` でラップされます。タイムアウトや接続障害は
AI にエラーとして報告されるため、エージェントは停止するのではなく、
謝罪して次に進むことができます。

## Webhook モードのディスパッチ

`endpoint` を持たないツールは、組織のレガシー Webhook URL に対して、
署名付きの `telephony.tool`（電話通話）または `web.tool`（Web 通話）
リクエストとしてディスパッチされます。実行後に Webhook エンドポイントへ配信される
[監査通知](/ja/webhooks/events)とは異なり、このリクエスト**自体が**
実行です。HTTP レスポンスがツール結果になります。

```json theme={null}
{
  "type": "telephony.tool",
  "data": {
    "call_id": 987654321,
    "tool_name": "search_appointments",
    "arguments": { "date": "2026-04-21" },
    "from_number": "+14155550199",
    "to_number": "+15551234567"
  }
}
```

`web.tool` には `from_number` / `to_number` の代わりに
`origin_domain` が含まれます。ツール結果を JSON として返してください。
レスポンスの契約は直接エンドポイント呼び出しと同じです。リクエストは、
他のすべての Webhook と同様に、生の本文に対して組織の Webhook シークレットで
署名されます。

<Note>
  登録済みの [Webhook エンドポイント](/ja/webhooks/endpoints)は、各ツールの実行後
  （実行経路を問わず）に、ツールのレスポンスを含むブロックしない
  `telephony.tool` / `web.tool` **通知も受信します**。監査証跡に役立ちます。
  [イベントカタログ](/ja/webhooks/events)を参照してください。
</Note>

***

## 署名の検証

直接のツール呼び出しは、Webhook と同じ方法で署名されます。

* 正確なリクエスト本文のバイト列に対する HMAC-SHA256（正規化された JSON —
  キーをソートし、余分な空白を含まない形式）
* 組織の Webhook シークレットをキーとして使用
* `GET` / `DELETE` ツールでは空のバイト文字列に署名

<CodeGroup>
  ```python Python theme={null}
  import hmac
  import hashlib

  def verify_tool_call(body: bytes, signature: str, secret: str) -> bool:
      expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
      return hmac.compare_digest(expected, signature)

  @app.post("/appointments/search")
  async def search_appointments(request: Request):
      body = await request.body()
      signature = request.headers.get("X-ThunderPhone-Signature", "")

      if not verify_tool_call(body, signature, WEBHOOK_SECRET):
          raise HTTPException(status_code=401)

      data = json.loads(body)
      date = data["date"]

      # Look up availability
      slots = await get_available_slots(date)

      return {"available_slots": slots}
  ```

  ```javascript Node.js theme={null}
  app.post('/appointments/search', express.raw({type: 'application/json'}), (req, res) => {
    const signature = req.headers['x-thunderphone-signature'] || '';
    const expected = crypto
      .createHmac('sha256', WEBHOOK_SECRET)
      .update(req.body)
      .digest('hex');

    if (!signature ||
        signature.length !== expected.length ||
        !crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) {
      return res.status(401).send('Invalid signature');
    }

    const { date, service } = JSON.parse(req.body);

    // Look up availability
    const slots = getAvailableSlots(date, service);

    res.json({ available_slots: slots });
  });
  ```
</CodeGroup>

空の本文の場合やシークレットがない場合の注意事項を含む完全なレシピは、[Webhook 署名を検証する](/ja/guides/verify-webhook-signatures)を参照してください。

***

## 例: 完全な予約フロー

完全な予約システム向けのツールセットは次のとおりです。

```json theme={null}
{
  "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": "key" }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "book_appointment",
        "description": "Book an appointment at a specific time",
        "parameters": {
          "type": "object",
          "properties": {
            "date": { "type": "string", "description": "YYYY-MM-DD" },
            "time": { "type": "string", "description": "HH:MM format" },
            "customer_name": { "type": "string" },
            "customer_phone": { "type": "string" }
          },
          "required": ["date", "time", "customer_name"]
        }
      },
      "endpoint": {
        "url": "https://api.example.com/appointments/book",
        "method": "POST",
        "headers": { "X-Api-Key": "key" }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "cancel_appointment",
        "description": "Cancel an existing appointment",
        "parameters": {
          "type": "object",
          "properties": {
            "confirmation_number": { "type": "string" }
          },
          "required": ["confirmation_number"]
        }
      },
      "endpoint": {
        "url": "https://api.example.com/appointments/cancel",
        "method": "POST",
        "headers": { "X-Api-Key": "key" }
      }
    }
  ]
}
```

***

## ベストプラクティス

<AccordionGroup>
  <Accordion title="明確な説明を記述する">
    `description` フィールドは、AI がツールを使用する**タイミング**を理解するのに役立ちます。ツールの機能と適切な使用タイミングを具体的に記述してください。
  </Accordion>

  <Accordion title="エラーを適切に処理する">
    汎用的な 500 エラーではなく、AI が理解できるエラーメッセージを返します。例：`{"error": "No slots available for that date"}`
  </Accordion>

  <Accordion title="レスポンスを簡潔に保つ">
    AI が会話を続けるために必要な情報だけを返します。ペイロードが大きいと応答時間が遅くなります。
  </Accordion>

  <Accordion title="必須フィールドを適切に使用する">
    本当に必要な場合にのみフィールドを `required` としてマークします。AI はツールを呼び出す前に、必須情報をユーザーに確認します。
  </Accordion>
</AccordionGroup>

***

## 関連項目

<CardGroup cols={2}>
  <Card title="アプリ接続" icon="plug" href="/ja/guides/connect-apps">
    HubSpot、Salesforce、Slack、Google
    Calendar、Google Sheets、Cal.com 向けのプラットフォーム管理ツール。エンドポイントは不要です。
  </Card>

  <Card title="MCP サーバー" icon="server" href="/ja/guides/mcp-servers">
    MCP サーバーを接続し、エージェントからそのツールを呼び出せます。
  </Card>

  <Card title="API 接続" icon="code" href="/ja/guides/api-connections">
    エージェントに接続できる再利用可能な REST 統合です。
  </Card>

  <Card title="Webhook 署名を検証する" icon="shield-check" href="/ja/guides/verify-webhook-signatures">
    Webhook とツール呼び出しのための検証ヘルパーです。
  </Card>
</CardGroup>
