Для AI-агентов: markdown этой страницы — /docs-content/chats/discovery/recent-external.md индекс документации — /llms.txt

Внешние чаты раздела

GET /v1/chats/recent/external

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

Параметры

Параметр Тип Обяз. По умолч. Описание
type (query) string да — Код раздела: латинская буква, затем буквы, цифры или _, до 64 символов. tasksTask — чаты задач, calendar — чаты встреч календаря. Разделы, в которых учитывается чат, приходят в поле recentSections счётчиков непрочитанного
limit (query) integer нет 50 Строк на странице, от 50 до 200. Меньшее значение поднимается до 50, большее срезается до 200, оба раза с эхом в meta
lastMessageDate (query) string нет — Курсор следующей страницы — наименьшая dateLastActivity среди незакреплённых строк предыдущей страницы. Формат YYYY-MM-DDTHH:MM:SS со смещением или Z, без долей секунды. На первой странице не передаётся

Другие параметры и повторы отклоняются с 400 INVALID_PARAMS. Разделы default и collab здесь не читаются — у них свои эндпоинты: общий список — последние диалоги в режиме v2, коллабы — список коллаб.

Обход — как у последних диалогов в режиме v2. Курсор следующей страницы — наименьшая непустая dateLastActivity среди незакреплённых строк, сравнивайте моменты времени, а не строки. Граница включительная, а закреплённые чаты открывают каждую страницу — повторы снимайте по chatId. Конец списка — только hasNextPage: false. Если при hasNextPage: true курсора нет или он равен прежнему, повторите запрос с бо́льшим limit, вплоть до 200. Строк ответа не отбрасывайте: курсор считается по всему ответу.

Примеры

curl — личный ключ

Terminal
curl "https://vibecode.bitrix24.tech/v1/chats/recent/external?type=tasksTask&limit=50" \
  -H "X-Api-Key: YOUR_API_KEY"

curl — OAuth-приложение

Terminal
curl "https://vibecode.bitrix24.tech/v1/chats/recent/external?type=tasksTask&limit=50" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"

JavaScript — личный ключ

javascript
const rows = new Map()
let limit = 50
let cursor
for (;;) {
  const url = new URL('https://vibecode.bitrix24.tech/v1/chats/recent/external')
  url.searchParams.set('type', 'tasksTask')
  url.searchParams.set('limit', String(limit))
  if (cursor) url.searchParams.set('lastMessageDate', cursor)
  const res = await fetch(url, { headers: { 'X-Api-Key': 'YOUR_API_KEY' } })
  const { data } = await res.json()
  for (const item of data.recentItems) rows.set(item.chatId, item)
  if (!data.hasNextPage) break
  const dates = data.recentItems.filter((i) => !i.pinned && i.dateLastActivity).map((i) => i.dateLastActivity)
  const next = dates.length ? dates.reduce((a, b) => (Date.parse(a) <= Date.parse(b) ? a : b)) : undefined
  if (!next || (cursor && Date.parse(next) >= Date.parse(cursor))) {
    if (limit === 200) throw new Error('Recent-list cursor did not advance; restart with a full refresh')
    limit = Math.min(limit * 2, 200)
    continue
  }
  cursor = next
  limit = 50
}

JavaScript — OAuth-приложение

javascript
const rows = new Map()
let limit = 50
let cursor
for (;;) {
  const url = new URL('https://vibecode.bitrix24.tech/v1/chats/recent/external')
  url.searchParams.set('type', 'tasksTask')
  url.searchParams.set('limit', String(limit))
  if (cursor) url.searchParams.set('lastMessageDate', cursor)
  const res = await fetch(url, {
    headers: {
      'X-Api-Key': 'YOUR_APP_KEY',
      'Authorization': 'Bearer USER_SESSION_TOKEN',
    },
  })
  const { data } = await res.json()
  for (const item of data.recentItems) rows.set(item.chatId, item)
  if (!data.hasNextPage) break
  const dates = data.recentItems.filter((i) => !i.pinned && i.dateLastActivity).map((i) => i.dateLastActivity)
  const next = dates.length ? dates.reduce((a, b) => (Date.parse(a) <= Date.parse(b) ? a : b)) : undefined
  if (!next || (cursor && Date.parse(next) >= Date.parse(cursor))) {
    if (limit === 200) throw new Error('Recent-list cursor did not advance; restart with a full refresh')
    limit = Math.min(limit * 2, 200)
    continue
  }
  cursor = next
  limit = 50
}

Поля ответа

Поле Тип Описание
success boolean Всегда true при успехе
data.recentItems array Строки раздела в порядке портала — закреплённые первыми, далее по активности
data.recentItems[].dialogId string ID диалога, chatXXX
data.recentItems[].chatId number ID чата — ключ для снятия повторов
data.recentItems[].messageId number ID последнего сообщения
data.recentItems[].pinned boolean Чат закреплён у текущего пользователя
data.recentItems[].unread boolean Чат вручную отмечен непрочитанным
data.recentItems[].dateLastActivity string|null Момент последней активности. Наименьшее значение среди незакреплённых строк — курсор следующей страницы
data.chats array Карточки чатов: id, dialogId, name, type — тот же код раздела, entityType и entityId — связанная сущность, entityLink.url — её адрес на портале, role текущего пользователя и другие поля чата
data.messages array Последние сообщения чатов
data.users array Авторы последних сообщений
data.recentConfigs array Разделы списка, в которых учитывается каждый чат: chatId и sections
data.hasNextPage boolean false — конец раздела
meta.requestedLimit number Переданный limit. Приходит вместе с appliedLimit, только когда значение вышло за диапазон от 50 до 200
meta.appliedLimit number Применённый limit — только если он был приведён к границе

Пример ответа

Раздел tasksTask, показаны основные поля:

JSON
{
  "success": true,
  "data": {
    "recentItems": [
      {
        "dialogId": "chat264388",
        "chatId": 264388,
        "messageId": 608251,
        "type": "chat",
        "pinned": false,
        "unread": false,
        "dateUpdate": "2026-09-11T12:53:10+00:00",
        "dateLastActivity": "2026-09-11T12:53:10+00:00"
      }
    ],
    "chats": [
      {
        "id": 264388,
        "dialogId": "chat264388",
        "name": "Подготовить релиз",
        "type": "tasksTask",
        "entityType": "TASKS_TASK",
        "entityId": "27",
        "owner": 1,
        "role": "owner"
      }
    ],
    "recentConfigs": [
      { "chatId": 264388, "sections": ["tasksTask"] }
    ],
    "hasNextPage": false
  }
}

Пример ответа при ошибке

400 — запрошен общий список:

JSON
{
  "success": false,
  "error": {
    "code": "INVALID_PARAMS",
    "message": "`type` default is not an external-chat section — read it through GET /v1/chats/recent?format=v2."
  }
}

Ошибки

HTTP Код Описание
400 INVALID_PARAMS Нет type, type не код раздела, type равен default или collab — в сообщении назван нужный эндпоинт. Также параметр вне type, limit, lastMessageDate, повтор параметра, нечисловой limit или lastMessageDate не в формате YYYY-MM-DDTHH:MM:SS со смещением или Z либо с несуществующей датой или временем. Проверяется до обращения к Битрикс24
422 BITRIX_ERROR Битрикс24 вернул ошибку, код портала — в error.b24Code
403 BITRIX_ACCESS_DENIED Битрикс24 отказал в доступе
403 SCOPE_DENIED API-ключ не имеет скоупа im
401 TOKEN_MISSING API-ключ не имеет настроенных токенов Битрикс24
502 BITRIX_UNAVAILABLE Битрикс24 недоступен или вернул ошибку сервера

Полный список общих ошибок API — Ошибки.

Известные особенности

Неизвестный раздел — пустой список, а не ошибка. Код, которого нет на портале, отвечает 200 с пустым recentItems и hasNextPage: false. Опечатку в type ответ не покажет: сверяйте код с полем recentSections счётчиков непрочитанного.

Пол limit — 50. Закреплённых чатов бывает до 45, и они повторяются на каждой странице. Страница меньше 50 строк могла бы целиком состоять из повторов и не дать курсора.

Обход — не снимок. Чат, поднятый новой активностью из-под курсора во время обхода, в нём не появится. После обхода перечитайте первую страницу.

Смотрите также