Справочник API

Все эндпоинты API v1. Примеры на curl, JavaScript (fetch) и Python (requests); выбранный язык запоминается для всей страницы.

Базовый URLhttps://hubvocal.com/v1
АвторизацияAuthorization: Bearer vt_live_…
Лимит запросов120 запросов/мин на ключ · 429 + Retry-After
Области доступаread · write · calls
У каждого ключа есть read, write и/или calls. read даёт доступ к GET-запросам, write — к изменениям, calls — к исходящим звонкам. Запрос за пределами областей доступа ключа получает 403.
Тело ошибки{"detail": "..."}
OpenAPIGET /v1/openapi.json

Об аутентификации, встраивании и кодах ошибок — в разделе Разработчикам.

Агенты

Разговоры идут в текстовом режиме, поэтому проверяются инструкции и использование инструментов, а не голос или задержка. Симуляции запускаются из панели управления; эндпоинта /v1 для них пока нет.

Список агентов

GET /v1/agents

Возвращает всех агентов вашей организации в том порядке, в каком они показаны в панели управления.

Запрос

curl
curl "https://hubvocal.com/v1/agents" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
[
  {
    "id": "front-desk",
    "name": "Front desk",
    "lang": "en",
    "engine": "live",
    "instructions": "You are the front desk assistant for a dental clinic. Help callers book appointments and answer general questions briefly. Never make things up; offer a callback from the team instead.",
    "greeting": "Hello, thanks for calling the clinic. How can I help you today?",
    "voice": {
      "voice": "marin",
      "speed": 1
    },
    "tools": {
      "builtins": [
        "end_call",
        "take_message"
      ],
      "webhooks": [
        "tl_8f3a2c"
      ]
    },
    "turn": {
      "first_speaker": "agent",
      "idle_check_s": 30
    },
    "recording": {
      "enabled": false,
      "announce": true
    },
    "post_call": {
      "summary": true,
      "fields": [
        {
          "name": "appointment_date",
          "type": "date",
          "description": "Requested appointment date, if any"
        },
        {
          "name": "callback",
          "type": "boolean",
          "description": "Does the caller want a callback?"
        }
      ]
    },
    "knowledge": {
      "doc_ids": [
        "kb_7d21e4"
      ],
      "mode": "tool"
    },
    "published_version": 3,
    "draft_changed": false
  }
]

Создать агента

POST /v1/agents

Создаёт агента. Каждое поле проверяется на сервере; значения сверх лимитов обрезаются. Если передать уже существующий id, запрос завершится ошибкой 409. Для обновления используйте PUT.

ИмяГдеТипОписание
id body string Необязательно. Строчные латинские буквы, цифры и дефисы, до 48 символов. Если не указан, создаётся из имени.
name
обязательно
body string Отображаемое имя, до 60 символов.
lang
обязательно
body string Код языка разговора, например tr, en, de. Полный список — в GET /v1/voices.
engine
обязательно
body "live" | "gemini" | "realtime" | "classic" live: GPT-Live 1, gemini: Gemini Live, realtime: OpenAI Realtime, classic: STT → LLM → TTS.
instructions body string Системные инструкции, до 8000 символов.
greeting body string Первая фраза агента, до 400 символов.
voice body object voice (имя из /v1/voices), speed (только classic и realtime; для live и gemini фиксировано на 1.0), tone (манера речи свободным текстом, до 600 символов).
tools body object builtins (end_call, take_message) и webhooks (id инструментов); всего до 16 инструментов. Если поле пустое или отсутствует, инструментов нет. mcp: [{server_id, tools}] добавляет инструменты с ваших MCP-серверов; они входят в тот же лимит.
turn body object Настройки очерёдности реплик: sensitivity (low, balanced, high; только движок classic), first_speaker (agent или caller), silence_wait_s (1–5), idle_check_s (0 или 10–120), agent_timeout_s (0 или 10–60). Для пустых полей используются значения по умолчанию.
recording body object recording: {enabled (по умолчанию false), announce (по умолчанию true), announce_text?}. Если запись включена, агент сообщает о ней перед приветствием.
post_call body object post_call.summary: составлять резюме после завершения звонка (по умолчанию true). post_call.fields: до 24 полей, которые заполняются после звонка ({name, type, description, enum?, required?}).
knowledge body object doc_ids (до 50 документов из базы знаний) и mode ("tool"). Тогда агент получает инструмент search_knowledge.
calendar body object integration_id и calendar_id из панели управления, duration_min (15–240), buffer_min (0–60), timezone, working_hours, min_notice_h (0–72), max_days_ahead (1–90). Включает инструменты записи на приём.

Запрос

curl
curl -X POST "https://hubvocal.com/v1/agents" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Front desk",
  "lang": "en",
  "engine": "live",
  "instructions": "You are the front desk assistant for a dental clinic. Help callers book appointments and answer general questions briefly. Never make things up; offer a callback from the team instead.",
  "greeting": "Hello, thanks for calling the clinic. How can I help you today?",
  "voice": {
    "voice": "marin",
    "speed": 1
  },
  "tools": {
    "builtins": [
      "end_call",
      "take_message"
    ],
    "webhooks": [
      "tl_8f3a2c"
    ]
  },
  "turn": {
    "first_speaker": "agent",
    "idle_check_s": 30
  },
  "recording": {
    "enabled": false,
    "announce": true
  },
  "post_call": {
    "summary": true,
    "fields": [
      {
        "name": "appointment_date",
        "type": "date",
        "description": "Requested appointment date, if any"
      },
      {
        "name": "callback",
        "type": "boolean",
        "description": "Does the caller want a callback?"
      }
    ]
  },
  "knowledge": {
    "doc_ids": [
      "kb_7d21e4"
    ],
    "mode": "tool"
  }
}'

Ответ · 201

JSON
{
  "id": "front-desk",
  "name": "Front desk",
  "lang": "en",
  "engine": "live",
  "instructions": "You are the front desk assistant for a dental clinic. Help callers book appointments and answer general questions briefly. Never make things up; offer a callback from the team instead.",
  "greeting": "Hello, thanks for calling the clinic. How can I help you today?",
  "voice": {
    "voice": "marin",
    "speed": 1
  },
  "tools": {
    "builtins": [
      "end_call",
      "take_message"
    ],
    "webhooks": [
      "tl_8f3a2c"
    ]
  },
  "turn": {
    "first_speaker": "agent",
    "idle_check_s": 30
  },
  "recording": {
    "enabled": false,
    "announce": true
  },
  "post_call": {
    "summary": true,
    "fields": [
      {
        "name": "appointment_date",
        "type": "date",
        "description": "Requested appointment date, if any"
      },
      {
        "name": "callback",
        "type": "boolean",
        "description": "Does the caller want a callback?"
      }
    ]
  },
  "knowledge": {
    "doc_ids": [
      "kb_7d21e4"
    ],
    "mode": "tool"
  },
  "published_version": null,
  "draft_changed": true
}

Ошибки

  • 409 Агент с таким id уже существует.

Получить агента

GET /v1/agents/{id}

Возвращает одного агента. published_version — номер опубликованной версии (null, если агент ни разу не публиковался), а draft_changed показывает, отличается ли от неё черновик.

ИмяГдеТипОписание
id
обязательно
path string Id агента, например front-desk.

Запрос

curl
curl "https://hubvocal.com/v1/agents/front-desk" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
{
  "id": "front-desk",
  "name": "Front desk",
  "lang": "en",
  "engine": "live",
  "instructions": "You are the front desk assistant for a dental clinic. Help callers book appointments and answer general questions briefly. Never make things up; offer a callback from the team instead.",
  "greeting": "Hello, thanks for calling the clinic. How can I help you today?",
  "voice": {
    "voice": "marin",
    "speed": 1
  },
  "tools": {
    "builtins": [
      "end_call",
      "take_message"
    ],
    "webhooks": [
      "tl_8f3a2c"
    ]
  },
  "turn": {
    "first_speaker": "agent",
    "idle_check_s": 30
  },
  "recording": {
    "enabled": false,
    "announce": true
  },
  "post_call": {
    "summary": true,
    "fields": [
      {
        "name": "appointment_date",
        "type": "date",
        "description": "Requested appointment date, if any"
      },
      {
        "name": "callback",
        "type": "boolean",
        "description": "Does the caller want a callback?"
      }
    ]
  },
  "knowledge": {
    "doc_ids": [
      "kb_7d21e4"
    ],
    "mode": "tool"
  },
  "published_version": 3,
  "draft_changed": false
}

Ошибки

  • 404 Агента с таким id нет.

Обновить агента

PUT /v1/agents/{id}

Заменяет агента отправленным объектом. Отправляйте объект целиком: пропущенные поля получат значения по умолчанию. Id в пути важнее id в теле.

ИмяГдеТипОписание
id
обязательно
path string Id агента, например front-desk.
name
обязательно
body string Отображаемое имя, до 60 символов.
lang
обязательно
body string Код языка разговора, например tr, en, de. Полный список — в GET /v1/voices.
engine
обязательно
body "live" | "gemini" | "realtime" | "classic" live: GPT-Live 1, gemini: Gemini Live, realtime: OpenAI Realtime, classic: STT → LLM → TTS.
instructions body string Системные инструкции, до 8000 символов.
greeting body string Первая фраза агента, до 400 символов.
voice body object voice (имя из /v1/voices), speed (только classic и realtime; для live и gemini фиксировано на 1.0), tone (манера речи свободным текстом, до 600 символов).
tools body object builtins (end_call, take_message) и webhooks (id инструментов); всего до 16 инструментов. Если поле пустое или отсутствует, инструментов нет. mcp: [{server_id, tools}] добавляет инструменты с ваших MCP-серверов; они входят в тот же лимит.
turn body object Настройки очерёдности реплик: sensitivity (low, balanced, high; только движок classic), first_speaker (agent или caller), silence_wait_s (1–5), idle_check_s (0 или 10–120), agent_timeout_s (0 или 10–60). Для пустых полей используются значения по умолчанию.
recording body object recording: {enabled (по умолчанию false), announce (по умолчанию true), announce_text?}. Если запись включена, агент сообщает о ней перед приветствием.
post_call body object post_call.summary: составлять резюме после завершения звонка (по умолчанию true). post_call.fields: до 24 полей, которые заполняются после звонка ({name, type, description, enum?, required?}).
knowledge body object doc_ids (до 50 документов из базы знаний) и mode ("tool"). Тогда агент получает инструмент search_knowledge.
calendar body object integration_id и calendar_id из панели управления, duration_min (15–240), buffer_min (0–60), timezone, working_hours, min_notice_h (0–72), max_days_ahead (1–90). Включает инструменты записи на приём.

Запрос

curl
curl -X PUT "https://hubvocal.com/v1/agents/front-desk" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Front desk",
  "lang": "en",
  "engine": "live",
  "instructions": "You are the front desk assistant for a dental clinic. Help callers book appointments and answer general questions briefly. Never make things up; offer a callback from the team instead.",
  "greeting": "Hello, thanks for calling the clinic. How can I help you today?",
  "voice": {
    "voice": "cedar",
    "speed": 1
  },
  "tools": {
    "builtins": [
      "end_call",
      "take_message"
    ],
    "webhooks": [
      "tl_8f3a2c"
    ]
  },
  "turn": {
    "first_speaker": "agent",
    "idle_check_s": 30
  },
  "recording": {
    "enabled": false,
    "announce": true
  },
  "post_call": {
    "summary": true,
    "fields": [
      {
        "name": "appointment_date",
        "type": "date",
        "description": "Requested appointment date, if any"
      },
      {
        "name": "callback",
        "type": "boolean",
        "description": "Does the caller want a callback?"
      }
    ]
  },
  "knowledge": {
    "doc_ids": [
      "kb_7d21e4"
    ],
    "mode": "tool"
  }
}'

Ответ · 200

JSON
{
  "id": "front-desk",
  "name": "Front desk",
  "lang": "en",
  "engine": "live",
  "instructions": "You are the front desk assistant for a dental clinic. Help callers book appointments and answer general questions briefly. Never make things up; offer a callback from the team instead.",
  "greeting": "Hello, thanks for calling the clinic. How can I help you today?",
  "voice": {
    "voice": "cedar",
    "speed": 1
  },
  "tools": {
    "builtins": [
      "end_call",
      "take_message"
    ],
    "webhooks": [
      "tl_8f3a2c"
    ]
  },
  "turn": {
    "first_speaker": "agent",
    "idle_check_s": 30
  },
  "recording": {
    "enabled": false,
    "announce": true
  },
  "post_call": {
    "summary": true,
    "fields": [
      {
        "name": "appointment_date",
        "type": "date",
        "description": "Requested appointment date, if any"
      },
      {
        "name": "callback",
        "type": "boolean",
        "description": "Does the caller want a callback?"
      }
    ]
  },
  "knowledge": {
    "doc_ids": [
      "kb_7d21e4"
    ],
    "mode": "tool"
  },
  "published_version": 3,
  "draft_changed": true
}

Ошибки

  • 404 Агента с таким id нет. Сначала создайте его через POST.

Удалить агента

DELETE /v1/agents/{id}

Удаляет агента. В организации всегда остаётся хотя бы один агент, поэтому удалить последнего нельзя.

ИмяГдеТипОписание
id
обязательно
path string Id агента, например front-desk.

Запрос

curl
curl -X DELETE "https://hubvocal.com/v1/agents/front-desk" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
{
  "deleted": "front-desk"
}

Ошибки

  • 400 Это последний агент в организации.
  • 404 Агента с таким id нет.

Список версий

GET /v1/agents/{id}/versions

Опубликованные версии агента, от новых к старым. is_live отмечает ту, которую сейчас используют звонки.

ИмяГдеТипОписание
id
обязательно
path string Id агента, например front-desk.

Запрос

curl
curl "https://hubvocal.com/v1/agents/front-desk/versions" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
[
  {
    "version": 3,
    "note": "Shorter greeting",
    "published_at": 1793829000,
    "published_by": "ayse@example.com",
    "is_live": true
  },
  {
    "version": 2,
    "note": "Added price list",
    "published_at": 1793740000,
    "published_by": "ayse@example.com",
    "is_live": false
  }
]

Ошибки

  • 404 Агента с таким id нет.

Получить версию

GET /v1/agents/{id}/versions/{n}

Полный объект агента в том виде, в каком он был в этой версии.

ИмяГдеТипОписание
id
обязательно
path string Id агента, например front-desk.
n
обязательно
path integer Номер версии.

Запрос

curl
curl "https://hubvocal.com/v1/agents/front-desk/versions/2" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
{
  "id": "front-desk",
  "name": "Front desk",
  "lang": "en",
  "engine": "live",
  "instructions": "You are the front desk assistant for a dental clinic. Help callers book appointments and answer general questions briefly. Never make things up; offer a callback from the team instead.",
  "greeting": "Hello, thanks for calling the clinic. How can I help you today?",
  "voice": {
    "voice": "marin",
    "speed": 1
  },
  "tools": {
    "builtins": [
      "end_call",
      "take_message"
    ],
    "webhooks": [
      "tl_8f3a2c"
    ]
  },
  "turn": {
    "first_speaker": "agent",
    "idle_check_s": 30
  },
  "recording": {
    "enabled": false,
    "announce": true
  },
  "post_call": {
    "summary": true,
    "fields": [
      {
        "name": "appointment_date",
        "type": "date",
        "description": "Requested appointment date, if any"
      },
      {
        "name": "callback",
        "type": "boolean",
        "description": "Does the caller want a callback?"
      }
    ]
  },
  "knowledge": {
    "doc_ids": [
      "kb_7d21e4"
    ],
    "mode": "tool"
  },
  "version": 2
}

Ошибки

  • 404 Такого агента или такой версии нет.

Опубликовать черновик

POST /v1/agents/{id}/publish

Сохраняет текущий черновик как новую версию, и звонки начинают использовать её. Уже идущие звонки остаются на своей версии.

ИмяГдеТипОписание
id
обязательно
path string Id агента, например front-desk.
note body string Короткая заметка о том, что изменилось.

Запрос

curl
curl -X POST "https://hubvocal.com/v1/agents/front-desk/publish" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "note": "Shorter greeting"
}'

Ответ · 200

JSON
{
  "version": 4
}

Ошибки

  • 404 Агента с таким id нет.

Откатить версию

POST /v1/agents/{id}/rollback

Копирует одну из прежних версий в черновик и публикует её как новую версию.

ИмяГдеТипОписание
id
обязательно
path string Id агента, например front-desk.
version
обязательно
body integer Версия, которую нужно вернуть.

Запрос

curl
curl -X POST "https://hubvocal.com/v1/agents/front-desk/rollback" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "version": 2
}'

Ответ · 200

JSON
{
  "version": 5
}

Ошибки

  • 404 Такого агента или такой версии нет.

База знаний

Список документов

GET /v1/knowledge

Документы вашей организации: статус обработки, размер, число фрагментов и агенты, которые их используют.

Запрос

curl
curl "https://hubvocal.com/v1/knowledge" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
[
  {
    "id": "kb_7d21e4",
    "title": "Price list 2026",
    "kind": "file",
    "filename": "price-list-2026.pdf",
    "url": null,
    "size_bytes": 248113,
    "chunks": 42,
    "status": "ready",
    "error": null,
    "created_at": 1793740000,
    "used_by": [
      "front-desk"
    ]
  }
]

Добавить документ

POST /v1/knowledge

Загрузите файл как multipart/form-data (поле file), отправьте текст как JSON {title, text} или одну веб-страницу как JSON {url}. Возвращает 201 со статусом processing; запрашивайте документ, пока статус не станет ready или failed.

ИмяГдеТипОписание
file body file multipart/form-data: pdf, docx, txt, md или html, до 10 МБ.
title body string Заголовок, вместе с text.
text body string Содержимое обычным текстом.
url body string Вместо файла или текста: одна страница по https, которую нужно загрузить.

Запрос

curl
curl -X POST "https://hubvocal.com/v1/knowledge" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "Opening hours",
  "text": "We are open 09:00–18:00 on weekdays and 10:00–14:00 on Saturdays. Closed on Sundays."
}'

Ответ · 201

JSON
{
  "id": "kb_9f03b1",
  "title": "Opening hours",
  "kind": "text",
  "filename": null,
  "url": null,
  "size_bytes": 96,
  "chunks": 0,
  "status": "processing",
  "error": null,
  "created_at": 1793740000,
  "used_by": []
}

Ошибки

  • 400 Неподдерживаемый тип файла, файл больше 10 МБ, URL не https или указывает на частный адрес, либо достигнут лимит организации (200 документов, 200 МБ).

Получить документ

GET /v1/knowledge/{id}

Документ с предпросмотром первых 2000 символов.

ИмяГдеТипОписание
id
обязательно
path string Id документа.

Запрос

curl
curl "https://hubvocal.com/v1/knowledge/kb_7d21e4" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
{
  "id": "kb_7d21e4",
  "title": "Price list 2026",
  "kind": "file",
  "filename": "price-list-2026.pdf",
  "url": null,
  "size_bytes": 248113,
  "chunks": 42,
  "status": "ready",
  "error": null,
  "created_at": 1793740000,
  "used_by": [
    "front-desk"
  ],
  "preview": "Price list 2026. Check-up 1,500 TRY, scale and polish 2,000 TRY…"
}

Ошибки

  • 404 Документа с таким id нет.

Удалить документ

DELETE /v1/knowledge/{id}

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

ИмяГдеТипОписание
id
обязательно
path string Id документа.

Запрос

curl
curl -X DELETE "https://hubvocal.com/v1/knowledge/kb_7d21e4" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
{
  "deleted": "kb_7d21e4"
}

Ошибки

  • 404 Документа с таким id нет.

Поиск

POST /v1/knowledge/search

Выполняет тот же поиск, что и агент, и возвращает самые подходящие фрагменты с оценкой. Удобно, чтобы проверить документы перед запуском.

ИмяГдеТипОписание
query
обязательно
body string Что искать.
doc_ids body string[] Искать только в этих документах.

Запрос

curl
curl -X POST "https://hubvocal.com/v1/knowledge/search" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "query": "how much is a scale and polish"
}'

Ответ · 200

JSON
[
  {
    "doc_id": "kb_7d21e4",
    "title": "Price list 2026",
    "chunk_index": 3,
    "text": "Scale and polish: 2,000 TRY, about 30 minutes.",
    "score": 0.82
  }
]

Инструменты

Встроенные инструменты

Эти инструменты не нужно описывать. Включите их в tools.builtins агента. search_knowledge добавляется, когда задано knowledge. Инструменты записи на приём добавляются, когда задано calendar.

ИмяЧто делает
end_callАгент прощается и кладёт трубку через 0,75 с после того, как договорит. Если абонент за это время заговорит, завершение звонка отменяется. В карточке звонка будет ended_by: "agent".
take_messageПринимает name, phone, message и callback_requested и записывает их в outcomes[] карточки звонка. Подтверждения не запрашивает.
search_knowledgeДобавляется автоматически, если у агента есть документы в knowledge. Ищет по ним и записывает источники в карточку звонка.
check_availabilityТип read. Возвращает свободные слоты между date_from и date_to в пределах рабочих часов агента. Добавляется, если задан calendar.
book_appointmentТип write, проходит шаг подтверждения. Бронирует время start на имя name и телефон phone, при желании с заметкой note. Запись попадает в outcomes[].
cancel_appointmentТип write, проходит шаг подтверждения. Отменяет запись по её booking_ref.

Интеграции с календарями (Google Calendar) подключаются только в панели управления; эндпоинта /v1 для них нет. В поле calendar агента укажите id интеграции и календаря из панели управления.

Список инструментов

GET /v1/tools

Инструменты-webhooks вашей организации. Секрет никогда не возвращается; has_secret показывает, задан ли он.

Запрос

curl
curl "https://hubvocal.com/v1/tools" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
[
  {
    "id": "tl_8f3a2c",
    "name": "check_order",
    "description": "Looks up the shipping status of an order by its number.",
    "kind": "read",
    "url": "https://crm.example.com/hooks/order",
    "parameters": {
      "type": "object",
      "properties": {
        "order_id": {
          "type": "string",
          "description": "Order number"
        }
      },
      "required": [
        "order_id"
      ]
    },
    "timeout_s": 8,
    "enabled": true,
    "has_secret": true,
    "created_at": 1793830000,
    "updated_at": 1793830000
  }
]

Получить инструмент

GET /v1/tools/{id}

Один инструмент-webhook. Секрет никогда не возвращается.

ИмяГдеТипОписание
id
обязательно
path string Id инструмента.

Запрос

curl
curl "https://hubvocal.com/v1/tools/tl_8f3a2c" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
{
  "id": "tl_8f3a2c",
  "name": "check_order",
  "description": "Looks up the shipping status of an order by its number.",
  "kind": "read",
  "url": "https://crm.example.com/hooks/order",
  "parameters": {
    "type": "object",
    "properties": {
      "order_id": {
        "type": "string",
        "description": "Order number"
      }
    },
    "required": [
      "order_id"
    ]
  },
  "timeout_s": 8,
  "enabled": true,
  "has_secret": true,
  "created_at": 1793830000,
  "updated_at": 1793830000
}

Ошибки

  • 404 Инструмента с таким id нет.

Создать инструмент

POST /v1/tools

Создаёт инструмент-webhook для организации. Чтобы использовать его, добавьте его id в tools.webhooks агента. URL должен быть https и не может указывать на локальный или частный адрес.

ИмяГдеТипОписание
name
обязательно
body string Строчные латинские буквы, цифры и подчёркивания, начинается с буквы (3–41 символ). Уникально в организации; end_call и take_message зарезервированы.
description
обязательно
body string Объясняет модели, когда и как использовать инструмент.
kind
обязательно
body "read" | "write" read выполняется сразу; write сначала просит абонента подтвердить.
url
обязательно
body string Ваш эндпоинт. Только https; локальные и частные адреса отклоняются.
parameters body object Объект JSON Schema: до 20 полей типа string, number, integer или boolean (можно enum).
timeout_s body integer От 2 до 15 секунд.
enabled body boolean Отключённые инструменты модели не предлагаются.
secret body string Используется для подписи запросов. Только для записи; при обновлении пустое значение сохраняет текущий секрет, а "-" удаляет его.

Запрос

curl
curl -X POST "https://hubvocal.com/v1/tools" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "check_order",
  "description": "Looks up the shipping status of an order by its number.",
  "kind": "read",
  "url": "https://crm.example.com/hooks/order",
  "parameters": {
    "type": "object",
    "properties": {
      "order_id": {
        "type": "string",
        "description": "Order number"
      }
    },
    "required": [
      "order_id"
    ]
  },
  "timeout_s": 8,
  "enabled": true,
  "secret": "whsec_2b7f…"
}'

Ответ · 201

JSON
{
  "id": "tl_8f3a2c",
  "name": "check_order",
  "description": "Looks up the shipping status of an order by its number.",
  "kind": "read",
  "url": "https://crm.example.com/hooks/order",
  "parameters": {
    "type": "object",
    "properties": {
      "order_id": {
        "type": "string",
        "description": "Order number"
      }
    },
    "required": [
      "order_id"
    ]
  },
  "timeout_s": 8,
  "enabled": true,
  "has_secret": true,
  "created_at": 1793830000,
  "updated_at": 1793830000
}

Ошибки

  • 400 Поле нарушает правила: формат имени, URL не https, частный адрес, больше 20 параметров или тайм-аут вне диапазона.
  • 409 Инструмент с таким именем уже есть, или это имя зарезервировано.

Обновить инструмент

PUT /v1/tools/{id}

Заменяет инструмент отправленным объектом. Чтобы сохранить текущий secret, оставьте поле пустым или не передавайте его; чтобы удалить, отправьте "-".

ИмяГдеТипОписание
id
обязательно
path string Id инструмента.
name
обязательно
body string Строчные латинские буквы, цифры и подчёркивания, начинается с буквы (3–41 символ). Уникально в организации; end_call и take_message зарезервированы.
description
обязательно
body string Объясняет модели, когда и как использовать инструмент.
kind
обязательно
body "read" | "write" read выполняется сразу; write сначала просит абонента подтвердить.
url
обязательно
body string Ваш эндпоинт. Только https; локальные и частные адреса отклоняются.
parameters body object Объект JSON Schema: до 20 полей типа string, number, integer или boolean (можно enum).
timeout_s body integer От 2 до 15 секунд.
enabled body boolean Отключённые инструменты модели не предлагаются.
secret body string Используется для подписи запросов. Только для записи; при обновлении пустое значение сохраняет текущий секрет, а "-" удаляет его.

Запрос

curl
curl -X PUT "https://hubvocal.com/v1/tools/tl_8f3a2c" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "check_order",
  "description": "Looks up the shipping status of an order by its number.",
  "kind": "read",
  "url": "https://crm.example.com/hooks/order",
  "parameters": {
    "type": "object",
    "properties": {
      "order_id": {
        "type": "string",
        "description": "Order number"
      }
    },
    "required": [
      "order_id"
    ]
  },
  "timeout_s": 10,
  "enabled": true,
  "secret": ""
}'

Ответ · 200

JSON
{
  "id": "tl_8f3a2c",
  "name": "check_order",
  "description": "Looks up the shipping status of an order by its number.",
  "kind": "read",
  "url": "https://crm.example.com/hooks/order",
  "parameters": {
    "type": "object",
    "properties": {
      "order_id": {
        "type": "string",
        "description": "Order number"
      }
    },
    "required": [
      "order_id"
    ]
  },
  "timeout_s": 10,
  "enabled": true,
  "has_secret": true,
  "created_at": 1793830000,
  "updated_at": 1793833600
}

Ошибки

  • 400 Поле нарушает правила: формат имени, URL не https, частный адрес, больше 20 параметров или тайм-аут вне диапазона.
  • 404 Инструмента с таким id нет.

Удалить инструмент

DELETE /v1/tools/{id}

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

ИмяГдеТипОписание
id
обязательно
path string Id инструмента.

Запрос

curl
curl -X DELETE "https://hubvocal.com/v1/tools/tl_8f3a2c" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
{
  "deleted": "tl_8f3a2c"
}

Ошибки

  • 404 Инструмента с таким id нет.

Проверить инструмент

POST /v1/tools/{id}/test

Отправляет настоящий запрос на URL инструмента с переданными аргументами и возвращает статус, время выполнения и до 4 КБ тела ответа.

ИмяГдеТипОписание
id
обязательно
path string Id инструмента.
arguments body object Примерные аргументы в соответствии с parameters.

Запрос

curl
curl -X POST "https://hubvocal.com/v1/tools/tl_8f3a2c/test" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "arguments": {
    "order_id": "A-10234"
  }
}'

Ответ · 200

JSON
{
  "ok": true,
  "status": 200,
  "ms": 412,
  "body": "{\"order_id\":\"A-10234\",\"status\":\"shipped\",\"eta\":\"2026-11-07\"}"
}

Ошибки

  • 404 Инструмента с таким id нет.

MCP-серверы

Список MCP-серверов

GET /v1/mcp-servers

MCP-серверы вашей организации с их статусом и синхронизированными инструментами. auth_set показывает, сохранён ли секрет; сам секрет никогда не возвращается.

Запрос

curl
curl "https://hubvocal.com/v1/mcp-servers" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
[
  {
    "id": "mcp_2b8e41",
    "name": "crm",
    "url": "https://mcp.example.com/mcp",
    "transport": "streamable_http",
    "auth": "bearer",
    "auth_set": true,
    "enabled": true,
    "status": "ok",
    "error": null,
    "tools_synced_at": 1793831000,
    "tools": [
      {
        "name": "find_customer",
        "description": "Find a customer by phone number.",
        "input_schema": {
          "type": "object",
          "properties": {
            "phone": {
              "type": "string"
            }
          },
          "required": [
            "phone"
          ]
        },
        "enabled": true,
        "access": "read"
      },
      {
        "name": "create_ticket",
        "description": "Open a support ticket.",
        "input_schema": {
          "type": "object",
          "properties": {
            "subject": {
              "type": "string"
            },
            "body": {
              "type": "string"
            }
          },
          "required": [
            "subject"
          ]
        },
        "enabled": false,
        "access": "write"
      }
    ]
  }
]

Добавить MCP-сервер

POST /v1/mcp-servers

Сохраняет сервер и загружает список его инструментов. Новые инструменты выключены. До 10 серверов на организацию.

ИмяГдеТипОписание
name
обязательно
body string Короткое имя; служит префиксом в именах инструментов (<name>.<tool>).
url
обязательно
body string MCP-эндпоинт сервера. Только https; локальные и частные адреса отклоняются.
transport body string streamable_http (по умолчанию) или sse.
auth body string none, bearer или header.
secret body string Токен или значение заголовка. Хранится в зашифрованном виде и никогда не возвращается; "-" удаляет его.
header_name body string Имя заголовка, если auth — header.

Запрос

curl
curl -X POST "https://hubvocal.com/v1/mcp-servers" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "crm",
  "url": "https://mcp.example.com/mcp",
  "auth": "bearer",
  "secret": "sk_live_…"
}'

Ответ · 201

JSON
{
  "id": "mcp_2b8e41",
  "name": "crm",
  "url": "https://mcp.example.com/mcp",
  "transport": "streamable_http",
  "auth": "bearer",
  "auth_set": true,
  "enabled": true,
  "status": "ok",
  "error": null,
  "tools_synced_at": 1793831000,
  "tools": [
    {
      "name": "find_customer",
      "description": "Find a customer by phone number.",
      "input_schema": {
        "type": "object",
        "properties": {
          "phone": {
            "type": "string"
          }
        },
        "required": [
          "phone"
        ]
      },
      "enabled": false,
      "access": "write"
    },
    {
      "name": "create_ticket",
      "description": "Open a support ticket.",
      "input_schema": {
        "type": "object",
        "properties": {
          "subject": {
            "type": "string"
          },
          "body": {
            "type": "string"
          }
        },
        "required": [
          "subject"
        ]
      },
      "enabled": false,
      "access": "write"
    }
  ]
}

Ошибки

  • 400 URL не https или указывает на частный адрес, либо не удалось получить список инструментов сервера.
  • 409 У организации уже есть 10 MCP-серверов.

Обновить MCP-сервер

PUT /v1/mcp-servers/{id}

Меняет имя, URL, аутентификацию или состояние (включён/выключен), а также то, какие инструменты включены и относятся ли они к read или write. Чтобы удалить секрет, отправьте secret: "-".

ИмяГдеТипОписание
id
обязательно
path string Id MCP-сервера.
name body string Короткое имя; служит префиксом в именах инструментов (<name>.<tool>).
url body string MCP-эндпоинт сервера. Только https; локальные и частные адреса отклоняются.
enabled body boolean Выключенный сервер агентам не предлагается.
auth body string none, bearer или header.
secret body string Токен или значение заголовка. Хранится в зашифрованном виде и никогда не возвращается; "-" удаляет его.
tools body object[] [{name, enabled, access}] для каждого инструмента; access — read или write.

Запрос

curl
curl -X PUT "https://hubvocal.com/v1/mcp-servers/mcp_2b8e41" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "tools": [
    {
      "name": "find_customer",
      "enabled": true,
      "access": "read"
    },
    {
      "name": "create_ticket",
      "enabled": true,
      "access": "write"
    }
  ]
}'

Ответ · 200

JSON
{
  "id": "mcp_2b8e41",
  "name": "crm",
  "url": "https://mcp.example.com/mcp",
  "transport": "streamable_http",
  "auth": "bearer",
  "auth_set": true,
  "enabled": true,
  "status": "ok",
  "error": null,
  "tools_synced_at": 1793831000,
  "tools": [
    {
      "name": "find_customer",
      "description": "Find a customer by phone number.",
      "input_schema": {
        "type": "object",
        "properties": {
          "phone": {
            "type": "string"
          }
        },
        "required": [
          "phone"
        ]
      },
      "enabled": true,
      "access": "read"
    },
    {
      "name": "create_ticket",
      "description": "Open a support ticket.",
      "input_schema": {
        "type": "object",
        "properties": {
          "subject": {
            "type": "string"
          },
          "body": {
            "type": "string"
          }
        },
        "required": [
          "subject"
        ]
      },
      "enabled": true,
      "access": "write"
    }
  ]
}

Ошибки

  • 400 URL не https или указывает на частный адрес, либо не удалось получить список инструментов сервера.
  • 404 MCP-сервера с таким id нет.

Удалить MCP-сервер

DELETE /v1/mcp-servers/{id}

Удаляет сервер и убирает его инструменты у всех агентов.

ИмяГдеТипОписание
id
обязательно
path string Id MCP-сервера.

Запрос

curl
curl -X DELETE "https://hubvocal.com/v1/mcp-servers/mcp_2b8e41" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
{
  "deleted": "mcp_2b8e41"
}

Ошибки

  • 404 MCP-сервера с таким id нет.

Синхронизировать инструменты

POST /v1/mcp-servers/{id}/sync

Заново загружает список инструментов. Новые инструменты появляются выключенными, с доступом write.

ИмяГдеТипОписание
id
обязательно
path string Id MCP-сервера.

Запрос

curl
curl -X POST "https://hubvocal.com/v1/mcp-servers/mcp_2b8e41/sync" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
{
  "id": "mcp_2b8e41",
  "name": "crm",
  "url": "https://mcp.example.com/mcp",
  "transport": "streamable_http",
  "auth": "bearer",
  "auth_set": true,
  "enabled": true,
  "status": "ok",
  "error": null,
  "tools_synced_at": 1793831000,
  "tools": [
    {
      "name": "find_customer",
      "description": "Find a customer by phone number.",
      "input_schema": {
        "type": "object",
        "properties": {
          "phone": {
            "type": "string"
          }
        },
        "required": [
          "phone"
        ]
      },
      "enabled": true,
      "access": "read"
    },
    {
      "name": "create_ticket",
      "description": "Open a support ticket.",
      "input_schema": {
        "type": "object",
        "properties": {
          "subject": {
            "type": "string"
          },
          "body": {
            "type": "string"
          }
        },
        "required": [
          "subject"
        ]
      },
      "enabled": false,
      "access": "write"
    }
  ]
}

Ошибки

  • 400 URL не https или указывает на частный адрес, либо не удалось получить список инструментов сервера.
  • 404 MCP-сервера с таким id нет.

Проверить инструмент

POST /v1/mcp-servers/{id}/test

Вызывает один инструмент на сервере с переданными аргументами и возвращает время выполнения, до 4 КБ содержимого и признак того, сообщил ли инструмент об ошибке.

ИмяГдеТипОписание
id
обязательно
path string Id MCP-сервера.
tool
обязательно
body string Имя вызываемого инструмента.
arguments body object Аргументы инструмента в соответствии с его input_schema.

Запрос

curl
curl -X POST "https://hubvocal.com/v1/mcp-servers/mcp_2b8e41/test" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "tool": "find_customer",
  "arguments": {
    "phone": "+905321234567"
  }
}'

Ответ · 200

JSON
{
  "ok": true,
  "ms": 236,
  "content": "{\"customer_id\":\"C-1042\",\"name\":\"Ayşe Yılmaz\",\"open_tickets\":0}",
  "is_error": false
}

Ошибки

  • 404 MCP-сервера с таким id нет.

Webhooks

Список webhooks

GET /v1/webhooks

Webhooks вашей организации с результатом последней доставки. Секрет здесь никогда не возвращается; secret_set показывает, задан ли он.

Запрос

curl
curl "https://hubvocal.com/v1/webhooks" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
[
  {
    "id": "wh_3c9d1e",
    "url": "https://crm.example.com/hooks/voice",
    "events": [
      "call.ended"
    ],
    "enabled": true,
    "secret_set": true,
    "created_at": 1793830000,
    "last_delivery": {
      "status": "ok",
      "at": 1793832440.2,
      "http_status": 200
    }
  }
]

Создать webhook

POST /v1/webhooks

Подписывает URL на события. Сейчас событие одно — call.ended. До 5 webhooks на организацию. Если не указать secret, он будет сгенерирован и вернётся только в этом ответе.

ИмяГдеТипОписание
url
обязательно
body string Ваш эндпоинт. Только https; локальные и частные адреса отклоняются.
events
обязательно
body string[] События, которые нужно получать. Сейчас ["call.ended"].
enabled body boolean Отключённые webhooks ничего не получают.
secret body string Секрет для подписи. Если не указан, генерируется автоматически; возвращается только один раз.

Запрос

curl
curl -X POST "https://hubvocal.com/v1/webhooks" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://crm.example.com/hooks/voice",
  "events": [
    "call.ended"
  ]
}'

Ответ · 201

JSON
{
  "id": "wh_3c9d1e",
  "url": "https://crm.example.com/hooks/voice",
  "events": [
    "call.ended"
  ],
  "enabled": true,
  "secret_set": true,
  "created_at": 1793830000,
  "last_delivery": null,
  "secret": "whsec_9QmZ…"
}

Ошибки

  • 400 URL не https, указывает на частный адрес, или событие неизвестно.
  • 409 У организации уже есть 5 webhooks.

Обновить webhook

PUT /v1/webhooks/{id}

Меняет URL, события или включает и отключает webhook. Отправьте secret: "-", чтобы сгенерировать новый секрет; он вернётся в ответе.

ИмяГдеТипОписание
id
обязательно
path string Id webhook.
url body string Ваш эндпоинт. Только https; локальные и частные адреса отклоняются.
events body string[] События, которые нужно получать. Сейчас ["call.ended"].
enabled body boolean Отключённые webhooks ничего не получают.
secret body string "-" генерирует новый секрет. Не передавайте поле, чтобы сохранить текущий.

Запрос

curl
curl -X PUT "https://hubvocal.com/v1/webhooks/wh_3c9d1e" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "enabled": false
}'

Ответ · 200

JSON
{
  "id": "wh_3c9d1e",
  "url": "https://crm.example.com/hooks/voice",
  "events": [
    "call.ended"
  ],
  "enabled": false,
  "secret_set": true,
  "created_at": 1793830000,
  "last_delivery": {
    "status": "ok",
    "at": 1793832440.2,
    "http_status": 200
  }
}

Ошибки

  • 400 URL не https, указывает на частный адрес, или событие неизвестно.
  • 404 Webhook с таким id нет.

Удалить webhook

DELETE /v1/webhooks/{id}

Удаляет webhook. Доставки, ожидающие отправки, отменяются.

ИмяГдеТипОписание
id
обязательно
path string Id webhook.

Запрос

curl
curl -X DELETE "https://hubvocal.com/v1/webhooks/wh_3c9d1e" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
{
  "deleted": "wh_3c9d1e"
}

Ошибки

  • 404 Webhook с таким id нет.

Проверить webhook

POST /v1/webhooks/{id}/test

Отправляет на URL тестовое событие call.ended и возвращает статус, время ответа и тело ответа.

ИмяГдеТипОписание
id
обязательно
path string Id webhook.

Запрос

curl
curl -X POST "https://hubvocal.com/v1/webhooks/wh_3c9d1e/test" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
{
  "ok": true,
  "http_status": 200,
  "ms": 184,
  "body": "{\"received\":true}"
}

Ошибки

  • 404 Webhook с таким id нет.

Список доставок

GET /v1/webhooks/{id}/deliveries

Последние 50 доставок webhook, от новых к старым: статус (pending, ok, failed), число попыток, HTTP-статус, ошибка и время следующей попытки.

ИмяГдеТипОписание
id
обязательно
path string Id webhook.

Запрос

curl
curl "https://hubvocal.com/v1/webhooks/wh_3c9d1e/deliveries" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
[
  {
    "id": "dl_51b7a9",
    "event": "call.ended",
    "call_id": "demo-8585522d",
    "status": "ok",
    "attempts": 1,
    "http_status": 200,
    "error": null,
    "created_at": 1793832440.2,
    "next_attempt_at": null
  },
  {
    "id": "dl_51a3c4",
    "event": "call.ended",
    "call_id": "tel-6b1f04d2",
    "status": "pending",
    "attempts": 2,
    "http_status": 503,
    "error": "HTTP 503",
    "created_at": 1793832101.7,
    "next_attempt_at": 1793833901.7
  }
]

Ошибки

  • 404 Webhook с таким id нет.

Повторить доставку

POST /v1/webhooks/deliveries/{id}/retry

Снова ставит неудачную доставку в очередь.

ИмяГдеТипОписание
id
обязательно
path string Id доставки из списка доставок.

Запрос

curl
curl -X POST "https://hubvocal.com/v1/webhooks/deliveries/dl_51a3c4/retry" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
{
  "ok": true
}

Ошибки

  • 404 Доставки с таким id нет, или она не завершилась ошибкой.

Голоса и движки

Список движков, голосов и лимитов

GET /v1/voices

Всё, что нужно для формы агента: названия движков, допустимые голоса для каждого движка, диапазоны скорости, языки, предустановки тона, модель за каждым движком и лимиты длины полей. Пример ниже сокращён.

Запрос

curl
curl "https://hubvocal.com/v1/voices" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
{
  "engines": {
    "live": "GPT-Live 1 (OpenAI full-duplex ses modeli)",
    "gemini": "Gemini Live (Google ses-sese model)",
    "realtime": "Realtime (OpenAI ses-sese model)",
    "classic": "Klasik (Deepgram + OpenAI LLM + OpenAI TTS)"
  },
  "voices": {
    "live": [
      "marin",
      "cedar",
      "gleam",
      "meridian"
    ],
    "gemini": [
      "Kore",
      "Aoede",
      "Charon",
      "Puck"
    ],
    "realtime": [
      "marin",
      "cedar",
      "alloy"
    ],
    "classic": [
      "alloy",
      "coral",
      "sage"
    ]
  },
  "speed": {
    "live": {
      "min": 1,
      "max": 1
    },
    "gemini": {
      "min": 1,
      "max": 1
    },
    "realtime": {
      "min": 0.25,
      "max": 1.5
    },
    "classic": {
      "min": 0.25,
      "max": 4
    }
  },
  "langs": {
    "tr": "Türkçe",
    "en": "English"
  },
  "presets": [
    {
      "id": "calm",
      "label": "Sakin ve güven veren",
      "text": "Sakin, yumuşak ve güven veren bir tonla konuş."
    }
  ],
  "models": {
    "live": {
      "model": "gpt-live-1",
      "backend": "gpt-5.6-luna"
    },
    "gemini": {
      "model": "gemini-3.8-live",
      "ready": true
    },
    "realtime": {
      "model": "gpt-realtime-2.1-mini"
    },
    "classic": {
      "stt": "nova-3",
      "llm": "gpt-4.1-mini",
      "tts": "gpt-4o-mini-tts"
    }
  },
  "limits": {
    "tone": 600,
    "instructions": 8000,
    "greeting": 400
  }
}

Звонки

Сроки хранения задаются для организации в панели управления: recordings_days (по умолчанию 30), transcripts_days (по умолчанию 365) и pii_redaction. Ежедневная задача удаляет записи и расшифровки с истёкшим сроком хранения; строка звонка и его стоимость сохраняются.

Веб-виджет: публичные ключи (pk_…) создаются для каждого агента в панели управления. Скрипт виджета вызывает POST /api/public/web-calls; подробнее — в руководстве на странице «Разработчикам».

Начать веб-звонок

POST /v1/web-calls

Открывает комнату для звонка из браузера и возвращает короткоживущий токен доступа. Передайте server_url и token в livekit-client в браузере; агент подключится к комнате сам. Вызывайте этот метод со своего сервера, чтобы API-ключ не попал в браузер. Вместо agent_id можно отправить полный объект agent и проверить черновик без сохранения.

ИмяГдеТипОписание
agent_id body string Id сохранённого агента. Обязателен, если не отправлен agent.
agent body object Полный объект агента (те же поля, что в POST /v1/agents), который используется только для этого звонка.
version body string | integer Какую версию использовать: "live" (по умолчанию), "draft" или номер версии.

Запрос

curl
curl -X POST "https://hubvocal.com/v1/web-calls" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "agent_id": "front-desk"
}'

Ответ · 200

JSON
{
  "server_url": "wss://hubvocal.com",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…",
  "room": "demo-3f9a1c2e",
  "max_seconds": 300
}

Ошибки

  • 400 Не отправлены ни agent_id, ни agent.
  • 402 Организация достигла месячного лимита расходов.
  • 403 Работа организации приостановлена.
  • 404 Агента с таким id нет.

Совершить исходящий звонок

POST /v1/calls

Звонит на номер телефона с одного из номеров вашей организации и подключает агента, когда трубку возьмут. Провайдер (DIDWW, Twilio или ваш SIP-транк) определяется по номеру from.

ИмяГдеТипОписание
from
обязательно
body string Один из номеров вашей организации в формате E.164 (+90…).
to
обязательно
body string Номер, на который нужно позвонить, в формате E.164.
agent_id body string Какой агент будет говорить. Если не указан, отвечает агент, назначенный на номер from.
version body string | integer Какую версию использовать: "live" (по умолчанию), "draft" или номер версии.

Запрос

curl
curl -X POST "https://hubvocal.com/v1/calls" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "from": "+908501234567",
  "to": "+905321234567",
  "agent_id": "front-desk"
}'

Ответ · 200

JSON
{
  "room": "tel-out-9c41e0b7",
  "provider": "didww",
  "sip_call_id": "SCL_7mVt2kQb9xRa"
}

Ошибки

  • 400 Номер не в международном формате или from не входит в ваши номера.
  • 402 Организация достигла месячного лимита расходов.
  • 502 Провайдер телефонии отклонил звонок.

Список звонков

GET /v1/calls

Звонки от новых к старым, веб и телефонные. quality — сводка измерений на стороне браузера; для телефонных звонков null. ended_by: caller, agent, max_call_seconds, caller_unresponsive, agent_unresponsive, no_answer или unknown. channel: web, phone_in или phone_out. В каждой строке также есть outcome и summary_text (первые 160 символов резюме). ended_by равен supervisor, если звонок завершил супервизор из консоли реального времени.

ИмяГдеТипОписание
limit query integer По умолчанию 50, максимум 500.
agent query string Только звонки этого агента (имя агента).
outcome query string Только звонки с этим итогом.

Запрос

curl
curl "https://hubvocal.com/v1/calls?limit=20" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
[
  {
    "room": "demo-8585522d",
    "org_id": "6f1c2a40-3b7e-4d0c-9a51-2f8e7c1d9b03",
    "org_name": "Example Clinic",
    "channel": "web",
    "profile": "Front desk",
    "engine": "live",
    "lang": "en",
    "voice": "marin",
    "started_at": 1793832409.1,
    "ended_at": 1793832434.2,
    "duration_s": 25.1,
    "total_usd": 0.021215,
    "ended_by": "caller",
    "outcome": "message_taken",
    "summary_text": "The caller asked for an appointment on Thursday afternoon; a message was taken for a callback.",
    "extracted": {
      "appointment_date": "2026-11-12",
      "callback": true
    },
    "first_audio_s": 2.43,
    "turns": 4,
    "source_gaps": {
      "count": 0,
      "total_ms": 0,
      "max_ms": 0
    },
    "quality": {
      "verdict": "Clean: no loss, no gaps.",
      "protocol": "UDP",
      "loss_pct": 0,
      "conceal_pct": 0,
      "jitter_ms": 4,
      "rtt_ms": 38
    }
  }
]

Получить звонок

GET /v1/calls/{room}

Полная карточка звонка: разбивка стоимости по провайдерам, расшифровка, время до приветствия, пропуски на стороне агента и шкала качества в браузере окнами по 2 секунды. Поля стоимости зависят от движка (live, llm, stt, tts, realtime…); в каждом есть usd. source_gaps.events содержит пары [секунда, мс]. В summary — text, outcome (resolved, message_taken, transferred, unresolved, no_conversation, spam), sentiment, topics и action_items. В supervisors — кто подключался к звонку из консоли реального времени и в каких режимах. В recording — available, duration_s и size_bytes. В extracted — значения post_call.fields агента (null, если значение не упоминалось).

ИмяГдеТипОписание
room
обязательно
path string Имя комнаты из списка звонков или из POST /v1/web-calls.

Запрос

curl
curl "https://hubvocal.com/v1/calls/demo-8585522d" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
{
  "call": {
    "room": "demo-8585522d",
    "org_id": "6f1c2a40-3b7e-4d0c-9a51-2f8e7c1d9b03",
    "org_name": "Example Clinic",
    "channel": "web",
    "profile": "Front desk",
    "engine": "live",
    "lang": "en",
    "voice": "marin",
    "started_at": 1793832409.1,
    "ended_at": 1793832434.2,
    "duration_s": 25.1,
    "total_usd": 0.021215,
    "ended_by": "caller",
    "outcome": "message_taken",
    "summary_text": "The caller asked for an appointment on Thursday afternoon; a message was taken for a callback.",
    "extracted": {
      "appointment_date": "2026-11-12",
      "callback": true
    },
    "first_audio_s": 2.43,
    "turns": 4,
    "source_gaps": {
      "count": 2,
      "total_ms": 230,
      "max_ms": 141,
      "agent_audio_s": 31.2,
      "events": [
        [
          16.4,
          141
        ],
        [
          40.1,
          89
        ]
      ]
    },
    "quality": {
      "verdict": "Clean: no loss, no gaps.",
      "protocol": "UDP",
      "loss_pct": 0,
      "conceal_pct": 0,
      "jitter_ms": 4,
      "rtt_ms": 38
    },
    "cost": {
      "live": {
        "billed_s": 25.1,
        "reported": true,
        "voice_usd": 0.020917,
        "backend": {
          "in": 1840,
          "cached": 1024,
          "out": 96
        },
        "backend_usd": 0.000298
      },
      "llm": {
        "input_tokens": 1840,
        "cached_tokens": 1024,
        "output_tokens": 96,
        "usd": 0.000298
      },
      "tts": {
        "input_tokens": 0,
        "audio_tokens": 0,
        "audio_s": 25.1,
        "usd": 0.020917
      },
      "stt": {
        "audio_s": 0,
        "usd": 0
      }
    },
    "tools": [
      {
        "t": 14.2,
        "name": "check_order",
        "kind": "read",
        "ok": true,
        "ms": 412,
        "status": 200
      }
    ],
    "outcomes": [],
    "summary": {
      "text": "The caller asked for an appointment on Thursday afternoon; a message was taken for a callback.",
      "language": "en",
      "outcome": "message_taken",
      "sentiment": "neutral",
      "topics": [
        "appointment"
      ],
      "action_items": [
        "Call the caller back on Thursday morning"
      ]
    },
    "recording": {
      "available": true,
      "duration_s": 25.1,
      "size_bytes": 201344
    },
    "supervisors": [
      {
        "user": "ayse@example.com",
        "joined_at": 1793832420.4,
        "left_at": 1793832431,
        "modes": [
          "listen",
          "whisper"
        ]
      }
    ],
    "greeting": {
      "connect_s": 0.15,
      "session_started_s": 0.05,
      "reply_requested_s": 0.05,
      "first_audio_s": 2.4,
      "reply_done_s": 7.1
    },
    "transcript": [
      {
        "role": "assistant",
        "text": "Hello, thanks for calling the clinic. How can I help you today?",
        "t": 2.4,
        "interrupted": false
      },
      {
        "role": "user",
        "text": "I would like an appointment on Thursday afternoon.",
        "t": 9.8
      }
    ]
  },
  "quality": {
    "summary": {
      "verdict": "Clean: no loss, no gaps.",
      "protocol": "UDP",
      "rtt_ms": 38,
      "protocols_seen": [
        "UDP"
      ],
      "loss_pct": 0,
      "conceal_pct": 0,
      "jitter_ms": 4,
      "buffer_ms": 62
    },
    "timeline": [
      {
        "t": 2,
        "loss": 0,
        "conceal": 0,
        "jitter": 3,
        "buffer": 60,
        "proto": "UDP"
      },
      {
        "t": 4,
        "loss": 0,
        "conceal": 0,
        "jitter": 4,
        "buffer": 62,
        "proto": "UDP"
      }
    ]
  }
}

Ошибки

  • 404 Звонок не найден.

Скачать запись

GET /v1/calls/{room}/recording

Аудио звонка в формате OGG/Opus. Поддерживаются Range-запросы. 404, если звонок не записывался или срок хранения записи истёк.

ИмяГдеТипОписание
room
обязательно
path string Имя комнаты из списка звонков или из POST /v1/web-calls.

Запрос

curl
curl "https://hubvocal.com/v1/calls/demo-8585522d/recording" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -o call.ogg

Ответ · 200

audio/ogg
HTTP/1.1 200 OK
Content-Type: audio/ogg
Accept-Ranges: bytes
Content-Length: 201344

<OGG/Opus>

Ошибки

  • 404 Звонок не записывался, или срок хранения записи истёк.

Удалить звонок

DELETE /v1/calls/{room}

Сразу удаляет запись, расшифровку и резюме звонка, например по запросу в рамках KVKK или GDPR. Строка звонка и его стоимость сохраняются.

ИмяГдеТипОписание
room
обязательно
path string Имя комнаты из списка звонков или из POST /v1/web-calls.

Запрос

curl
curl -X DELETE "https://hubvocal.com/v1/calls/demo-8585522d" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
{
  "deleted": "demo-8585522d"
}

Ошибки

  • 404 Звонок не найден.

Экспорт звонков (CSV)

GET /v1/calls/export

Звонки за период в формате CSV, по одной строке на звонок; структурированные поля идут дополнительными столбцами.

ИмяГдеТипОписание
format
обязательно
query string Только csv.
from query date YYYY-MM-DD, включительно.
to query date YYYY-MM-DD, включительно.
agent_id query string Только звонки этого агента.

Запрос

curl
curl "https://hubvocal.com/v1/calls/export?format=csv&from=2026-11-01&to=2026-11-05" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -o calls.csv

Ответ · 200

text/csv
room,started_at,agent,channel,duration_s,total_usd,outcome,appointment_date,callback
demo-8585522d,2026-11-05T09:46:49Z,front-desk,web,25.1,0.021215,message_taken,2026-11-12,true

Номера телефонов

Список номеров телефонов

GET /v1/numbers

Номера телефонов вашей организации и агент, который отвечает на каждом (profile_id), а также готовность каждого провайдера телефонии. Номера добавляет команда платформы, агентов назначаете вы.

Запрос

curl
curl "https://hubvocal.com/v1/numbers" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
{
  "numbers": [
    {
      "number": "+908501234567",
      "provider": "didww",
      "org_id": "6f1c2a40-3b7e-4d0c-9a51-2f8e7c1d9b03",
      "org_name": "Example Clinic",
      "profile_id": "front-desk",
      "label": "Main line"
    }
  ],
  "sip": {
    "enabled": true,
    "room_prefix": "tel-",
    "providers": {
      "didww": {
        "inbound_ips": "46.19.209.14,46.19.210.14",
        "inbound_auth": false,
        "outbound_host": "trunk.example.com",
        "outbound_auth": true,
        "outbound_ready": true,
        "inbound_ready": true
      }
    }
  }
}

Назначить агента на номер

PUT /v1/numbers/{number}

Выбирает агента, который отвечает на входящие звонки на этот номер. Чтобы снять назначение, отправьте agent_id: null. Знак + в номере кодируйте в пути как %2B (префикс 00 тоже подходит).

ИмяГдеТипОписание
number
обязательно
path string Номер в формате E.164, закодированный для URL.
agent_id body string | null Агент, который отвечает на входящие звонки.
label body string Заметка для команды, до 60 символов.

Запрос

curl
curl -X PUT "https://hubvocal.com/v1/numbers/%2B908501234567" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "agent_id": "front-desk",
  "label": "Main line"
}'

Ответ · 200

JSON
{
  "ok": true
}

Ошибки

  • 400 Такого агента нет.
  • 404 Номер не принадлежит вашей организации.

Потребление

Потребление

GET /v1/usage

Звонки, минуты и затраты на провайдеров для вашей организации — по провайдерам и по дням (Europe/Istanbul). По умолчанию — текущий месяц. kind: llm, tts, stt или voice (движки «речь в речь»).

ИмяГдеТипОписание
from query date YYYY-MM-DD, включительно.
to query date YYYY-MM-DD, включительно.

Запрос

curl
curl "https://hubvocal.com/v1/usage?from=2026-11-01&to=2026-11-05" \
  -H "Authorization: Bearer $VT_API_KEY"

Ответ · 200

JSON
{
  "from": "2026-11-01",
  "to": "2026-11-05",
  "totals": {
    "calls": 42,
    "minutes": 81.2,
    "usd": 3.94
  },
  "by_provider": [
    {
      "provider": "openai",
      "model": "gpt-live-1",
      "kind": "voice",
      "calls": 30,
      "input_tokens": 0,
      "cached_tokens": 0,
      "output_tokens": 0,
      "audio_s": 2900.1,
      "usd": 2.41
    }
  ],
  "by_day": [
    {
      "date": "2026-11-05",
      "usd": 1.2,
      "minutes": 20.5,
      "calls": 9
    }
  ],
  "by_org": [
    {
      "org_id": "6f1c2a40-3b7e-4d0c-9a51-2f8e7c1d9b03",
      "org_name": "Example Clinic",
      "usd": 3.94,
      "minutes": 81.2,
      "calls": 42
    }
  ]
}

Спецификация

Спецификация OpenAPI

GET /v1/openapi.json Ключ не нужен

Документ OpenAPI 3.1 для этого API. Ключ не нужен. Импортируйте его в Postman, Insomnia или генератор клиентов.

Запрос

curl
curl "https://hubvocal.com/v1/openapi.json"

Ответ · 200

JSON
{
  "openapi": "3.1.0",
  "info": {
    "title": "HubVocal API",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://hubvocal.com/v1"
    }
  ],
  "paths": {}
}