Skip to main content

Отдельные звонки

POST /v1/calls/phone

Один исходящий звонок: платформа регистрирует звонок, сразу отвечает и набирает номер из устойчивой очереди набора через указанный транк, подключая опубликованного агента, когда абонент ответит. Нормализация номера. Из to_number убираются все нецифровые символы ("+1 (555) 123-4567""15551234567"). Номер без цифр отклоняется с 400. Если группа задаёт префикс набора, он добавляется к нормализованному номеру; разрешённые направления проверяются по нормализованному номеру до префикса. Порядок проверок. Потолок очереди набора (429 dial_queue_full) проверяется первым, до всякой валидации. Затем синхронно и до регистрации звонка: транк и грант (404), группа и привязка агента (404/409/403), номер звонящего (400), политика направлений (403), лимиты группы (429), ring_duration (400) и в конце — опубликованная версия агента (409). Отказ на любом из этих шагов не оставляет звонка. Поскольку лимиты проверяются до проверки публикации, 429 не говорит вам, опубликован ли агент. Заголовок Idempotency-Key здесь рекомендуется (и фактически обязателен после 429): повтор с тем же ключом возвращает уже созданный звонок вместо второго набора. Ключи помнятся сутки и ограничены вашим API-ключом и эндпоинтом. Переигровка возвращает объект звонка в том виде, в котором он был при создании (status: "queued"), а не его текущее состояние — для этого опрашивайте GET /v1/calls/{call_id}.
Успех — 202 Accepted, а не 201. Звонок зарегистрирован и поставлен в очередь набора; сам набор происходит асинхронно после ответа. Сохраните call_id: это ключ сопоставления для опроса и для каждого вебхука.
Ошибки инициации звонка

Объект звонка

Приходит в POST /v1/calls/phone, GET /v1/calls/{call_id} и POST /v1/calls/{call_id}/end. Жизненный цикл: queued (набор инициирован, дозвона ещё нет) → ringingongoing (абонент ответил) → ended (разговор состоялся, включая сообщения на автоответчик и переводы) либо failed.
failed сам по себе не означает, что абонент не ответил. Обычно он приходит с call_status: "not_connected" (no_answer, busy, dial_failed, …), но сбой платформы тоже читается как failed с call_status: "error" (internal_error, not_finalized, agent_unavailable). Всегда читайте call_status / status_reason.
Веб-звонки пропускают ringing и failed: они идут queuedongoing (первая реплика истории) → ended. Асинхронные поля заполняются после завершения звонка: call_analysis — когда закончится пост-анализ, recording_url — когда финализируется запись. Вебхук call_analyzed сообщает, когда готово и то, и другое, — опрос это запасной путь, а не основной механизм.

Чтение и завершение звонка

GET /v1/calls/{call_id} возвращает полный объект звонка; на неизвестный идентификатор — 404 call_not_found. POST /v1/calls/{call_id}/end завершает живой звонок — телефонный звонок, ещё стоящий в очереди набора, отменяется до набора — и возвращает объект звонка.
end идемпотентен только внутри окна живого реестра: вызов на звонке, который закончился менее 5 минут назад, вернёт объект без ошибки; после этого запись в реестре исчезает и эндпоинт отвечает 404 call_not_found, хотя GET /v1/calls/{call_id} по-прежнему возвращает сохранённый объект. Не используйте end как способ прочитать состояние.
GET /v1/calls/{call_id}/turns отдаёт метрики задержек по тёрнам завершённого телефонного или веб-звонка: массив {"turn", "metrics": {"vad_ms", "asr_ms", "eou_wait_ms", "classifier_ms", "llm_ms", "tts_ms", "turn_ms", …, "estimated"?: true}, "interrupted"?: true, "merged_from"?: number}. Диагностическая поверхность для нагрузочных тестов; 404 на неизвестные идентификаторы и на сессии, не являющиеся звонком. merged_from появляется у тёрна абонента, чью фразу расколола пауза и которую склеили обратно: это число обрывков, а фазы тёрна взяты у первого из них. Ключ аддитивный: клиент, который его не читает, разбирает ответ обычным образом. Метрики llm_first_sentence_ms в ответе нет.

GET /v1/calls — список звонков

Ответ: {calls: [...], has_more, next_cursor}. Элементы списка — сводки без транскрипта; полный объект — GET /v1/calls/{call_id}. Идите по страницам, передавая next_cursor как cursor, пока has_more не станет false. В списке только телефонные и веб-звонки; тестовые сессии редактора и чаты в него не попадают.
from_number / to_number — фильтры уровня страницы: страница может содержать меньше limit элементов (в том числе ноль), пока has_more всё ещё true. Не считайте пустую страницу концом результатов. Для сверки по номерам лучше фильтровать по своей metadata на своей стороне.