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.

Parameters

Parameter Type Required Default Description
offset (query) number yes — Starting position. First call: 0. Subsequent calls: the nextOffset value from the previous response
limit (query) number no 100 Maximum 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
success boolean Always true on success
data object Result container
data.events array Array of events
data.events[].eventId number Event identifier. Used as offset in the next request
data.events[].type string Event type (ONIMV2MESSAGEADD, ONIMV2JOINCHAT, etc.)
data.events[].date string Event date and time (ISO 8601)
data.events[].data object Event data; fields are in camelCase. The structure depends on type. The fields of the ONIMV2MESSAGEADD event are described in User events
data.nextOffset number Value for the offset parameter in the next request
data.hasMore boolean true — 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
400 MISSING_PARAMS The offset parameter is missing or empty
400 INVALID_OFFSET The offset value is not a non-negative integer (fractional, negative, leading zeros, extraneous characters)
400 INVALID_LIMIT The limit value is outside the range 1–1000 or is not an integer
403 SCOPE_DENIED The API key does not have the im scope
401 TOKEN_MISSING The API key has no configured tokens
422 BITRIX_ERROR Bitrix24 returned an error (error text in message)
502 BITRIX_UNAVAILABLE Bitrix24 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
ONIMV2MESSAGEADD New message in a subscribed chat
ONIMV2MESSAGEUPDATE Message edited
ONIMV2MESSAGEDELETE Message deleted
ONIMV2JOINCHAT A participant joined the chat
ONIMV2REACTIONCHANGE A 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