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

Get events

GET /v1/chats/events

Returns accumulated messenger user events starting from the specified position. The offset parameter is required — pass 0 on the first call, then nextOffset from each response.

Requires a prior subscription. Without an active subscription, events are not accumulated and the response will be empty.

The generic filter parameter is not applied by this endpoint. By default, the API preserves the previous HTTP 200 response and data, adds Warning: 299 - "filter is not supported on this endpoint and was ignored", and records unsupported-filter use in the server log.

Parameters

Parameter Type Required Default Description
Parameteroffset (query) Typenumber Requiredyes Default— DescriptionStarting position. First call: 0. Subsequent calls: the nextOffset value from the previous response
Parameterlimit (query) Typenumber Requiredno Default100 DescriptionMaximum number of events per call (1–1000)

Examples

curl — personal key

Terminal
curl "https://vibecode.bitrix24.com/v1/chats/events?offset=0&limit=50" \
  -H "X-Api-Key: YOUR_API_KEY"

curl — OAuth application

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

JavaScript — personal key

javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/chats/events?offset=0&limit=50', {
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
  },
})

const { success, data } = await res.json()
console.log('Events:', data.events.length, 'Next offset:', data.nextOffset)

JavaScript — OAuth application

javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/chats/events?offset=0&limit=50', {
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
})

const { success, data } = await res.json()

Response fields

Field Type Description
Fieldsuccess Typeboolean DescriptionAlways true on success
Fielddata Typeobject DescriptionResult container
Fielddata.events Typearray DescriptionArray of events
Fielddata.events[].eventId Typenumber DescriptionEvent identifier. Used as offset in the next request
Fielddata.events[].type Typestring DescriptionEvent type (ONIMV2MESSAGEADD, ONIMV2JOINCHAT, etc.)
Fielddata.events[].date Typestring DescriptionEvent date and time (ISO 8601)
Fielddata.events[].data Typeobject DescriptionEvent data; fields are in camelCase. The structure depends on type. The fields of the ONIMV2MESSAGEADD event are described in User events
Fielddata.nextOffset Typenumber DescriptionValue for the offset parameter in the next request
Fielddata.hasMore Typeboolean Descriptiontrue — there are more events beyond the current response

Response example

There are new events:

JSON
{
  "success": true,
  "data": {
    "events": [
      {
        "eventId": 101,
        "type": "ONIMV2JOINCHAT",
        "date": "2026-06-05T10:00:00+00:00",
        "data": {
          "dialogId": "chat100",
          "chat": {
            "id": 100,
            "name": "Project chat",
            "type": "open"
          },
          "user": {
            "id": 42,
            "name": "John Smith"
          }
        }
      },
      {
        "eventId": 103,
        "type": "ONIMV2MESSAGEADD",
        "date": "2026-06-05T10:01:30+00:00",
        "data": {
          "message": {
            "id": 500,
            "chatId": 100,
            "text": "Hi everyone!"
          },
          "chat": {
            "id": 100,
            "name": "Project chat"
          },
          "user": {
            "id": 42,
            "name": "John Smith"
          }
        }
      }
    ],
    "nextOffset": 104,
    "hasMore": false
  }
}

Empty response (no new events):

JSON
{
  "success": true,
  "data": {
    "events": [],
    "nextOffset": 104,
    "hasMore": false
  }
}

Error response example

400 — the required offset parameter was not provided:

JSON
{
  "success": false,
  "error": {
    "code": "MISSING_PARAMS",
    "message": "Query parameter `offset` is required. Pass `0` for the first call, then `nextOffset` from each response to advance the cursor."
  }
}

Errors

HTTP Code Description
HTTP200 CodeWarning: 299 DescriptionThe filter is ignored by default; previous data is preserved and the warning is sent in the Warning header.
HTTP400 (strict mode only) CodeUNSUPPORTED_FILTER DescriptionThe server mode is disabled by default; until it is enabled, the endpoint preserves HTTP 200 and the previous data.
HTTP400 CodeMISSING_PARAMS DescriptionThe offset parameter is missing or empty
HTTP400 CodeINVALID_OFFSET DescriptionThe offset value is not a non-negative integer (fractional, negative, leading zeros, extraneous characters)
HTTP400 CodeINVALID_LIMIT DescriptionThe limit value is outside the range 1–1000 or is not an integer
HTTP403 CodeSCOPE_DENIED DescriptionThe API key does not have the im scope
HTTP401 CodeTOKEN_MISSING DescriptionThe API key has no configured tokens
HTTP422 CodeBITRIX_ERROR DescriptionBitrix24 returned an error (error text in message)
HTTP502 CodeBITRIX_UNAVAILABLE DescriptionBitrix24 is unavailable or returned a server error

For the full list of common API errors, see Errors.

Event types

The type field of each event is one of the following codes:

Event Description
EventONIMV2MESSAGEADD DescriptionNew message in a subscribed chat
EventONIMV2MESSAGEUPDATE DescriptionMessage edited
EventONIMV2MESSAGEDELETE DescriptionMessage deleted
EventONIMV2JOINCHAT DescriptionA participant joined the chat
EventONIMV2REACTIONCHANGE DescriptionA message reaction changed

Known specifics

Token is required. For a personal vibe_api_… key, the X-Api-Key header is enough. For an OAuth vibe_app_… key, you must also add Authorization: Bearer <session_token> — without it the request returns 401 TOKEN_MISSING. To obtain a token for an OAuth application, see Keys and authorization.

Client-side cursor. Unlike bot event polling, this endpoint does not store the offset position in the database — the calling code manages the cursor. On the first call, pass offset=0; on subsequent calls, pass the nextOffset value from the previous response.

Request chain:

GET /v1/chats/events?offset=0   → { nextOffset: 104, hasMore: true }
GET /v1/chats/events?offset=104 → { nextOffset: 112, hasMore: false }
GET /v1/chats/events?offset=112 → { events: [], hasMore: false }

Recommended polling interval: 2–5 seconds between requests. On an empty response, do not increase the polling frequency — events will be delivered on the next call. For more on limits, see Limits and optimization.

Polling does not keep the machine online. If the loop below runs on a Black Hole server, disable auto-sleep on it. The idle timer counts inbound requests to the server, while polling only makes outbound calls — from the timer's point of view the server is idle, and after an hour it goes to sleep along with the polling process. To disable it, call PATCH /v1/infra/servers/:id/sleep with sleepAfterMinutes: null.

Polling loop (ready-to-use example):

javascript
const API_KEY = 'YOUR_API_KEY'
const BASE = 'https://vibecode.bitrix24.com/v1'

async function pollChatEvents() {
  // Subscribe first — without a subscription events are not accumulated
  await fetch(`${BASE}/chats/events/subscribe`, {
    method: 'POST',
    headers: { 'X-Api-Key': API_KEY },
  })

  let offset = 0

  while (true) {
    try {
      const res = await fetch(`${BASE}/chats/events?offset=${offset}`, {
        headers: { 'X-Api-Key': API_KEY },
      })
      const { data } = await res.json()

      for (const event of data.events ?? []) {
        await handleEvent(event)
      }

      if (data.nextOffset !== undefined) {
        offset = data.nextOffset
      }

      if (!data.hasMore) {
        await new Promise(r => setTimeout(r, 3000))
      }
    } catch (err) {
      console.error('Polling error:', err.message)
      await new Promise(r => setTimeout(r, 5000))
    }
  }
}

async function handleEvent(event) {
  switch (event.type) {
    case 'ONIMV2MESSAGEADD':
      console.log('New message:', event.data.message?.text)
      break
    case 'ONIMV2JOINCHAT':
      console.log('Participant joined the chat:', event.data.chat?.name)
      break
    case 'ONIMV2MESSAGEDELETE':
      console.log('Message deleted:', event.data.message?.id)
      break
    default:
      console.log('Event:', event.type)
  }
}

pollChatEvents()

See also