For AI agents: markdown of this page — /docs-content-en/chats/discovery/recent-collabs.md documentation index — /llms.txt

Collab list

GET /v1/chats/recent/collabs

Returns the current user's collab chats page by page: pinned ones first, then by last activity time. Use it for a separate collab tab in the dialog list.

Parameters

Parameter Type Required Default Description
Parameterlimit (query) Typeinteger Requiredno Default50 DescriptionRows per page, 50 to 200. A smaller value is raised to 50 and a larger one is clamped to 200, and both adjustments are echoed in meta
ParameterlastMessageDate (query) Typestring Requiredno Default— DescriptionCursor of the next page: the smallest dateLastActivity among the unpinned rows of the previous page. Format YYYY-MM-DDTHH:MM:SS with an offset or Z, without fractional seconds. Not passed on the first page

Other parameters and repeated parameters are rejected with 400 INVALID_PARAMS.

Pagination — as in recent dialogs in the v2 mode. The cursor of the next page is the smallest non-empty dateLastActivity among the unpinned rows; compare instants, not strings. The bound is inclusive, and pinned chats appear at the top of every page, so deduplicate by chatId. The list ends only at hasNextPage: false. If hasNextPage is true but there is no cursor or it equals the previous one, repeat the request with a larger limit, up to 200. Do not discard response rows: the cursor is computed over the whole response.

Examples

curl — personal key

Terminal
curl "https://vibecode.bitrix24.com/v1/chats/recent/collabs?limit=50" \
  -H "X-Api-Key: YOUR_API_KEY"

curl — OAuth application

Terminal
curl "https://vibecode.bitrix24.com/v1/chats/recent/collabs?limit=50" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"

JavaScript — personal key

javascript
const rows = new Map()
let limit = 50
let cursor
for (;;) {
  const url = new URL('https://vibecode.bitrix24.com/v1/chats/recent/collabs')
  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 application

javascript
const rows = new Map()
let limit = 50
let cursor
for (;;) {
  const url = new URL('https://vibecode.bitrix24.com/v1/chats/recent/collabs')
  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
}

Response fields

Field Type Description
Fieldsuccess Typeboolean DescriptionAlways true on success
Fielddata.recentItems Typearray DescriptionList rows in the order Bitrix24 returns them: pinned first, then by activity
Fielddata.recentItems[].dialogId Typestring DescriptionDialog ID of the collab, chatXXX
Fielddata.recentItems[].chatId Typenumber DescriptionChat ID, the deduplication key
Fielddata.recentItems[].messageId Typenumber DescriptionID of the last message
Fielddata.recentItems[].pinned Typeboolean DescriptionThe chat is pinned for the current user
Fielddata.recentItems[].unread Typeboolean DescriptionThe chat is manually marked as unread
Fielddata.recentItems[].dateLastActivity Typestring|null DescriptionInstant of the last activity. The smallest value among the unpinned rows is the cursor of the next page
Fielddata.chats Typearray DescriptionCollab chat cards: id, dialogId, name, type with the value collab, entityType with the value SONET_GROUP, entityId — the group ID, the current user's role and other chat fields
Fielddata.messages Typearray DescriptionThe chats' last messages
Fielddata.users Typearray DescriptionAuthors of the last messages
Fielddata.files Typearray DescriptionFiles of the last messages
Fielddata.recentConfigs Typearray DescriptionList sections in which each chat is counted: chatId and sections
Fielddata.hasNextPage Typeboolean Descriptionfalse — the end of the list
Fieldmeta.requestedLimit Typenumber DescriptionThe limit passed. It arrives together with appliedLimit, only when the value was outside the range of 50 to 200
Fieldmeta.appliedLimit Typenumber DescriptionThe limit applied — only when it was clamped to a bound

Response example

The main fields are shown; limit=10 is raised to 50:

JSON
{
  "success": true,
  "data": {
    "recentItems": [
      {
        "dialogId": "chat53",
        "chatId": 53,
        "messageId": 413,
        "type": "chat",
        "pinned": false,
        "unread": false,
        "dateUpdate": "2026-06-15T12:31:26+00:00",
        "dateLastActivity": "2026-04-21T10:55:53+00:00"
      }
    ],
    "chats": [
      {
        "id": 53,
        "dialogId": "chat53",
        "name": "Partner program launch",
        "type": "collab",
        "entityType": "SONET_GROUP",
        "entityId": "3",
        "owner": 1,
        "role": "owner"
      }
    ],
    "recentConfigs": [
      { "chatId": 53, "sections": ["default", "collab"] }
    ],
    "hasNextPage": false
  },
  "meta": {
    "requestedLimit": 10,
    "appliedLimit": 50
  }
}

Error response example

400 — the cursor has no offset:

JSON
{
  "success": false,
  "error": {
    "code": "INVALID_PARAMS",
    "message": "`lastMessageDate` must be a datetime YYYY-MM-DDTHH:MM:SS with a UTC offset (+03:00) or Z and no fractional seconds — the smallest `dateLastActivity` among the unpinned rows of the previous page."
  }
}

Errors

HTTP Code Description
HTTP400 CodeINVALID_PARAMS DescriptionA parameter other than limit and lastMessageDate, a repeated parameter, a non-numeric limit, or a lastMessageDate that is not in the YYYY-MM-DDTHH:MM:SS format with an offset or Z or that has a nonexistent date or time (2026-02-30, 24:00). Checked before the Bitrix24 call
HTTP422 CodeBITRIX_ERROR DescriptionBitrix24 returned an error; the Bitrix24 code is in error.b24Code
HTTP403 CodeBITRIX_ACCESS_DENIED DescriptionBitrix24 denied access
HTTP403 CodeSCOPE_DENIED DescriptionThe API key does not have the im scope
HTTP401 CodeTOKEN_MISSING DescriptionThe API key has no Bitrix24 tokens configured
HTTP502 CodeBITRIX_UNAVAILABLE DescriptionBitrix24 is unavailable or returned a server error

Full list of common API errors — Errors.

Known specifics

The limit floor is 50. A user can have up to 45 pinned chats, and they repeat on every page. A page smaller than 50 rows could consist of repeats only and give no cursor.

Pagination does not give a snapshot. A collab that new activity lifts above the cursor during pagination does not appear in the results. Re-read the first page after pagination.

See also