> ## 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) або не вказуйте її, щоб отримувати виклики інструментів через вебхук вашої організації
3. Під час розмови AI вирішує, коли використовувати інструмент, на основі діалогу
4. ThunderPhone викликає ваш endpoint з аргументами інструмента
5. Відповідь вашого API повертається AI для продовження діалогу

<Note>
  Інструменти функцій — це шлях із використанням власного API. ThunderPhone також
  надає керовані платформою інструменти, яким не потрібен endpoint:
  [підключення застосунків](/uk/guides/connect-apps) (HubSpot, Salesforce, Slack,
  Google Calendar, Google Sheets, Cal.com),
  [підключення API](/uk/guides/api-connections) і
  [сервери MCP](/uk/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 Schema для аргументів інструмента          |

### Конфігурація endpoint

| Поле      | Тип    | Обов’язково | Опис                                        |
| --------- | ------ | ----------- | ------------------------------------------- |
| `url`     | string | Так         | URL endpoint вашого API                     |
| `method`  | string | Ні          | HTTP-метод (за замовчуванням: `POST`)       |
| `headers` | object | Ні          | Спеціальні заголовки, які потрібно включити |

<Note>
  Конфігурація `endpoint` **не** надсилається моделі AI — ThunderPhone використовує її лише для виконання виклику інструмента.
</Note>

***

## Два шляхи виклику

Який запит отримає ваш сервер, залежить від того, чи має інструмент
`endpoint`:

|                         | Інструмент **з** `endpoint`                                                     | Інструмент **без** `endpoint`                                                                         |
| ----------------------- | ------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| Куди надсилається запит | Безпосередньо до `endpoint.url`                                                 | На [застарілий 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`                                                           |
| Ключ підпису            | Секрет вебхука організації                                                      | Секрет вебхука організації                                                                            |

Обидва шляхи є **блокувальними** — AI очікує результат посеред речення —
із тайм-аутом **20 с**. Обробники мають працювати швидко. Можна використовувати
поєднання: під час розмови, для якої організація має URL вебхука, інструменти з
`endpoint` викликаються безпосередньо, а решта використовують вебхук.

## Прямі виклики endpoint

Коли ШІ викликає інструмент, що має `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:

* `X-ThunderPhone-Signature` — HMAC-SHA256 точних байтів тіла запиту
  з ключем — вашим **секретом webhook організації**
* `X-ThunderPhone-Call-ID` — ID поточного дзвінка

`Content-Type: application/json` установлюється, якщо його не перевизначено у вашому `endpoint.headers`
— користувацький `Content-Type` має пріоритет.

<Warning>
  Підпис створюється з використанням секрету webhook на рівні організації з
  [`GET /v1/webhook`](/api-reference/organizations#legacy-single-url-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](/uk/guides/verify-webhook-signatures).

### Відповідь

Поверніть JSON-відповідь із результатом інструмента:

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

Відповідь форматується й передається ШІ для продовження
розмови. Відповіді не у форматі JSON обгортаються як `{"data": "<text>"}`;
тайм-аути та помилки з’єднання повідомляються ШІ як помилки, тож
агент може перепросити й продовжити, а не зависати.

## Диспетчеризація в режимі webhook

Інструменти **без** `endpoint` надсилаються на застарілу URL-адресу
webhook вашої організації як підписаний запит `telephony.tool` (телефонні дзвінки) або `web.tool`
(вебвиклики). На відміну від [сповіщень аудиту](/uk/webhooks/events),
що доставляються до endpoint webhook після виконання, цей запит **є**
виконанням — ваша 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` містить `origin_domain` замість `from_number` /
`to_number`. Відповідайте результатом інструмента у форматі JSON — це той самий контракт
відповіді, що й для прямих викликів endpoint. Запит підписується секретом webhook
організації для необробленого тіла, як і всі інші webhook.

<Note>
  Підписані [endpoint webhook](/uk/webhooks/endpoints) додатково
  отримують неблокувальне **сповіщення** `telephony.tool` / `web.tool`
  **після** виконання кожного інструмента (незалежно від шляху його виконання), зокрема
  відповідь інструмента — це корисно для журналів аудиту. Див.
  [каталог подій](/uk/webhooks/events).
</Note>

***

## Перевірка підпису

Прямі виклики інструментів підписуються так само, як вебхуки:

* HMAC-SHA256 для точних байтів тіла запиту (канонічний JSON —
  ключі відсортовано, без зайвих пробілів)
* З використанням секрету вебхука вашої організації
* Інструменти `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>

Повні приклади — зокрема випадок із порожнім тілом і застереження щодо відсутності секрету —
наведено в розділі [Перевірка підписів вебхуків](/uk/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` допомагає ШІ зрозуміти, **коли** використовувати інструмент. Чітко вкажіть, що він робить і коли його доречно застосовувати.
  </Accordion>

  <Accordion title="Коректно обробляйте помилки">
    Повертайте повідомлення про помилки, зрозумілі для ШІ: `{"error": "No slots available for that date"}` замість загальних помилок 500.
  </Accordion>

  <Accordion title="Зберігайте відповіді лаконічними">
    Повертайте лише те, що потрібно ШІ для продовження розмови. Великі корисні навантаження сповільнюють час відповіді.
  </Accordion>

  <Accordion title="Зважено використовуйте обов’язкові поля">
    Позначайте поля як `required` лише за справжньої потреби. Перед викликом інструмента ШІ попросить користувача надати обов’язкову інформацію.
  </Accordion>
</AccordionGroup>

***

## Пов’язані матеріали

<CardGroup cols={2}>
  <Card title="Підключення застосунків" icon="plug" href="/uk/guides/connect-apps">
    Інструменти платформи для HubSpot, Salesforce, Slack, Google
    Calendar, Google Sheets і Cal.com — кінцева точка не потрібна.
  </Card>

  <Card title="Сервери MCP" icon="server" href="/uk/guides/mcp-servers">
    Підключіть сервер MCP і дозвольте агенту викликати його інструменти.
  </Card>

  <Card title="Підключення API" icon="code" href="/uk/guides/api-connections">
    Багаторазові REST-інтеграції, які можна підключати до агентів.
  </Card>

  <Card title="Перевірка підписів вебхуків" icon="shield-check" href="/uk/guides/verify-webhook-signatures">
    Один допоміжний засіб перевірки для вебхуків і викликів інструментів.
  </Card>
</CardGroup>
