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

Chat changes since a moment

GET /v1/chats/sync

Returns what changed in the current user's chats since the given moment: new and removed chats, new, edited and deleted messages, pins. Use it to bring a local copy of the chats up to date after a break without re-reading the whole list.

Parameters

Parameter Type Required Default Description
lastDate (query) string yes — The moment to read changes from. Format YYYY-MM-DDTHH:MM:SS with an offset or Z, without fractional seconds. For the next page, navigationData.lastServerDate of the previous one
lastId (query) integer no — navigationData.lastId of the previous page, 0 or more. Not passed on the first page
limit (query) integer no 50 Change log entries per page, 1 to 200. A smaller value is raised to 1 and a larger one is clamped to 200, both echoed in meta

Other parameters and repeated parameters are rejected with 400 INVALID_PARAMS.

Walk. Request the first page with lastDate set to the moment up to which your local copy is current. While navigationData.hasMore is true, request the next one with lastDate equal to navigationData.lastServerDate and lastId equal to navigationData.lastId. Save the lastServerDate and lastId pair of the last page: the next sync starts from it.

Examples

curl — personal key

Terminal
curl "https://vibecode.bitrix24.com/v1/chats/sync?lastDate=2026-09-24T10:00:00Z&limit=200" \
  -H "X-Api-Key: YOUR_API_KEY"

curl — OAuth application

Terminal
curl "https://vibecode.bitrix24.com/v1/chats/sync?lastDate=2026-09-24T10:00:00Z&limit=200" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"

JavaScript — personal key

javascript
let lastDate = '2026-09-24T10:00:00Z'
let lastId
const added = new Set()
for (;;) {
  const url = new URL('https://vibecode.bitrix24.com/v1/chats/sync')
  url.searchParams.set('lastDate', lastDate)
  url.searchParams.set('limit', '200')
  if (lastId !== undefined) url.searchParams.set('lastId', String(lastId))
  const res = await fetch(url, { headers: { 'X-Api-Key': 'YOUR_API_KEY' } })
  const { data } = await res.json()
  if (Array.isArray(data)) throw new Error('Incremental sync is unavailable; refresh the full recent-chat list')
  for (const id of Object.values(data.messageSync.addedMessages)) added.add(id)
  lastDate = data.navigationData.lastServerDate
  lastId = data.navigationData.lastId
  if (!data.navigationData.hasMore) break
}

JavaScript — OAuth application

javascript
let lastDate = '2026-09-24T10:00:00Z'
let lastId
const added = new Set()
for (;;) {
  const url = new URL('https://vibecode.bitrix24.com/v1/chats/sync')
  url.searchParams.set('lastDate', lastDate)
  url.searchParams.set('limit', '200')
  if (lastId !== undefined) url.searchParams.set('lastId', String(lastId))
  const res = await fetch(url, {
    headers: {
      'X-Api-Key': 'YOUR_APP_KEY',
      'Authorization': 'Bearer USER_SESSION_TOKEN',
    },
  })
  const { data } = await res.json()
  if (Array.isArray(data)) throw new Error('Incremental sync is unavailable; refresh the full recent-chat list')
  for (const id of Object.values(data.messageSync.addedMessages)) added.add(id)
  lastDate = data.navigationData.lastServerDate
  lastId = data.navigationData.lastId
  if (!data.navigationData.hasMore) break
}

Response fields

Field Type Description
success boolean Always true on success
data.chatSync.addedRecent object Chats that appeared in the dialog list: key and value are the chat ID
data.chatSync.addedChats object Chats that appeared or changed for the user: key and value are the chat ID
data.chatSync.deletedChats object Chats removed from the user's dialog list: key and value are the chat ID
data.chatSync.completeDeletedChats object Chats deleted from the Bitrix24 account: key and value are the chat ID
data.chatSync.readAllChats boolean Arrives as true if the user read all chats during this period: reset the unread counters in the local copy
data.messageSync.addedMessages object New messages: key and value are the message ID
data.messageSync.updatedMessages object Edited messages: key and value are the message ID
data.messageSync.completeDeletedMessages object Deleted messages: key and value are the message ID
data.pinSync.addedPins object New pinned messages: key and value are the pin ID
data.pinSync.deletedPins object Removed message pins: key and value are the pin ID
data.userSync object User changes: updatedUsers and deletedUsers
data.chats array Chat cards for the chats from chatSync
data.messages array Messages from messageSync
data.pins array Message pins from pinSync: id, messageId, chatId, authorId, dateCreate
data.recentItems array Dialog list rows for the chats from chatSync
data.users array Users mentioned in the changes
data.dialogIds object Mapping of chat ID to dialog ID: key is the chat ID, value is the dialogId
data.navigationData.lastServerDate string lastDate for the next page: the moment of the last change log entry on this page
data.navigationData.lastId number lastId for the next page
data.navigationData.hasMore boolean true if there is a next page
meta.requestedLimit number The limit passed. It arrives together with appliedLimit, only when the value was outside the range of 1 to 200
meta.appliedLimit number The limit applied

Response example

The main fields are shown:

JSON
{
  "success": true,
  "data": {
    "chatSync": {
      "addedRecent": { "264431": 264431 },
      "addedChats": { "264431": 264431 },
      "deletedChats": { "264418": 264418 },
      "completeDeletedChats": []
    },
    "messageSync": {
      "addedMessages": { "609001": 609001 },
      "updatedMessages": [],
      "completeDeletedMessages": []
    },
    "pinSync": {
      "addedPins": [],
      "deletedPins": []
    },
    "userSync": {
      "updatedUsers": [],
      "deletedUsers": []
    },
    "messages": [
      {
        "id": 609001,
        "chatId": 264431,
        "authorId": 1,
        "date": "2026-09-24T21:10:22+00:00",
        "text": "The draft plan is ready"
      }
    ],
    "chats": [
      {
        "id": 264431,
        "dialogId": "chat264431",
        "name": "Release preparation",
        "type": "chat"
      }
    ],
    "dialogIds": { "264431": "chat264431" },
    "navigationData": {
      "lastServerDate": "2026-09-24T21:10:22+00:00",
      "hasMore": false,
      "lastId": 182091
    }
  }
}

Error response example

400 — a date without an offset:

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

Errors

HTTP Code Description
400 INVALID_PARAMS No lastDate, lastDate not in the YYYY-MM-DDTHH:MM:SS format with an offset or Z, or with a nonexistent date or time (2026-02-30, 24:00), lastId less than 0, a non-numeric limit, a parameter other than lastDate, lastId and limit, or a repeated parameter. Checked before the Bitrix24 call
422 BITRIX_ERROR Bitrix24 returned an error; the Bitrix24 code is in error.b24Code
403 BITRIX_ACCESS_DENIED Bitrix24 denied access
403 SCOPE_DENIED The API key does not have the im scope
401 TOKEN_MISSING The API key has no Bitrix24 tokens configured
502 BITRIX_UNAVAILABLE Bitrix24 is unavailable or returned a server error

Full list of common API errors — Errors.

Known specifics

An empty collection arrives as an array. When a change group has no entries, an empty array arrives instead of an object: "updatedMessages": []. Read such fields with Object.values, which handles both forms the same way.

Incremental history is not a four-week guarantee. Some Bitrix24 change records remain for only about a day. After a long interruption, especially one approaching a day, re-read recent dialogs and the needed message history in full before trusting a new delta.

Sync can be turned off on a Bitrix24 account. Then data is an empty array, not an object with the fields above. In that case, re-read the list in full.

These are not real-time events. The endpoint answers "what has changed since a given time"; to receive new messages as they appear, use event polling.

See also