---
title: "Создание интеграции с инструментом (API)"
description: "Позвольте вашему агенту вызывать ваши API прямо во время разговора: искать в базе данных, создавать заявку, находить заказ."
---

Интеграция **инструмента** — это повторно используемая HTTP-конечная точка, которую агент может
вызывать во время звонка. Вы передаёте ThunderPhone описание инструмента в формате JSON Schema
и URL конечной точки; агент решает, когда вызывать её, на основе разговора, а ThunderPhone выполняет
исходящий HTTP-запрос со своих серверов и возвращает ответ агенту.

<Note>
  Панель управления покрывает большинство задач с инструментами без этого API: **Подключения
  → Приложения** подключает Slack, HubSpot, Salesforce, Google Calendar,
  Google Sheets и Cal.com несколькими нажатиями OAuth; **Подключения →
  API** превращает любой HTTP API в действие агента (вставьте команду cURL,
  и ИИ-мастер создаст черновик инструмента со встроенным элементом управления «Тестовый запрос»); а
  **Подключения → MCP** добавляет MCP-серверы. См.
  [Подключения](/ru/guides/concepts). Это руководство посвящено базовому
  API, лежащему в основе раздела API.
</Note>

В этом руководстве пошагово рассматривается создание инструмента для получения прогноза погоды.

## Устройство инструмента

Две части:

1. **Схема** — определение функции в стиле OpenAI
   (`{type: "function", function: {name, description, parameters}}`),
   которое сообщает LLM, что делает инструмент и какие аргументы он принимает.
2. **Конечная точка** — URL, который серверы ThunderPhone вызывают, когда
   LLM решает использовать инструмент. Запрос — это JSON POST с
   выбранными LLM аргументами в теле.

## 1. Выберите редактор

<CardGroup cols={2}>
  <Card title="Панель управления" icon="window-maximize">
    Откройте **Подключения → API**, создайте или отредактируйте API-подключение,
    переключите редактор параметров на **JSON** и добавьте туда формат.
  </Card>
  <Card title="API интеграций" icon="plug">
    Создайте спецификацию с помощью `POST /v1/integrations` или обновите её с помощью
    `PATCH /v1/integrations/{id}`.
  </Card>
</CardGroup>

Оба пути создают сохранённую интеграцию. После сохранения подключите эту интеграцию к
агенту. В API агентов нет доступного для записи встроенного поля `tools`.
В этом руководстве используется путь через API интеграций.

## 2. Создайте интеграцию

```bash
curl -X POST https://api.thunderphone.com/v1/integrations \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "display_name": "Weather API",
    "spec": {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Return the current weather for a zip code.",
        "parameters": {
          "type": "object",
          "properties": {
            "zip": { "type": "string", "description": "5-digit US ZIP code" }
          },
          "required": ["zip"]
        }
      }
    },
    "endpoint_url":    "https://api.example.com/weather",
    "endpoint_method": "GET",
    "headers": [
      { "key": "X-Api-Key", "value": "your-provider-key" }
    ]
  }'
```

Сохраните возвращённый `id` (UUID). Значения заголовков доступны только для записи: в ответах перечисляются только имена заголовков, а последующий `PATCH` может отправить заголовок без `value`, чтобы сохранить ранее сохранённое значение.

<Tip>
  Уделите особое внимание `description` инструмента и каждого
  параметра. LLM использует эти строки во время выполнения, чтобы определить,
  нужно ли и как вызывать инструмент. Нечёткие описания → нечёткие вызовы инструмента.
</Tip>

### Укажите `format: "email"` для параметров адреса

Параметр, принимающий адрес электронной почты, должен быть обозначен в
своей схеме:

```json
"email": { "type": "string", "format": "email", "description": "The caller's email address" }
```

`format` — это больше, чем подсказка. Для разрешённой схемы email перед
вызовом вашего эндпоинта ThunderPhone удаляет пробелы в начале и конце значения, приводит
домен к нижнему регистру, преобразует отдельные английские слова `at`, `dot`,
`underscore`, `dash` и `hyphen` в соответствующие символы и удаляет пробелы
непосредственно вокруг `@`, `.`, `_` и `-`. Эти слова имеют одинаковое значение
независимо от того, содержит ли расшифровка уже буквальный символ `@`:
`"john dot smith at gmail dot com"` преобразуется в
`john.smith@gmail.com`.

Любые другие внутренние пробелы отклоняются, а не объединяются без уведомления.
Слова, произносимые вместо разделителей, поддерживаются только на английском; неанглийские
или нераспознанные формы с пробелами отклоняются. Допустимые интернационализированные
домены и локальные части SMTPUTF8 принимаются. Введённый Punycode остаётся Punycode,
а домен в Unicode остаётся Unicode после нормализации парсером, поэтому ваш API
получает обычное представление, указанное звонящим. Если итоговое значение
недопустимо, инструмент **не вызывается**. Агент получает
`invalid_email_argument`, указывающий ему
подтвердить написание со звонящим и повторно отправить буквальный адрес.

Пропущенный необязательный email не изменяется. `null`, пустая строка или строка,
состоящая только из пробелов, также не изменяются, когда свойство необязательное
или допускает значение null; те же значения отклоняются для обязательного email,
не допускающего null.

Локальные ссылки схемы, такие как `#/$defs/email` и
`#/definitions/email`, а также `anyOf`, `oneOf` и `allOf`, проверяются
с ограничениями циклов и глубины. Нелокальный или неразрешимый `$ref` — это
известное ограничение проверки, и он передаётся без изменений, как и вызов,
снимок инструмента которого не содержит пригодной схемы. Используйте локальные схемы
email, если необходимо применить проверку.

Параметры без принудительно применяемого формата email передаются в точности
в том виде, в котором их создала модель.

Поддерживаемые форматы: `date-time`, `time`, `date`, `duration`,
`email`, `hostname`, `ipv4`, `ipv6` и `uuid`; сегодня нормализуется
и принудительно проверяется только `email`.

## 3. Протестируйте эндпоинт в песочнице

Перед привязкой интеграции к агенту отправьте подписанный запрос
с серверов ThunderPhone, чтобы подтвердить подключение:

```bash
curl -X POST https://api.thunderphone.com/v1/integrations/test-request \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url":    "https://api.example.com/weather?zip=94110",
    "method": "GET",
    "headers": { "X-Api-Key": "your-provider-key" }
  }'
```

```json Response
{
  "ok": true,
  "status": 200,
  "elapsed_ms": 187,
  "response_headers": { "content-type": "application/json" },
  "response_preview": "{\"temperature_f\": 64, ...}"
}
```

Этот тест также усиливает защиту ThunderPhone от SSRF — запросы к localhost
или диапазонам частных IP возвращают `400 code=url_not_allowed`.

## 4. Свяжите интеграцию с агентом

Подключите через `integration_ids` при создании или обновлении агента:

```bash
curl -X PATCH https://api.thunderphone.com/v1/agents/12 \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "integration_ids": ["f9b5a1a4-..."]
  }'
```

К одному агенту можно подключить несколько интеграций. В промпте агента
на них можно ссылаться по имени — «используй `get_weather`, когда звонящий спрашивает
о погодных условиях» — либо агент может неявно обнаружить их по
описаниям схем.

## 5. Реализуйте конечную точку

Когда агент вызывает инструмент, ThunderPhone отправляет подписанный POST-запрос на
ваш `endpoint_url`:

```
POST /weather HTTP/1.1
Host: api.example.com
X-Api-Key: your-provider-key
X-ThunderPhone-Signature-V2: t=<unix seconds>,v1=<HMAC-SHA256 hex>
X-ThunderPhone-Signature: <HMAC-SHA256 hex>
X-ThunderPhone-Call-ID: 987654321
Content-Type: application/json

{"zip": "94110"}
```

Ваш сервер отвечает JSON-объектом, который возвращается LLM:

```json
{"temperature_f": 64, "condition": "Partly cloudy", "wind_mph": 8}
```

LLM обрабатывает этот ответ и озвучивает звонящему понятное человеку резюме.

<Warning>
  Подпись вычисляется по необработанному телу запроса с использованием того же
  `secret`, что и для конечной точки вебхука. **Проверяйте её** — конечные точки инструментов
  доступны из интернета и подвержены тем же рискам подделки, что и
  вебхуки. См.
  [Проверка подписей вебхуков](/ru/guides/verify-webhook-signatures).
</Warning>

## 6. Протестируйте цикл

Запустите [микрофонную сессию](/api-reference/mic-sessions) с агентом
и задайте вопрос, который обрабатывает ваш инструмент («Какая погода в
94110?»). Расшифровка звонка показывает полный цикл:

```json
{
  "call_id": 987654321,
  "transcripts": [
    { "role": "user",
      "content": "What's the weather in 94110?" },
    { "role": "tool_call",
      "content": "{\"tool_call\": \"get_weather\", \"arguments\": {\"zip\": \"94110\"}}" },
    { "role": "tool_response",
      "content": "{\"tool_name\": \"get_weather\", \"response\": {\"temperature_f\": 64, \"condition\": \"Partly cloudy\"}}" },
    { "role": "agent",
      "content": "It's 64 degrees and partly cloudy." }
  ]
}
```

Получить её можно через
[`GET /v1/calls/{call_id}/transcript`](/api-reference/calls#get-transcript);
поток необработанных событий (с таймингом каждой записи и смещениями аудио) доступен по адресу
[`GET /v1/calls/{call_id}/history`](/api-reference/calls#get-history).

В интерфейсах списка звонков и аналитики ThunderPhone теперь показывает тестовые звонки отдельно от реального трафика. Тесты и симуляции Browser Talk могут повторно использовать реальный номер телефона и выглядеть как входящие, но они не учитываются в общем количестве звонков в продакшене, оценках или показателях проблем.

## Распространённые ошибки

<AccordionGroup>
  <Accordion title="Агент никогда не вызывает инструмент">
    LLM принимает решение на основе описания инструмента. Если вопрос звонящего
    не соответствует описанию, модель не вызовет
    инструмент. Уточните описание (добавьте распространённые синонимы и
    формулировки) или явно укажите это в промпте агента («Когда
    звонящий спрашивает о погоде, используй `get_weather`.»).
  </Accordion>

  <Accordion title="Инструмент возвращает слишком много данных">
    Ответы размером более 6 кБ обрезаются в предпросмотре расшифровки. Возвращайте
    только поля, необходимые LLM, — а не всю запись.
  </Accordion>

  <Accordion title="Тайм-ауты">
    Для конечных точек инструментов установлен тайм-аут по умолчанию 10 секунд. Если нужно больше времени,
    обрабатывайте запрос асинхронно: верните `{"status": "pending", "request_id": "..."}`
    и предоставьте результат через отдельный вызов инструмента.
  </Accordion>

  <Accordion title="Версионирование">
    Каждый `PATCH` интеграции создаёт новую редакцию. Просмотрите
    [`GET /v1/integrations/{id}/versions`](/api-reference/integrations#version-history),
    чтобы узнать, кто и что изменил. Если вы нарушите схему инструмента, можно
    вручную откатить изменения, отправив PATCH с более старым снимком.
  </Accordion>
</AccordionGroup>

---

## Следующие шаги

<CardGroup cols={2}>
  <Card title="Справочник по интеграциям" icon="plug" href="/api-reference/integrations">
    CRUD, передача, история версий.
  </Card>
  <Card title="Спецификация Function Tools" icon="screwdriver-wrench" href="/ru/tools/overview">
    Полная грамматика схемы JSON и контракт подписанного эндпоинта.
  </Card>
  <Card title="Проверка подписей" icon="shield-check" href="/ru/guides/verify-webhook-signatures">
    Примените шаблон подписи вебхука к эндпоинтам инструментов.
  </Card>
  <Card title="API расшифровок и истории" icon="phone" href="/api-reference/calls">
    Просмотрите полный цикл вызова инструмента.
  </Card>
</CardGroup>
