---
title: "Інструменти функцій"
description: "Надайте своїм ШІ-агентам інструменти функцій, які викликають зовнішні API під час розмови — отримують дані клієнтів, бронюють зустрічі, оновлюють записи — із типізованими параметрами."
---

Інструменти функцій дають вашим AI-агентам змогу викликати зовнішні API під час телефонних дзвінків. Використовуйте їх для пошуку даних клієнтів, перевірки доступності, бронювання зустрічей або виконання будь-яких дій, які підтримує ваш бекенд.

## Як це працює

1. Визначте інструменти за допомогою схеми (які аргументи приймає інструмент)
2. Надайте конфігурацію `endpoint` (куди ThunderPhone викликає ваш API) — або не вказуйте її, щоб отримувати виклики інструментів на вебхуку вашої організації
3. Під час дзвінка AI вирішує, коли використовувати інструмент, на основі розмови
4. ThunderPhone викликає вашу кінцеву точку з аргументами інструменту
5. Відповідь вашого API передається AI для продовження розмови

| Можливість | Де виконується | Налаштування |
| --- | --- | --- |
| [Вбудовані інструменти](/uk/guides/built-in-tools) | ThunderPhone | Інструкції в промпті; для деяких інструментів також потрібне налаштування агента |
| [Підключення застосунків](/uk/guides/connect-apps) | ThunderPhone і підключений провайдер | Підключіть обліковий запис і додайте схвалені дії |
| [Підключення API](/uk/guides/api-connections) та інструменти функцій | Ваш HTTP API | Визначте кінцеву точку та схему або отримуйте виклики функцій через вебхук |
| [Сервери MCP](/uk/guides/mcp-servers) | Віддалений сервер MCP | Додайте сервер, знайдіть його інструменти та підключіть його до агента |

---

## Схема інструменту

Кожен інструмент має таку структуру:

```json
{
  "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"
    }
  },
  "timeout": 120
}
```

### Конфігурація інструменту

| Поле | Тип | Обов’язково | Опис |
|-------|------|----------|-------------|
| `timeout` | число | Ні | Максимальний час виконання в секундах (за замовчуванням: `20`, максимум: `180`) |

### Визначення функції

| Поле | Тип | Обов’язково | Опис |
|-------|------|----------|-------------|
| `name` | рядок | Так | Унікальний ідентифікатор інструменту |
| `description` | рядок | Так | Пояснює AI, коли використовувати цей інструмент |
| `parameters` | об’єкт | Так | JSON Schema для аргументів інструменту |

### Конфігурація кінцевої точки

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

<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-V2` + `X-ThunderPhone-Signature` | `Content-Type` + `X-ThunderPhone-Signature-V2` + `X-ThunderPhone-Signature` |
| Ключ підпису | Секрет вебхука організації | Секрет вебхука організації |

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

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

Коли ШІ викликає інструмент, що має `endpoint`, ThunderPhone надсилає
запит на вашу URL-адресу:

### Заголовки запиту

```http
POST /appointments/search HTTP/1.1
Host: api.example.com
Content-Type: application/json
X-ThunderPhone-Signature-V2: t=1767225600,v1=5f2c...
X-ThunderPhone-Signature: abc123...
X-ThunderPhone-Call-ID: 987654321
X-Api-Key: your-api-key
```

Користувацькі заголовки з `endpoint.headers` завжди додаються
дослівно, а також ці заголовки з простором імен ThunderPhone:

- `X-ThunderPhone-Signature-V2` — HMAC-SHA256 із позначкою часу для
  методу, шляху, параметрів запиту й тіла, підписаний вашим **секретом вебхука організації**.
  Перевіряйте цей заголовок і відхиляйте запити, яким понад 5 хвилин; див.
  [Перевірка підписів вебхуків](/uk/guides/verify-webhook-signatures)
- `X-ThunderPhone-Signature` — застарілий HMAC-SHA256 точних байтів
  тіла запиту з тим самим ключем, який і далі надсилається для наявних засобів перевірки
- `X-ThunderPhone-Call-ID` — Ідентифікатор поточного дзвінка

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

<Warning>
  Підпис обчислюється із секретом вебхука на рівні організації з
  [`GET /v1/webhook`](/api-reference/organizations#legacy-single-url-webhook).
  Якщо ваша організація ніколи не налаштовувала застарілий вебхук, секрету
  немає, і виклики інструментів містять **лише** `X-ThunderPhone-Call-ID` —
  обробник, який завершується помилкою за відсутності підпису, відхилить їх.
  Або налаштуйте застарілий вебхук, щоб отримати секрет, або додайте власний
  спільний секрет у `endpoint.headers`.
</Warning>

### Формат запиту

Кожне API-підключення має налаштування `request_format`. Виберіть `vapi` або
`retell`, якщо імпортований інструмент має й надалі викликати ендпойнт, створений для
цієї платформи. Для нових і наявних підключень за замовчуванням використовується `standard`.

Для `POST` / `PUT` / `PATCH` ThunderPhone серіалізує вибраний
конверт канонічно (відсортовані ключі, компактні роздільники). Обидва підписи
охоплюють саме ці байти.

#### Standard

`standard` надсилає лише аргументи інструмента без обгортки. Це значення за замовчуванням, яке зберігає оригінальне тіло запиту ThunderPhone байт у байт:

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

#### Vapi

`vapi` надсилає [серверне повідомлення `tool-calls`](https://docs.vapi.ai/tools/custom-tools) Vapi
у форматі, задокументованому Vapi. `call.id` — це ID виклику ThunderPhone. ID
виклику інструмента `id` є унікальним для виклику та повторно використовується для зіставлення
результату ендпойнта. Виклик відображається і в `toolCallList`, і в
`toolWithToolCallList`, а `function.arguments` є JSON-об’єктом:

```json
{
  "message": {
    "type": "tool-calls",
    "timestamp": 1725000000123,
    "call": { "id": "987654321" },
    "toolCallList": [
      {
        "id": "call_00112233445566778899aabbccddeeff",
        "type": "function",
        "function": {
          "name": "search_appointments",
          "arguments": { "date": "2025-01-02", "service": "consultation" }
        }
      }
    ],
    "toolWithToolCallList": [
      {
        "type": "function",
        "function": { "name": "search_appointments" },
        "toolCall": {
          "id": "call_00112233445566778899aabbccddeeff",
          "type": "function",
          "function": {
            "name": "search_appointments",
            "arguments": { "date": "2025-01-02", "service": "consultation" }
          }
        }
      }
    ]
  }
}
```

Поля лише для Vapi, як-от `assistant`, `artifact` і повний об’єкт `call`,
не надсилаються.

Поверніть конверт відповіді Vapi з відповідним ID виклику інструмента:

```json
{
  "results": [
    {
      "toolCallId": "call_00112233445566778899aabbccddeeff",
      "result": "{\"available_slots\":[\"9:00 AM\",\"2:00 PM\"]}"
    }
  ]
}
```

ThunderPhone передає ШІ розгорнутий рядок `result`. Також підтримується
значення JSON для сумісності з ендпойнтами, які вже його повертають. `error`
замість `result` повертається ШІ як помилка інструмента. Якщо ендпойнт повертає
некоректний або невідповідний конверт Vapi, ThunderPhone записує
попередження в журнал і повертається до стандартного аналізу відповіді замість того, щоб завершити
виклик помилкою.

#### Retell

`retell` надсилає запит, задокументований для [користувацької функції Retell](https://docs.retellai.com/build/single-multi-prompt/custom-function):

```json
{
  "name": "search_appointments",
  "call": { "call_id": "987654321" },
  "args": { "date": "2025-01-02", "service": "consultation" }
}
```

Об’єкт `call` містить лише `call_id`. ThunderPhone не включає
специфічні для Retell поля, які він не може достовірно надати під час надсилання, як-от
`agent_id`, `transcript`, `transcript_object`, `metadata` або динамічні
змінні. Retell приймає будь-яке тіло відповіді; ThunderPhone передає його
без змін, використовуючи стандартну обробку відповіді.

Для `GET` / `DELETE` аргументи надсилаються як **параметри запиту**,
а тіло залишається порожнім незалежно від `request_format`. Підпис V2
охоплює рядок запиту в надісланому вигляді; застарілий підпис обчислюється для
порожнього рядка байтів. Див.
[Перевірка підписів вебхуків](/uk/guides/verify-webhook-signatures).

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

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

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

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

## Маршрутизація в режимі вебхука

Інструменти **без** `endpoint` надсилаються на застарілу URL-адресу
вебхука вашої організації як підписаний запит `telephony.tool` (телефонні
виклики) або `web.tool` (вебвиклики). На відміну від
[сповіщень аудиту](/uk/webhooks/events), що доставляються до endpoint вебхуків
після виконання, цей запит **є** виконанням — ваша HTTP-відповідь є
результатом інструмента.

```json
{
  "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 — за тим самим контрактом відповіді, що й для прямих викликів кінцевих точок. Запит підписано секретом вебхука організації та містить обидва заголовки підпису, як і кожен інший вебхук.

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

---

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

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

- `X-ThunderPhone-Signature-V2` підписує позначку часу, метод, шлях і параметри запиту в надісланому вигляді, а також точні байти тіла. Відхиляйте запити, позначка часу яких відрізняється від вашого часу більш ніж на 5 хвилин.
- `X-ThunderPhone-Signature` (застарілий) підписує лише байти тіла; для `GET` / `DELETE` використовується порожній рядок байтів. Він досі надсилається без змін.

Допоміжні функції SDK перевіряють заголовок V2, зокрема 5-хвилинне вікно:

<CodeGroup>
```python Python
import json

from fastapi import FastAPI, HTTPException, Request
from thunderphone import verify_signature

app = FastAPI()

@app.post("/appointments/search")
async def search_appointments(request: Request):
    body = await request.body()
    query = request.scope.get("query_string", b"").decode("latin-1")
    path = request.url.path + (f"?{query}" if query else "")

    if not verify_signature(
        request.headers.get("X-ThunderPhone-Signature-V2"),
        secret=WEBHOOK_SECRET,
        method=request.method,
        path=path,
        body=body,
    ):
        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
import express from "express";
import { verifySignature } from "@thunderphone/sdk";

app.post('/appointments/search', express.raw({type: 'application/json'}), (req, res) => {
  const ok = verifySignature({
    header: req.header('X-ThunderPhone-Signature-V2'),
    secret: WEBHOOK_SECRET,
    method: req.method,
    path: req.originalUrl,
    body: req.body,
  });
  if (!ok) 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>

Повні приклади — підписуваний рядок, покроковий приклад, код без SDK, випадок `GET` / `DELETE` і застереження щодо відсутності секрету — наведено в розділі [Перевірка підписів вебхуків](/uk/guides/verify-webhook-signatures).

---

## Приклад: повний процес запису

Ось набір інструментів для повноцінної системи запису на прийом:

```json
{
  "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="wrench" href="/uk/guides/built-in-tools">
    Налаштовуйте дії з викликами, якими керує платформа, без визначення кінцевої точки.
  </Card>
  <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>
