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
curl "https://vibecode.bitrix24.com/v1/chats/events?offset=0&limit=50" \
-H "X-Api-Key: YOUR_API_KEY"
curl — OAuth application
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
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
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. Structure depends on the type, fields in camelCase |
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:
{
"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):
{
"success": true,
"data": {
"events": [],
"nextOffset": 104,
"hasMore": false
}
}
Error response example
400 — the required offset parameter was not provided:
{
"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 |
Full list of common API errors — Errors.
Event types
The type field of each event is one of the 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 key vibe_api_… the X-Api-Key header is enough. For an OAuth key vibe_app_… you must also add Authorization: Bearer <session_token> — without it the request returns 401 TOKEN_MISSING. Obtaining a token for an OAuth application — see Keys and authorization.
Cursor on the client side. Unlike bot event polling, this endpoint does not store the offset position in the database — cursor management is on the calling code's side. On the first call pass offset=0, on subsequent calls — 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 frequency — events will be delivered on the next call. More about limits — Limits and optimization.
Polling loop (ready-to-use example):
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()