API и вебхуки

REST API голосовых агентов: ключи доступа, запуск и отмена звонков, кампании, транскрипты и записи, а также вебхуки с событиями звонков.

Через API ваша CRM, сайт или бэкенд могут запускать звонки агента, создавать кампании и забирать результаты. Вебхуки, наоборот, сами присылают вам события, когда звонок начался или закончился.

API-ключи

  1. Откройте «Голосовые агенты» → «API-ключи» → «Создать ключ».
  2. Отметьте нужные «Области» (права ключа):
ОбластьЧто разрешает
agents.readПолучать список агентов
calls.readЧитать звонки, транскрипты и записи
calls.writeЗапускать и отменять звонки, click-to-call
campaigns.readЧитать кампании и их прогресс
campaigns.writeСоздавать и отменять кампании
  1. Нажмите «Создать» и сразу скопируйте ключ — «Сохраните ключ сейчас — он больше не будет показан». Затем нажмите «Я сохранил».

В таблице ключей видны «Префикс», «Области», «Последнее использование» и «Статус». Кнопка «Отозвать» немедленно отключает ключ — клиенты с ним начнут получать ответ 401.

Храните ключ только на сервере: он даёт доступ к звонкам всего аккаунта.

Основы

Базовый адрес:

https://agents.virtuman.com/api/voice-agents/v1

Каждый запрос передаёт ключ в заголовке:

Authorization: Bearer va_xxxxxxxxxxxxxxxx

Тело запросов и ответов — JSON. Ошибки возвращаются в виде { "error": "<код>" }:

Код ответаПримеры errorЗначение
400invalid_body, invalid_queryНеверные параметры (в issues — подробности)
401missing_bearer, malformed_key, unknown_key, revoked, expiredКлюч не передан или недействителен
403insufficient_scopeУ ключа нет нужной области
404not_found, agent_not_foundОбъект не найден в вашем аккаунте
409agent_not_live, listener_agent_cannot_dial, no_calling_windowДействие невозможно в текущем состоянии

ID агента виден в адресе страницы агента, а также в ответе GET /agents.

Агенты

GET /agents — список агентов (область agents.read).

{ "data": [ { "id": "…", "name": "Напоминание об оплате", "language": "ru-RU", "is_live": true, "created_at": "…" } ] }

Звонки

POST /calls — поставить исходящий звонок в очередь (область calls.write).

curl -X POST https://agents.virtuman.com/api/voice-agents/v1/calls \
  -H "Authorization: Bearer $VA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agentId": "4f1c…",
    "toNumber": "+79991234567",
    "parameters": { "name": "Анна", "debt": 1200 },
    "metadata": { "crm_deal_id": "D-1042" }
  }'
ПолеОбязательноОписание
agentIdдаID активного разговорного агента
toNumberдаНомер получателя в формате E.164
fromPhoneNumberIdнетID исходящего номера, с которого звонить
parametersнетДанные для агента: доступны в промпте, приветствии и схеме диалога
metadataнетВаши данные для сопоставления (до 50 ключей). Агенту не показываются, возвращаются в каждом вебхуке

Ответ 201:

{ "id": "9b2e…", "status": "queued", "scheduledFor": null }

Если сейчас вне расписания агента, звонок принимается и откладывается — в scheduledFor будет время набора. Если окон в расписании нет вовсе, вернётся 409 no_calling_window.

GET /calls — список звонков (область calls.read). Параметры запроса: limit (1–100, по умолчанию 50), agentId, status, cursor. Ответ: { "data": [...], "nextCursor": "…" } — для следующей страницы передайте nextCursor в cursor.

GET /calls/{callId} — один звонок: направление, статус, номера, время начала и окончания, стоимость, длительность записи.

GET /calls/{callId}/transcript — транскрипт: { "transcript": { "turns": [...] } }.

GET /calls/{callId}/recording — временная ссылка на запись: { "url": "…", "ttlSeconds": 3600 }. Если записи нет — 404 no_recording.

POST /calls/{callId}/cancel — отменить звонок (область calls.write). Звонок в очереди отменяется сразу, идущий разговор завершается. Для уже завершённого звонка вернётся 409 already_terminal.

Click-to-call с помощником

POST /click-to-call (область calls.write) — сначала звонит оператору, затем клиенту и подключает агента-слушателя с подсказками. Запрос ждёт, пока оператор возьмёт трубку.

{
  "agentId": "<агент в режиме слушателя>",
  "fromPhoneNumberId": "<ID исходящего номера>",
  "operatorNumber": "101",
  "customerNumber": "+79991234567"
}

operatorNumber может быть внутренним добавочным, customerNumber — только E.164. Ответ 201: { "id": "<ID звонка>" }. Возможные ошибки: agent_not_listener, concurrency_limit_reached, no_trunk, operator_unreachable, customer_dial_failed.

Кампании

POST /campaigns (область campaigns.write):

{
  "agentId": "4f1c…",
  "name": "Обзвон должников",
  "concurrencyLimit": 5,
  "retryPolicy": { "max_attempts": 3, "backoff_ms_base": 600000 },
  "targets": [
    { "e164": "+79991234567", "parameters": { "name": "Анна" } },
    { "e164": "+79997654321" }
  ],
  "startImmediately": true
}

concurrencyLimit — от 1 до 50 (по умолчанию 5), max_attempts — от 1 до 10, targets — до 10 000 номеров. Ключи crm_entity_type и crm_entity_id внутри parameters используются для записи итога в CRM и агенту не передаются. Ответ 201: { "id": "…", "status": "running" } (или "draft", если startImmediately: false).

GET /campaigns/{campaignId} (область campaigns.read) — кампания и счётчики counts: total, pending, dialing, completed, failed, skipped.

DELETE /campaigns/{campaignId} (область campaigns.write) — отменить кампанию.

Вебхуки

Вебхуки бывают двух уровней: для конкретного агента (вкладка «Вебхуки» в форме агента) и для всего аккаунта (раздел «Вебхуки»).

Настройка

  1. Нажмите «Добавить вебхук».
  2. Укажите «Целевой URL» — ваш HTTPS-адрес.
  3. Отметьте «События»:
    • call.started — звонок начался;
    • call.ended — звонок завершён;
    • call.failed — звонок не состоялся (в failureReason — причина);
    • call.cost_cap_exceeded — достигнут дневной лимит расходов;
    • campaign.completed — кампания завершена.
  4. Выберите «Формат подписи»:
    • «VoiceAgent» — заголовок X-VoiceAgent-Signature: sha256=<HMAC тела>;
    • «Standard Webhooks» — заголовки webhook-id, webhook-timestamp, webhook-signature с защитой от повтора;
    • «BusinessOS» — для входящих хуков автоматизации BusinessOS.
  5. При необходимости добавьте «Свои заголовки» — например, токен авторизации получателя. Значения хранятся зашифрованными и больше не показываются.
  6. Нажмите «Создать» и сохраните секрет — он показывается один раз.

Вебхук можно «Приостановить», «Возобновить», «Изменить» и «Удалить». Команда «Обновить секрет» выдаёт новый секрет; для форматов «VoiceAgent» и «Standard Webhooks» старый продолжает подписывать доставки ещё 24 часа, чтобы вы успели переключиться.

Что приходит

{
  "event": "call.ended",
  "deliveryId": "…",
  "accountId": "…",
  "occurredAt": "2026-10-18T09:12:44Z",
  "call": {
    "id": "…",
    "agentId": "…",
    "direction": "outbound",
    "fromNumber": "+74951234567",
    "toNumber": "+79991234567",
    "status": "completed",
    "startedAt": "…",
    "answeredAt": "…",
    "endedAt": "…",
    "durationMs": 84000,
    "costUsd": 0.12,
    "recordingUrl": "…",
    "transcript": { "turns": [] },
    "collectedFields": { "payment_date": "2026-10-25" },
    "collectedCompleteness": "complete",
    "callback": null,
    "metadata": { "crm_deal_id": "D-1042" }
  }
}

Также в call приходят dialogSchema (как настроена анкета), toolCalls (хронология вызовов инструментов) и parentCallId для перезвонов. deliveryId одинаков при повторных доставках одного события — используйте его, чтобы не обработать событие дважды.

Отвечайте кодом 2xx, как только приняли событие. При сетевой ошибке или ответе 5xx доставка повторяется с нарастающими паузами примерно в течение суток; ответ 4xx считается окончательным отказом. События доставки видны на вкладке «Активность» звонка: «Вебхук отправлен» или «Вебхук: ошибка».