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

`GET /v1/chats/events`

Возвращает накопленные пользовательские события мессенджера начиная с указанной позиции. Параметр `offset` обязателен — передайте `0` при первом вызове, затем `nextOffset` из каждого ответа.

Требует предварительной [подписки](/docs/chats/events/subscribe). Без активной подписки события не накапливаются, ответ будет пустым.

## Параметры

| Параметр | Тип | Обяз. | По умолч. | Описание |
|----------|-----|:-----:|-----------|---------|
| `offset` (query) | number | да | — | Начальная позиция. Первый вызов: `0`. Следующие вызовы: значение `nextOffset` из предыдущего ответа |
| `limit` (query) | number | нет | `100` | Максимальное количество событий за один вызов (1–1000) |

## Примеры

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

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

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

```bash
curl "https://vibecode.bitrix24.tech/v1/chats/events?offset=0&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/chats/events?offset=0&limit=50', {
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
  },
})

const { success, data } = await res.json()
console.log('Событий:', data.events.length, 'Следующий offset:', data.nextOffset)
```

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

```javascript
const res = await fetch('https://vibecode.bitrix24.tech/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()
```

## Поля ответа

| Поле | Тип | Описание |
|------|-----|---------|
| `success` | boolean | Всегда `true` при успехе |
| `data` | object | Контейнер результата |
| `data.events` | array | Массив событий |
| `data.events[].eventId` | number | Идентификатор события. Используется как `offset` в следующем запросе |
| `data.events[].type` | string | Тип события (`ONIMV2MESSAGEADD`, `ONIMV2JOINCHAT` и др.) |
| `data.events[].date` | string | Дата и время события (ISO 8601) |
| `data.events[].data` | object | Данные события. Структура зависит от типа, поля в camelCase |
| `data.nextOffset` | number | Значение для параметра `offset` в следующем запросе |
| `data.hasMore` | boolean | `true` — есть ещё события за пределами текущего ответа |

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

Есть новые события:

```json
{
  "success": true,
  "data": {
    "events": [
      {
        "eventId": 101,
        "type": "ONIMV2JOINCHAT",
        "date": "2026-06-05T10:00:00+03:00",
        "data": {
          "dialogId": "chat100",
          "chat": {
            "id": 100,
            "name": "Чат проекта",
            "type": "open"
          },
          "user": {
            "id": 42,
            "name": "Иван Иванов"
          }
        }
      },
      {
        "eventId": 103,
        "type": "ONIMV2MESSAGEADD",
        "date": "2026-06-05T10:01:30+03:00",
        "data": {
          "message": {
            "id": 500,
            "chatId": 100,
            "text": "Всем привет!"
          },
          "chat": {
            "id": 100,
            "name": "Чат проекта"
          },
          "user": {
            "id": 42,
            "name": "Иван Иванов"
          }
        }
      }
    ],
    "nextOffset": 104,
    "hasMore": false
  }
}
```

Пустой ответ (новых событий нет):

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

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

400 — не передан обязательный параметр `offset`:

```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."
  }
}
```

## Ошибки

| HTTP | Код | Описание |
|------|-----|---------|
| 400 | `MISSING_PARAMS` | Параметр `offset` не передан или пустой |
| 400 | `INVALID_OFFSET` | Значение `offset` не является целым неотрицательным числом (дробные, отрицательные, ведущие нули, посторонние символы) |
| 400 | `INVALID_LIMIT` | Значение `limit` вне диапазона 1–1000 или не является целым числом |
| 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `im` |
| 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов |
| 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку (текст ошибки в `message`) |
| 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен или вернул ошибку сервера |

Полный список общих ошибок API — [Ошибки](/docs/errors).

## Типы событий

Поле `type` каждого события — один из кодов:

| Событие | Описание |
|---------|---------|
| `ONIMV2MESSAGEADD` | Новое сообщение в подписанном чате |
| `ONIMV2MESSAGEUPDATE` | Сообщение отредактировано |
| `ONIMV2MESSAGEDELETE` | Сообщение удалено |
| `ONIMV2JOINCHAT` | Участник зашёл в чат |
| `ONIMV2REACTIONCHANGE` | Реакция на сообщение изменена |

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

**Токен обязателен.** Для личного ключа `vibe_api_…` достаточно заголовка `X-Api-Key`. Для OAuth-ключа `vibe_app_…` обязательно добавлять `Authorization: Bearer <session_token>` — без него запрос вернёт `401 TOKEN_MISSING`. Получение токена для OAuth-приложения — см. [Ключи и авторизация](/docs/keys-auth).

**Курсор на стороне клиента.** В отличие от опроса событий бота, этот эндпоинт не хранит позицию `offset` в базе данных — управление курсором на стороне вызывающего кода. При первом вызове передавайте `offset=0`, при последующих — значение `nextOffset` из предыдущего ответа.

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

```
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 }
```

**Рекомендуемый интервал опроса:** 2–5 секунд между запросами. При пустом ответе не увеличивайте частоту — события будут доставлены при следующем вызове. Подробнее о лимитах — [Лимиты и оптимизация](/docs/optimization).

**Цикл опроса (готовый пример):**

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

async function pollChatEvents() {
  // Сначала подписаться — без подписки события не накапливаются
  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('Ошибка опроса:', err.message)
      await new Promise(r => setTimeout(r, 5000))
    }
  }
}

async function handleEvent(event) {
  switch (event.type) {
    case 'ONIMV2MESSAGEADD':
      console.log('Новое сообщение:', event.data.message?.text)
      break
    case 'ONIMV2JOINCHAT':
      console.log('Участник зашёл в чат:', event.data.chat?.name)
      break
    case 'ONIMV2MESSAGEDELETE':
      console.log('Сообщение удалено:', event.data.message?.id)
      break
    default:
      console.log('Событие:', event.type)
  }
}

pollChatEvents()
```

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

- [Подписаться на события](/docs/chats/events/subscribe)
- [Отписаться от событий](/docs/chats/events/unsubscribe)
- [События мессенджера](/docs/chats/events)
- [User-события и опрос вместе с ботом](/docs/bots/events/user-events)
- [Лимиты и оптимизация](/docs/optimization)
