API и вебхуки
REST API голосовых агентов: ключи доступа, запуск и отмена звонков, кампании, транскрипты и записи, а также вебхуки с событиями звонков.
Через API ваша CRM, сайт или бэкенд могут запускать звонки агента, создавать кампании и забирать результаты. Вебхуки, наоборот, сами присылают вам события, когда звонок начался или закончился.
API-ключи
- Откройте «Голосовые агенты» → «API-ключи» → «Создать ключ».
- Отметьте нужные «Области» (права ключа):
| Область | Что разрешает |
|---|---|
agents.read | Получать список агентов |
calls.read | Читать звонки, транскрипты и записи |
calls.write | Запускать и отменять звонки, click-to-call |
campaigns.read | Читать кампании и их прогресс |
campaigns.write | Создавать и отменять кампании |
- Нажмите «Создать» и сразу скопируйте ключ — «Сохраните ключ сейчас — он больше не будет показан». Затем нажмите «Я сохранил».
В таблице ключей видны «Префикс», «Области», «Последнее использование» и «Статус». Кнопка «Отозвать» немедленно отключает ключ — клиенты с ним начнут получать ответ 401.
Храните ключ только на сервере: он даёт доступ к звонкам всего аккаунта.
Основы
Базовый адрес:
https://agents.virtuman.com/api/voice-agents/v1
Каждый запрос передаёт ключ в заголовке:
Authorization: Bearer va_xxxxxxxxxxxxxxxx
Тело запросов и ответов — JSON. Ошибки возвращаются в виде { "error": "<код>" }:
| Код ответа | Примеры error | Значение |
|---|---|---|
400 | invalid_body, invalid_query | Неверные параметры (в issues — подробности) |
401 | missing_bearer, malformed_key, unknown_key, revoked, expired | Ключ не передан или недействителен |
403 | insufficient_scope | У ключа нет нужной области |
404 | not_found, agent_not_found | Объект не найден в вашем аккаунте |
409 | agent_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) — отменить кампанию.
Вебхуки
Вебхуки бывают двух уровней: для конкретного агента (вкладка «Вебхуки» в форме агента) и для всего аккаунта (раздел «Вебхуки»).
Настройка
- Нажмите «Добавить вебхук».
- Укажите «Целевой URL» — ваш HTTPS-адрес.
- Отметьте «События»:
call.started— звонок начался;call.ended— звонок завершён;call.failed— звонок не состоялся (вfailureReason— причина);call.cost_cap_exceeded— достигнут дневной лимит расходов;campaign.completed— кампания завершена.
- Выберите «Формат подписи»:
- «VoiceAgent» — заголовок
X-VoiceAgent-Signature: sha256=<HMAC тела>; - «Standard Webhooks» — заголовки
webhook-id,webhook-timestamp,webhook-signatureс защитой от повтора; - «BusinessOS» — для входящих хуков автоматизации BusinessOS.
- «VoiceAgent» — заголовок
- При необходимости добавьте «Свои заголовки» — например, токен авторизации получателя. Значения хранятся зашифрованными и больше не показываются.
- Нажмите «Создать» и сохраните секрет — он показывается один раз.
Вебхук можно «Приостановить», «Возобновить», «Изменить» и «Удалить». Команда «Обновить секрет» выдаёт новый секрет; для форматов «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 считается окончательным отказом. События доставки видны на вкладке «Активность» звонка: «Вебхук отправлен» или «Вебхук: ошибка».