For AI agents: markdown of this page — /docs-content-en/calls/followup/list.md documentation index — /llms.txt
Follow-up list
⚠️ The method ships in update
call 26.600.0and is not yet available on all Bitrix24 accounts. If the update has not reached your account yet, the API returns422 METHOD_NOT_YET_AVAILABLE— this means the method has not been released on the account, not that the integration is broken.
POST /v1/calls/followups/list
Returns a list of AI Follow-ups for completed calls within the specified period. Pagination through the results is cursor-based.
Request fields (body)
| Field | Type | Req. | Description |
|---|---|---|---|
filter |
object | yes | Filter conditions. Without this object the request is rejected |
filter.startDate.from |
string | yes | Start of the period, ISO 8601 — 2026-01-01T00:00:00Z |
filter.startDate.to |
string | yes | End of the period, ISO 8601. A value earlier than from is rejected |
filter.participantId |
integer | no | Filter by a single participant. Available to the Bitrix24 account administrator only: a regular employee cannot filter by another participant. List of employees — GET /v1/users |
select |
string[] | no | Which fields to return. Allowed values — in the "Select field" section |
order |
object | no | Sorting by start date: { "startDate": "asc" } or { "startDate": "desc" }. Defaults to desc |
pagination |
object | no | Page size and cursor. Rules — in the "Navigation" section |
pagination.limit |
integer | no | Records per page. Defaults to 50, maximum 200. Selecting data-heavy fields lowers the maximum to 20 |
pagination.afterCursor |
object | no | Cursor of the next page. Copied as a whole from data.afterCursor of the previous response. Not passed in the first request |
mentionFormat |
string | no | Format of @-mentions in text fields: bb, html or none. Defaults to bb |
Select field
Without select only call metadata is returned. The remaining fields are requested explicitly. An unknown value is rejected with 422 BITRIX_ERROR and a message that names the rejected field.
Metadata
| Value | What is returned |
|---|---|
callId, callType, initiatorId, startDate, endDate, durationSeconds |
Base fields. Always returned in the list |
uuid |
Call session identifier |
participants |
List of participants |
tracks |
Call recordings with download links |
outcomes |
List of the AI blocks that are ready |
language |
Transcription language |
version |
Version of the AI data schema |
createdAt |
Time of the last AI record |
AI blocks
A block is requested either as a whole or as an individual subfield using dot notation.
| Block | Subfields |
|---|---|
transcription |
transcription.language, transcription.segments |
overview |
overview.topic, overview.detailedTakeaways, overview.meetingType, overview.agenda, overview.agreements, overview.actionItems, overview.meetings |
summary |
Requested only as a whole |
insights |
insights.speakerEvaluationAvailable, insights.speakerAnalysis, insights.meetingStrengths, insights.meetingWeaknesses, insights.speechStyleInfluence, insights.engagementLevel, insights.areasOfResponsibility, insights.finalRecommendations |
evaluation |
evaluation.efficiencyValue, evaluation.calendar, evaluation.criteria |
Selection rules:
- Requesting a whole block (
["overview"]) returns all of its subfields. - Requesting a subfield (
["overview.topic"]) returns only that subfield — the rest are omitted. transcription,transcription.segments,overviewandinsightscontain a lot of data. Selecting them lowers the maximum page size to 20 records.
Navigation
- The first request is sent without
pagination.afterCursor. - If
hasMorein the response istrue, copy the wholedata.afterCursorobject intopagination.afterCursorof the next request. - Repeat until
hasMorebecomesfalse.
pagination.limit — defaults to 50, maximum 200. Selecting data-heavy fields lowers the maximum to 20.
{ "pagination": { "limit": 50, "afterCursor": { "startDate": "2026-01-12T14:30:00.000000+00:00", "id": 12330 } } }
Mention format
mentionFormat controls how @-mentions of employees look in all AI text fields — transcription.segments[].text, overview.*, insights.*, evaluation.criteria.*.thoughts.
| Value | Text in the response | When to choose |
|---|---|---|
bb |
[USER=7]John Smith[/USER] |
Rendering in an interface that supports BB code |
html |
<span class="bx-call-mention" …>John Smith</span> |
Rendering on the web |
none |
John Smith |
Passing the text to an AI model, search, export |
Examples
A review of one employee's meetings for January: we take the call metadata, the topic, the agreements and the action items from the overview, plus the participant analysis and the overall score. Results are sorted newest first, and mentions arrive as plain text. This is the first request, so it has no afterCursor — the cursor for the next page arrives in the response.
curl — personal key
curl -X POST https://vibecode.bitrix24.com/v1/calls/followups/list \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filter": {
"startDate": { "from": "2026-01-01T00:00:00Z", "to": "2026-01-31T23:59:59Z" },
"participantId": 42
},
"select": [
"callId", "startDate", "durationSeconds", "participants", "outcomes",
"overview.topic", "overview.agreements", "overview.actionItems",
"insights.speakerAnalysis", "evaluation.efficiencyValue"
],
"order": { "startDate": "desc" },
"pagination": { "limit": 20 },
"mentionFormat": "none"
}'
curl — OAuth application
curl -X POST https://vibecode.bitrix24.com/v1/calls/followups/list \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"filter": {
"startDate": { "from": "2026-01-01T00:00:00Z", "to": "2026-01-31T23:59:59Z" },
"participantId": 42
},
"select": [
"callId", "startDate", "durationSeconds", "participants", "outcomes",
"overview.topic", "overview.agreements", "overview.actionItems",
"insights.speakerAnalysis", "evaluation.efficiencyValue"
],
"order": { "startDate": "desc" },
"pagination": { "limit": 20 },
"mentionFormat": "none"
}'
JavaScript — personal key
const res = await fetch('https://vibecode.bitrix24.com/v1/calls/followups/list', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
filter: {
startDate: { from: '2026-01-01T00:00:00Z', to: '2026-01-31T23:59:59Z' },
participantId: 42,
},
select: [
'callId', 'startDate', 'durationSeconds', 'participants', 'outcomes',
'overview.topic', 'overview.agreements', 'overview.actionItems',
'insights.speakerAnalysis', 'evaluation.efficiencyValue',
],
order: { startDate: 'desc' },
pagination: { limit: 20 },
mentionFormat: 'none',
}),
})
const body = await res.json()
if (!body.success) {
// Handle the error explicitly: otherwise on 403 or 422 the code fails when accessing data
throw new Error(`${body.error.code}: ${body.error.message}`)
}
const { data } = body
for (const call of data.items) {
// AI blocks are not ready for every call: some of them arrive as null
const topic = call.overview?.topic ?? 'topic not determined'
const score = call.evaluation?.efficiencyValue ?? '—'
console.log(call.startDate, topic, `score: ${score}`)
for (const item of call.overview?.actionItems ?? []) {
console.log(' action item:', item.actionItem)
}
}
// Next page: put the cursor from the response into pagination.afterCursor of the new request
console.log(data.hasMore, data.afterCursor)
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/calls/followups/list', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
filter: {
startDate: { from: '2026-01-01T00:00:00Z', to: '2026-01-31T23:59:59Z' },
participantId: 42,
},
select: [
'callId', 'startDate', 'durationSeconds', 'participants', 'outcomes',
'overview.topic', 'overview.agreements', 'overview.actionItems',
'insights.speakerAnalysis', 'evaluation.efficiencyValue',
],
order: { startDate: 'desc' },
pagination: { limit: 20 },
mentionFormat: 'none',
}),
})
const body = await res.json()
if (!body.success) {
// Handle the error explicitly: otherwise on 403 or 422 the code fails when accessing data
throw new Error(`${body.error.code}: ${body.error.message}`)
}
const { data } = body
console.log(data.items, data.hasMore, data.afterCursor)
Response fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Always true on success |
data.items |
object[] | Array of Follow-ups. Element fields — in the table below |
data.hasMore |
boolean | Whether there are records beyond the current page |
data.afterCursor |
object | null | Cursor of the next page. null — there are no more records |
Fields of an array element:
| Field | Type | Description |
|---|---|---|
items[].callId |
number | Call identifier. Passed to GET /v1/calls/followups/:callId |
items[].callType |
number | Call type: 1 — instant, 2 — conference, 3 — big room |
items[].initiatorId |
number | Call initiator. Employee profile — GET /v1/users/:id |
items[].startDate |
string | Call start, ISO 8601 in UTC |
items[].endDate |
string | null | Call end, ISO 8601 in UTC |
items[].durationSeconds |
number | Call duration in seconds |
items[].uuid |
string | Call session identifier |
items[].language |
string | Transcription language code |
items[].version |
number | Version of the AI data schema |
items[].participants |
object[] | Call participants |
items[].outcomes |
string[] | AI blocks already generated for this call |
items[].createdAt |
string | Time of the last AI record |
items[].tracks |
object[] | Call recordings |
items[].transcription |
object | Transcription of the conversation |
items[].overview |
object | Meeting overview |
items[].summary |
object | Fragment-by-fragment summary |
items[].evaluation |
object | Meeting efficiency score |
items[].insights |
object | Insights and participant analysis |
Participants — `participants[]`
| Field | Type | Description |
|---|---|---|
userId |
number | Employee identifier |
name |
string | Employee name |
avatar |
string | Link to the avatar |
workPosition |
string | Job title |
talkedSeconds |
number | How many seconds the participant spoke |
Call recordings — `tracks[]`
| Field | Type | Description |
|---|---|---|
trackId |
number | Recording identifier |
type |
string | Track type, for example mixed_audio |
duration |
number | Recording duration in seconds |
fileName |
string | File name |
mimeType |
string | MIME type of the file |
url |
string | Download link |
dateCreate |
string | When the recording was created, ISO 8601 |
Transcription — `transcription`
| Field | Type | Description |
|---|---|---|
language |
string | Transcript language code |
segments[] |
object[] | Utterances in chronological order |
segments[].userId |
number | Who is speaking |
segments[].userName |
string | Speaker name |
segments[].start |
number | Start of the utterance, seconds from the start of the call |
segments[].end |
number | End of the utterance, seconds from the start of the call |
segments[].text |
string | Text of the utterance |
Meeting overview — `overview`
| Field | Type | Description |
|---|---|---|
topic |
string | Meeting topic |
detailedTakeaways |
string | Detailed takeaways |
meetingType |
object | Meeting type: typeTag — code, title — name, explanation — justification |
agenda |
object | Agenda: explanation — wording, quote — quote from the conversation |
agreements[] |
object[] | Agreements: agreement — wording, quote — quote |
actionItems[] |
object[] | Action items: actionItem — wording, quote — quote |
meetings[] |
object[] | Scheduled meetings: meeting — wording, quote — quote |
Summary — `summary`
| Field | Type | Description |
|---|---|---|
segments[] |
object[] | Fragments of the conversation |
segments[].start |
number | Start of the fragment, seconds |
segments[].end |
number | End of the fragment, seconds |
segments[].title |
string | Fragment title |
segments[].summary |
string | Summary of the fragment |
Insights — `insights`
| Field | Type | Description |
|---|---|---|
speakerEvaluationAvailable |
boolean | Whether participant analysis is available on the Bitrix24 account |
speakerAnalysis[] |
object[] | Participant analysis, in descending order of talkPercentage |
speakerAnalysis[].userId |
number | Employee identifier. Profile — GET /v1/users/:id |
speakerAnalysis[].detailedInsight |
string | Conclusion about the participant |
speakerAnalysis[].efficiencyValue |
number | Participant efficiency score, from 0 to 100 |
speakerAnalysis[].evaluationCriteria |
string | The criterion the score was based on |
speakerAnalysis[].talkPercentage |
number | Share of the time the participant spoke, in percent |
speakerAnalysis[].duration |
number | How many seconds the participant spoke |
speakerAnalysis[].durationFormat |
string | The same time in MM:SS format |
meetingStrengths[] |
object[] | Strengths: strengthTitle and strengthExplanation |
meetingWeaknesses[] |
object[] | Weaknesses: weaknessTitle and weaknessExplanation |
speechStyleInfluence |
string | How the speaking style influenced the meeting |
engagementLevel |
string | Engagement of the participants |
areasOfResponsibility |
string | Who is responsible for what after the meeting |
finalRecommendations |
string | Recommendations for the next meeting |
Efficiency score — `evaluation`
| Field | Type | Description |
|---|---|---|
efficiencyValue |
number | Overall meeting efficiency, from 0 to 100 |
calendar.overhead |
boolean | Whether the meeting ran longer than necessary |
criteria |
object | Map of criteria. The key is the criterion code, the value is an object with the fields below |
criteria.<code>.value |
boolean | Whether the criterion is met |
criteria.<code>.title |
string | Criterion name |
criteria.<code>.criteria |
string | Criterion wording |
criteria.<code>.thoughts |
string | Justification of the score |
Response example
The response to the request from the examples above. Base call fields always arrive, and the AI blocks contain exactly what is listed in select: inside overview — only the topic, the agreements and the action items, inside insights — only the participant analysis, inside evaluation — only the overall score. Employee mentions arrive as plain text, because mentionFormat: "none" was requested.
{
"success": true,
"data": {
"items": [
{
"callId": 12345,
"callType": 1,
"initiatorId": 7,
"startDate": "2026-01-15T10:00:00+00:00",
"endDate": "2026-01-15T10:42:00+00:00",
"durationSeconds": 2520,
"participants": [
{ "userId": 7, "name": "John Smith", "avatar": "https://example.bitrix24.com/upload/avatar.png", "workPosition": "Project manager", "talkedSeconds": 600 },
{ "userId": 42, "name": "Mary Jones", "avatar": "https://example.bitrix24.com/upload/avatar-2.png", "workPosition": "Developer", "talkedSeconds": 1200 }
],
"outcomes": ["transcription", "overview", "summary", "insights", "evaluation"],
"overview": {
"topic": "Sprint planning",
"agreements": [
{ "agreement": "Only the catalog import goes into the sprint", "quote": "I suggest we keep only the catalog import, we will not finish the rest." }
],
"actionItems": [
{ "actionItem": "Prepare the prototype by Friday", "quote": "Then we show the prototype on Friday." }
]
},
"insights": {
"speakerAnalysis": [
{ "userId": 42, "detailedInsight": "The participant proposed cutting the scope and backed it with a deadline estimate.", "efficiencyValue": 82, "evaluationCriteria": "Constructiveness of proposals", "talkPercentage": 66, "duration": 1200, "durationFormat": "20:00" },
{ "userId": 7, "detailedInsight": "The participant ran the meeting and recorded the agreements.", "efficiencyValue": 74, "evaluationCriteria": "Discussion management", "talkPercentage": 34, "duration": 600, "durationFormat": "10:00" }
]
},
"evaluation": {
"efficiencyValue": 75
}
},
{
"callId": 12318,
"callType": 2,
"initiatorId": 42,
"startDate": "2026-01-12T09:00:00+00:00",
"endDate": "2026-01-12T09:25:00+00:00",
"durationSeconds": 1500,
"participants": [
{ "userId": 42, "name": "Mary Jones", "avatar": "https://example.bitrix24.com/upload/avatar-2.png", "workPosition": "Developer", "talkedSeconds": 900 }
],
"outcomes": ["transcription", "overview"],
"overview": {
"topic": "Review of the week's support requests",
"agreements": [],
"actionItems": [
{ "actionItem": "Collect frequent questions into the knowledge base", "quote": "Let's collect the recurring questions into one article." }
]
},
"insights": null,
"evaluation": null
}
],
"hasMore": true,
"afterCursor": { "startDate": "2026-01-12T09:00:00.000000+00:00", "id": 12318 }
}
}
The second call shows a common case: not all of its AI blocks are ready. outcomes lists what has been generated, and blocks that were requested but are absent arrive as null — check them before accessing their fields.
See the Follow-up for a single call page for a call with all of its blocks filled in.
Error response example
400 — the request body has no filter object:
{
"success": false,
"error": {
"code": "MISSING_PARAMS",
"message": "Required: filter.startDate.from/to (ISO 8601)"
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| 400 | MISSING_PARAMS |
The request body has no filter object |
| 400 | INVALID_PARAMS |
The value of a request field is not in the list of allowed values — mentionFormat, for example. If Bitrix24 rejected the value of a specific field, the response additionally contains an error.validation array with the field name |
| 401 | MISSING_API_KEY |
The X-Api-Key header was not passed |
| 401 | TOKEN_MISSING |
The key has no portal tokens. An OAuth application key requires the Authorization: Bearer header |
| 403 | SCOPE_DENIED |
The key has no call scope |
| 403 | BITRIX_ACCESS_DENIED |
Bitrix24 denied access: the key's webhook has no call permission on the portal side. Reconnect the key with the required permission |
| 422 | METHOD_NOT_YET_AVAILABLE |
Update call 26.600.0 has not been released on the portal yet. The response contains an error.release field with the target version |
| 422 | BITRIX_ERROR |
The request was rejected: incorrect date range, disallowed field in select, incorrect pagination or order, no access to the data. The reason is in error.message |
| 429 | RATE_LIMITED |
Request rate exceeded on the Bitrix24 side |
| 429 | QUEUE_OVERFLOW, QUEUE_TIMEOUT |
The portal request queue is full or the request did not get through the queue in time. The Retry-After header suggests the delay before a retry |
| 503 | BITRIX_TIMEOUT |
Bitrix24 accepted the request but did not respond within 15 seconds. For reads a retry is safe |
| 502 | BITRIX_UNAVAILABLE |
Bitrix24 is unavailable |
The full list of common API errors — Errors.
Known specifics
Calls without AI processing do not appear in the list. The output contains only the calls for which a Follow-up has already been generated. An empty items array means there are no such calls for the period.
An incomplete period is rejected with code 422, not 400. The code 400 MISSING_PARAMS is returned only when there is no filter object in the request body at all. A missing to, or a period where from is later than to, returns 422 BITRIX_ERROR with a description of the reason.
Participant analysis is not available on every Bitrix24 account. When it is unavailable, the insights block comes back with speakerEvaluationAvailable: false and an empty participant analysis. This is not a request error — the response structure does not change.
The output is limited by the employee's permissions. The key returns Follow-ups of the calls in which the key owner took part, or whose linked chat the key owner belongs to. The Bitrix24 account administrator sees all calls of the account. That is why the same period gives different lists for different employees.