Follow-up по одному звонку
⚠️ Метод выходит в обновлении
call 26.600.0и доступен пока не на всех порталах Битрикс24. Если обновление на ваш портал ещё не пришло, API вернёт422 METHOD_NOT_YET_AVAILABLE— это признак того, что метод на портале ещё не выпущен, а не ошибка интеграции.
GET /v1/calls/followups/:callId
Возвращает AI Follow-up одного завершённого звонка.
Параметры
| Параметр | Тип | Обяз. | Описание |
|---|---|---|---|
callId (path) |
integer | да | Идентификатор звонка. Положительное целое. Где взять — POST /v1/calls/followups/list |
select (query) |
string[] | нет | Какие поля вернуть. Передаётся повторяющимся параметром или списком через запятую. Словарь значений общий со списком — раздел «Поле select» страницы Список Follow-up |
mentionFormat (query) |
string | нет | Формат @-упоминаний в текстовых полях: bb, html или none. По умолчанию — bb |
Поле select
Значение select |
Что в ответе |
|---|---|
| Не указан | Полный объект Follow-up. Присутствуют все поля, отсутствующие данные приходят как null |
| Пустой массив | Только базовые метаданные: callId, callType, initiatorId, startDate, endDate, durationSeconds |
| Список полей | Только перечисленные поля и всегда callId. Запрошенное, но незаполненное поле приходит как null |
Примеры
Запрос без select — возвращается весь Follow-up целиком. mentionFormat: none убирает разметку упоминаний, поэтому текст готов к передаче в нейросеть или к сохранению в задачу. Чтобы забрать только часть блоков, добавьте select — например ?select=overview.actionItems&select=evaluation.efficiencyValue.
curl — личный ключ
curl "https://vibecode.bitrix24.tech/v1/calls/followups/12345?mentionFormat=none" \
-H "X-Api-Key: YOUR_API_KEY"
curl — OAuth-приложение
curl "https://vibecode.bitrix24.tech/v1/calls/followups/12345?mentionFormat=none" \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN"
JavaScript — личный ключ
const params = new URLSearchParams({ mentionFormat: 'none' })
const res = await fetch(`https://vibecode.bitrix24.tech/v1/calls/followups/12345?${params}`, {
headers: { 'X-Api-Key': 'YOUR_API_KEY' },
})
const body = await res.json()
if (!body.success) {
// Ошибку разбираем явно: иначе на 403 или 422 код упадёт на обращении к data
throw new Error(`${body.error.code}: ${body.error.message}`)
}
const { data } = body
const call = data.item
// Готовые AI-блоки перечислены в outcomes, неготовые приходят как null
console.log(call.outcomes, `${call.durationSeconds} сек`)
console.log(call.overview?.topic ?? 'обзор ещё не сформирован')
for (const item of call.overview?.actionItems ?? []) {
console.log('задача:', item.actionItem, '— цитата:', item.quote)
}
// speakerAnalysis отсутствует, если разбор участников на портале недоступен
for (const speaker of call.insights?.speakerAnalysis ?? []) {
console.log(`участник ${speaker.userId}: ${speaker.talkPercentage}% времени, оценка ${speaker.efficiencyValue}`)
}
// Критерии — карта, ключи зависят от типа встречи: обходим по ключам
for (const [code, criterion] of Object.entries(call.evaluation?.criteria ?? {})) {
console.log(code, criterion.value ? 'выполнен' : 'не выполнен', '—', criterion.thoughts)
}
JavaScript — OAuth-приложение
const params = new URLSearchParams({ mentionFormat: 'none' })
const res = await fetch(`https://vibecode.bitrix24.tech/v1/calls/followups/12345?${params}`, {
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
},
})
const body = await res.json()
if (!body.success) {
// Ошибку разбираем явно: иначе на 403 или 422 код упадёт на обращении к data
throw new Error(`${body.error.code}: ${body.error.message}`)
}
const { data } = body
console.log(data.item)
Поля ответа
| Поле | Тип | Описание |
|---|---|---|
success |
boolean | Всегда true при успехе |
data.item |
object | Follow-up звонка. Поля — в таблице ниже |
Поля объекта item:
| Поле | Тип | Описание |
|---|---|---|
item.callId |
number | Идентификатор звонка |
item.callType |
number | Вид звонка: 1 — мгновенный, 2 — конференция, 3 — большая комната |
item.initiatorId |
number | Инициатор звонка. Карточка сотрудника — GET /v1/users/:id |
item.startDate |
string | Начало звонка, ISO 8601 в UTC |
item.endDate |
string | null | Окончание звонка, ISO 8601 в UTC |
item.durationSeconds |
number | Длительность звонка в секундах |
item.uuid |
string | Идентификатор сессии звонка |
item.language |
string | Код языка транскрипции |
item.version |
number | Версия схемы AI-данных |
item.participants |
object[] | Участники звонка |
item.outcomes |
string[] | Готовые AI-блоки этого звонка |
item.createdAt |
string | Время последней AI-записи |
item.tracks |
object[] | Записи звонка |
item.transcription |
object | null | Транскрипция разговора |
item.overview |
object | null | Обзор встречи |
item.summary |
object | null | Краткое изложение по фрагментам |
item.evaluation |
object | null | Оценка эффективности встречи |
item.insights |
object | null | Аналитические выводы и разбор участников |
Участники — `participants[]`
| Поле | Тип | Описание |
|---|---|---|
userId |
number | Идентификатор сотрудника |
name |
string | Имя сотрудника |
avatar |
string | Ссылка на аватар |
workPosition |
string | Должность |
talkedSeconds |
number | Сколько секунд участник говорил |
Записи звонка — `tracks[]`
| Поле | Тип | Описание |
|---|---|---|
trackId |
number | Идентификатор записи |
type |
string | Вид дорожки, например mixed_audio |
duration |
number | Длительность записи в секундах |
fileName |
string | Имя файла |
mimeType |
string | MIME-тип файла |
url |
string | Ссылка на скачивание |
dateCreate |
string | Когда запись создана, ISO 8601 |
Транскрипция — `transcription`
| Поле | Тип | Описание |
|---|---|---|
language |
string | Код языка расшифровки |
segments[] |
object[] | Реплики в хронологическом порядке |
segments[].userId |
number | Кто говорит |
segments[].userName |
string | Имя говорящего |
segments[].start |
number | Начало реплики, секунды от начала звонка |
segments[].end |
number | Конец реплики, секунды от начала звонка |
segments[].text |
string | Текст реплики |
Обзор встречи — `overview`
| Поле | Тип | Описание |
|---|---|---|
topic |
string | Тема встречи |
detailedTakeaways |
string | Развёрнутые выводы |
meetingType |
object | Тип встречи: typeTag — код, title — название, explanation — обоснование |
agenda |
object | Повестка: explanation — формулировка, quote — цитата из разговора |
agreements[] |
object[] | Договорённости: agreement — формулировка, quote — цитата |
actionItems[] |
object[] | Задачи: actionItem — формулировка, quote — цитата |
meetings[] |
object[] | Назначенные встречи: meeting — формулировка, quote — цитата |
Краткое изложение — `summary`
| Поле | Тип | Описание |
|---|---|---|
segments[] |
object[] | Фрагменты разговора |
segments[].start |
number | Начало фрагмента, секунды |
segments[].end |
number | Конец фрагмента, секунды |
segments[].title |
string | Заголовок фрагмента |
segments[].summary |
string | Изложение фрагмента |
Аналитические выводы — `insights`
| Поле | Тип | Описание |
|---|---|---|
speakerEvaluationAvailable |
boolean | Доступен ли разбор участников на портале |
speakerAnalysis[] |
object[] | Разбор участников, по убыванию talkPercentage |
speakerAnalysis[].userId |
number | Идентификатор сотрудника. Карточка — GET /v1/users/:id |
speakerAnalysis[].detailedInsight |
string | Вывод по участнику |
speakerAnalysis[].efficiencyValue |
number | Оценка эффективности участника, от 0 до 100 |
speakerAnalysis[].evaluationCriteria |
string | Критерий, по которому дана оценка |
speakerAnalysis[].talkPercentage |
number | Доля времени, которую участник говорил, в процентах |
speakerAnalysis[].duration |
number | Сколько секунд участник говорил |
speakerAnalysis[].durationFormat |
string | То же время в виде ММ:СС |
meetingStrengths[] |
object[] | Сильные стороны: strengthTitle и strengthExplanation |
meetingWeaknesses[] |
object[] | Слабые стороны: weaknessTitle и weaknessExplanation |
speechStyleInfluence |
string | Как манера речи повлияла на встречу |
engagementLevel |
string | Вовлечённость участников |
areasOfResponsibility |
string | Кто за что отвечает по итогам |
finalRecommendations |
string | Рекомендации к следующей встрече |
Оценка эффективности — `evaluation`
| Поле | Тип | Описание |
|---|---|---|
efficiencyValue |
number | Общая эффективность встречи, от 0 до 100 |
calendar.overhead |
boolean | Была ли встреча избыточной по времени |
criteria |
object | Карта критериев. Ключ — код критерия, значение — объект с полями ниже |
criteria.<код>.value |
boolean | Выполнен ли критерий |
criteria.<код>.title |
string | Название критерия |
criteria.<код>.criteria |
string | Формулировка критерия |
criteria.<код>.thoughts |
string | Обоснование оценки |
Пример ответа
{
"success": true,
"data": {
"item": {
"callId": 12345,
"callType": 1,
"initiatorId": 7,
"startDate": "2026-01-15T10:00:00+00:00",
"endDate": "2026-01-15T10:42:00+00:00",
"durationSeconds": 2520,
"uuid": "bb085e5d-5160-4a63-9ac4-152248046c39",
"language": "ru",
"version": 3,
"participants": [
{ "userId": 7, "name": "Иван Петров", "workPosition": "Руководитель проекта", "talkedSeconds": 600 }
],
"outcomes": ["transcription", "overview", "summary", "insights", "evaluation"],
"createdAt": "2026-01-15T11:05:00+00:00",
"tracks": [
{ "trackId": 100, "type": "mixed_audio", "duration": 2520, "fileName": "call_12345.wav", "mimeType": "audio/wav", "url": "https://example.bitrix24.ru/disk/call_12345.wav", "dateCreate": "2026-01-15T11:00:00+00:00" }
],
"transcription": {
"language": "ru",
"segments": [
{ "userId": 7, "userName": "Иван Петров", "start": 12, "end": 25, "text": "Давайте зафиксируем объём спринта. Что берём в работу?" },
{ "userId": 42, "userName": "Мария Иванова", "start": 26, "end": 48, "text": "Предлагаю оставить только импорт каталога, остальное не успеем." },
{ "userId": 7, "userName": "Иван Петров", "start": 49, "end": 70, "text": "Согласен. Тогда прототип показываем в пятницу." }
]
},
"overview": {
"topic": "Планирование спринта",
"detailedTakeaways": "Команда сократила объём спринта до импорта каталога и договорилась показать прототип в пятницу.",
"meetingType": {
"typeTag": "planning",
"title": "Планирование",
"explanation": "Участники распределяли задачи и сроки на ближайшую итерацию."
},
"agenda": {
"explanation": "Определить объём спринта и сроки демонстрации.",
"quote": "Давайте зафиксируем объём спринта."
},
"agreements": [
{ "agreement": "В спринт берём только импорт каталога", "quote": "Предлагаю оставить только импорт каталога, остальное не успеем." }
],
"actionItems": [
{ "actionItem": "Подготовить прототип к пятнице", "quote": "Тогда прототип показываем в пятницу." }
],
"meetings": [
{ "meeting": "Демонстрация прототипа в пятницу", "quote": "Тогда прототип показываем в пятницу." }
]
},
"summary": {
"segments": [
{ "start": 0, "end": 600, "title": "Объём спринта", "summary": "Обсудили, что успеет команда, и сократили набор задач до импорта каталога." },
{ "start": 601, "end": 2520, "title": "Сроки и демонстрация", "summary": "Договорились показать прототип в пятницу и вернуться к остальным задачам в следующем спринте." }
]
},
"insights": {
"speakerEvaluationAvailable": true,
"speakerAnalysis": [
{
"userId": 42,
"detailedInsight": "Участник предложил сократить объём и обосновал это оценкой сроков.",
"efficiencyValue": 82,
"evaluationCriteria": "Конструктивность предложений",
"talkPercentage": 66,
"duration": 1200,
"durationFormat": "20:00"
},
{
"userId": 7,
"detailedInsight": "Участник вёл встречу и зафиксировал договорённости.",
"efficiencyValue": 74,
"evaluationCriteria": "Управление обсуждением",
"talkPercentage": 34,
"duration": 600,
"durationFormat": "10:00"
}
],
"meetingStrengths": [
{ "strengthTitle": "Чёткий итог", "strengthExplanation": "Встреча завершилась зафиксированным решением и сроком." }
],
"meetingWeaknesses": [
{ "weaknessTitle": "Неравное участие", "weaknessExplanation": "Две трети времени говорил один участник." }
],
"speechStyleInfluence": "Спокойный темп речи помог быстро прийти к решению.",
"engagementLevel": "Высокая вовлечённость обоих участников.",
"areasOfResponsibility": "Импорт каталога закреплён за Марией Ивановой.",
"finalRecommendations": "Заранее рассылать повестку, чтобы сократить обсуждение объёма."
},
"evaluation": {
"efficiencyValue": 75,
"calendar": { "overhead": false },
"criteria": {
"agenda_defined": {
"value": true,
"criteria": "Повестка обозначена в начале встречи",
"title": "Повестка",
"thoughts": "Ведущий сформулировал цель первой репликой."
},
"decisions_made": {
"value": true,
"criteria": "Приняты решения по обсуждаемым вопросам",
"title": "Решения",
"thoughts": "Объём спринта и срок демонстрации зафиксированы."
},
"all_participants_involved": {
"value": false,
"criteria": "Все участники вовлечены в обсуждение",
"title": "Вовлечённость",
"thoughts": "Распределение реплик — 66 на 34 процента."
}
}
}
}
}
}
Ключи в evaluation.criteria — коды критериев. Их набор зависит от типа встречи, поэтому обходите карту по ключам, а не по фиксированному списку.
Пример ответа при ошибке
422 — звонок не найден или его Follow-up недоступен:
{
"success": false,
"error": {
"code": "BITRIX_ERROR",
"message": "Нет доступа к данным Follow-up"
}
}
Текст error.message приходит от Битрикс24, поэтому его формулировка и язык зависят от языка портала. Ветвитесь по error.code, а не по тексту сообщения.
Ошибки
| HTTP | Код | Описание |
|---|---|---|
| 400 | INVALID_PARAMS |
callId в пути — не положительное целое число. Проверяется до обращения к Битрикс24 |
| 400 | INVALID_PARAMS |
Значение query-параметра вне списка допустимых — например mentionFormat. Если Битрикс24 отклонил значение по полю, ответ дополнительно содержит массив error.validation с именем поля |
| 401 | MISSING_API_KEY |
Не передан заголовок X-Api-Key |
| 401 | TOKEN_MISSING |
У ключа нет токенов портала. Ключ OAuth-приложения требует заголовок Authorization: Bearer |
| 403 | SCOPE_DENIED |
У ключа нет скоупа call |
| 403 | BITRIX_ACCESS_DENIED |
Битрикс24 отказал в доступе: у веб-хука ключа нет права call на стороне портала. Переподключите ключ с нужным правом |
| 422 | METHOD_NOT_YET_AVAILABLE |
Обновление call 26.600.0 на портале ещё не выпущено. Ответ содержит поле error.release с целевой версией |
| 422 | BITRIX_ERROR |
Запрос отклонён Битрикс24. Звонка с таким callId нет либо к его Follow-up нет доступа — сообщение «Нет доступа к данным Follow-up». Причина конкретного отказа — в error.message |
| 429 | RATE_LIMITED |
Превышена частота запросов на стороне Битрикс24 |
| 429 | QUEUE_OVERFLOW, QUEUE_TIMEOUT |
Очередь запросов портала переполнена или запрос не дождался очереди. Заголовок Retry-After подсказывает задержку перед повтором |
| 503 | BITRIX_TIMEOUT |
Битрикс24 принял запрос, но не ответил за 15 секунд. Для чтения повтор безопасен |
| 502 | BITRIX_UNAVAILABLE |
Битрикс24 недоступен |
Полный список общих ошибок API — Ошибки.
Известные особенности
Отличить несуществующий звонок от отказа в доступе по ответу нельзя. Оба случая приходят одинаковым ответом. Список Follow-up тоже не даёт ответа: в него попадают только звонки с готовым Follow-up и только те, к которым у сотрудника есть доступ, — отсутствие звонка в списке не означает, что звонка нет.
Звонки без AI-обработки. Если звонок завершён, но Follow-up по нему не сформирован, метод возвращает объект с метаданными: AI-блоки приходят как null, а outcomes — пустым массивом.
Разбор участников доступен не на каждом портале. Если на портале он недоступен, блок insights приходит с speakerEvaluationAvailable: false и пустым разбором участников. Это не ошибка запроса — структура ответа не меняется.
Доступ ограничен правами сотрудника. Follow-up доступен тому, кто участвовал в звонке или состоит в связанном чате — в том числе если его добавили в чат уже после разговора. Администратор портала видит Follow-up любого звонка портала.