#Получить события (polling)

GET /v1/bots/:botId/events

Основной механизм получения входящих сообщений и команд. Бот периодически запрашивает новые события.

Vibe хранит lastOffset в базе данных — при первом запросе без offset используется сохранённое значение. Это позволяет боту продолжить с места остановки после перезапуска.

#Параметры

Параметр Тип Обяз. По умолч. Описание
botId (path) number да ID бота
offset (query) number нет из БД Начальная позиция. Без параметра — сохранённое в БД значение. offset=0 — начать с начала
limit (query) number нет 100 Максимальное количество событий (1-1000)
withUserEvents (query) boolean нет false Включить user-события (ONIMV2*)

#Примеры

#curl — личный ключ

Terminal
curl "https://vibecode.bitrix24.tech/v1/bots/42/events?limit=50" \
  -H "X-Api-Key: YOUR_API_KEY"

#curl — OAuth-приложение

Terminal
curl "https://vibecode.bitrix24.tech/v1/bots/42/events?limit=50" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"

#JavaScript — личный ключ

javascript
const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/events?limit=50', {
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
  },
})

const { success, data } = await res.json()
console.log('События:', data.events.length, 'Ещё:', data.hasMore)

#JavaScript — OAuth-приложение

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

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

#Поля ответа

Поле Тип Описание
events array Массив событий (см. типы событий)
events[].eventId number ID события — передайте как offset в следующем запросе
events[].type string Код события (ONIMBOTV2MESSAGEADD, ONIMBOTV2COMMANDADD и т.д.)
events[].date string Дата и время события (ISO 8601)
events[].data object Данные события (структура зависит от типа, ключи в camelCase)
nextOffset number Смещение для следующего запроса
hasMore boolean Есть ещё необработанные события
storedOffset number Текущее сохранённое смещение в БД

#Пример ответа

JSON
{
  "success": true,
  "data": {
    "events": [
      {
        "eventId": 35,
        "type": "ONIMBOTV2MESSAGEADD",
        "date": "2026-04-13T17:15:00+03:00",
        "data": {
          "dialogId": "chat123",
          "message": { "id": 1501, "text": "Привет, бот!" },
          "user": { "id": 1, "name": "Иван Петров" }
        }
      }
    ],
    "nextOffset": 36,
    "hasMore": false,
    "storedOffset": 0
  }
}

#Пример ответа при ошибке

404 — бот не найден:

JSON
{
  "success": false,
  "error": {
    "code": "BOT_NOT_FOUND",
    "message": "Bot 999 not found. Register it first via POST /v1/bots."
  }
}

#Ошибки

HTTP Код Описание
400 INVALID_BOT_ID botId не является числом
404 BOT_NOT_FOUND Бот с таким ID не найден
403 BOT_ACCESS_DENIED Бот принадлежит другому API-ключу
502 BITRIX_ERROR Ошибка Bitrix24 (текст ошибки в message)
403 SCOPE_DENIED API-ключ не имеет скоупа imbot
401 TOKEN_MISSING API-ключ не имеет настроенных токенов

Полный список общих ошибок API — Ошибки.

#Известные особенности

Серверное хранение offset: Vibe хранит lastOffset в БД. При первом запросе без offset — используется сохранённое значение. После получения событий lastOffset обновляется автоматически (fire-and-forget).

offset=0: явная передача offset=0 начинает с начала истории — для отладки или первичной загрузки.

Цепочка запросов:

GET /events           → { nextOffset: 42, hasMore: true }
GET /events?offset=42 → { nextOffset: 55, hasMore: false }
GET /events?offset=55 → { events: [], hasMore: false }

Рекомендуемый интервал polling: 2-5 секунд между запросами.

Polling-цикл (готовый пример):

javascript
const BOT_ID = 42
const API_KEY = 'YOUR_API_KEY'
const BASE = 'https://vibecode.bitrix24.tech/v1'

async function pollEvents() {
  let offset = undefined

  while (true) {
    try {
      const url = new URL(`${BASE}/bots/${BOT_ID}/events`)
      if (offset !== undefined) url.searchParams.set('offset', String(offset))

      const res = await fetch(url, {
        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
      }
    } catch (err) {
      console.error('Poll error:', err.message)
    }

    await new Promise(r => setTimeout(r, 3000))
  }
}

async function handleEvent(event) {
  const { data } = event

  switch (event.type) {
    case 'ONIMBOTV2MESSAGEADD':
      // Ответить на сообщение
      await fetch(`${BASE}/bots/${BOT_ID}/messages`, {
        method: 'POST',
        headers: { 'X-Api-Key': API_KEY, 'Content-Type': 'application/json' },
        body: JSON.stringify({
          dialogId: data.dialogId,
          fields: { message: `Получил: ${data.message.text}` },
        }),
      })
      break

    case 'ONIMBOTV2COMMANDADD':
      // Ответить на команду
      await fetch(`${BASE}/bots/${BOT_ID}/commands/${data.command.id}/answer`, {
        method: 'POST',
        headers: { 'X-Api-Key': API_KEY, 'Content-Type': 'application/json' },
        body: JSON.stringify({
          messageId: data.message.id,
          message: `Команда /${data.command.command}: ${data.command.params}`,
        }),
      })
      break
  }
}

pollEvents()

#Смотрите также