
# Диагностика проблем бот-платформы

Если бот не отвечает на сообщения, начните с разделов ниже. Каждый сценарий — отдельный набор проверок с готовыми командами `curl` и эталонными ответами от Вайбкод.

## Сценарии диагностики

- [События не приходят](#события-не-приходят) — пользователь пишет боту, но `GET /v1/bots/:botId/events` возвращает пустой массив
- [Бот работал и замолчал](#бот-работал-и-замолчал) — бот отвечал, потом перестал, и опрос событий больше не выполняется
- [TOKEN_MISSING при ключе авторизации](#token_missing-при-ключе-авторизации) — `vibe_app_…` отправлен без `Authorization: Bearer`
- [Пустые events подряд](#пустые-events-подряд) — `success: true`, но `nextOffset` не двигается
- [BITRIX_ERROR: User is not subscribed](#bitrix_error-user-is-not-subscribed) — `withUserEvents=true` без предварительной подписки
- [INTERNAL_ERROR при опросе событий](#internal_error-при-опросе-событий) — временная ошибка прокси и схема повтора с растущей паузой
- [Бот отключён (BOT_DISABLED)](#бот-отключён-bot_disabled) — автоматическое отключение по `AUTH_FAILURES` или `PORTAL_DELETED`
- [Код занят, а бота нет в списке](#код-занят-а-бота-нет-в-списке) — `409 BOT_ALREADY_EXISTS` при регистрации и пустой `GET /v1/bots`
- [Отличия fetch от webhook](#отличия-fetch-от-webhook) — разница форматов данных и поведения при доставке событий
- [Стикеры](#стикеры) — ограничение платформы
- [Методы Bot API v2 не видны в списке REST-методов портала](#методы-bot-api-v2-не-видны-в-списке-rest-методов-портала) — общий список REST-методов портала не содержит имён Bot API v2
- [Куда обратиться](#куда-обратиться) — что приложить к тикету в поддержку

---

## События не приходят

Симптом: пользователь пишет боту в чате Битрикс24, бот не отвечает, `GET /v1/bots/:botId/events` возвращает `events: []`.

### Чек-лист по порядку

1. **Бот зарегистрирован и активен.** `GET /v1/bots/:botId` возвращает `success: true` с полями `bot.id`, `bot.code`, `bot.eventMode`. Если 404 — бот не зарегистрирован, выполните `POST /v1/bots`.
2. **`eventMode: "fetch"`.** Проверяется в ответе шага 1. Если `webhook` — события через опрос не приходят, Битрикс24 отправляет их на `webhookUrl`.
3. **Тип бота соответствует сценарию.** Бот типа `bot` получает только сообщения с `@упоминанием` и личные сообщения. Для приёма всех сообщений в чате нужен тип `personal` или `supervisor` — указывается при регистрации в поле `type` и не меняется потом. Если ожидаете все сообщения, а тип `bot`, события придут только при `@упоминании`.
4. **Бот добавлен в чат.** Бот получает события только из чатов, где он состоит. Для личного диалога это происходит при первом обращении пользователя к боту. Для группового чата бота нужно добавить явно через `POST /v1/bots/:botId/chats/:dialogId/users`.
5. **Пользователь пишет именно этому боту.** Если на портале есть несколько ботов, проверьте `code` бота, к которому идёт обращение в чате, и сравните с `code` в ответе `GET /v1/bots/:botId`. Сообщения другому боту в очередь этого бота не попадут.
6. **После 5+ пустых опросов проверьте поле `hint`** в ответе `GET /v1/bots/:botId/events`. Платформа добавляет диагностическую подсказку, если очередь пуста подряд.
7. **Перепривяжите подписку на события.** Если бот активен (в чаты приходят сообщения), но очередь пуста и появилось поле `hint`, вызовите [`POST /v1/bots/:botId/resubscribe`](/docs/bots/management/resubscribe). Перепривязка восстанавливает доставку и сохраняет привязки открытых линий и приветственного бота, в отличие от повторной регистрации через `POST /v1/bots`.

Если все 7 пунктов пройдены, а очередь по-прежнему пуста — это значит, что портал Битрикс24 не направляет события боту. Соберите данные по разделу [Куда обратиться](#куда-обратиться) и отправьте тикет.

Чек-лист рассчитан на работающий опрос. Если бот сначала отвечал, а потом замолчал и опрос больше не выполняется, начните со следующего раздела.

---

## Бот работал и замолчал

Симптом: бот отвечал на сообщения, потом перестал. Последний вызов `GET /v1/bots/:botId/events` прошёл без ошибок, новых запросов от бота больше нет, сообщения пользователей остаются без ответа.

### Причина

Виртуальная машина, на которой работает бот, остановлена по таймауту простоя — у новой машины это 60 минут. Опрос событий бот отправляет сам, наружу, а таймер сбрасывают только входящие запросы к приложению, поэтому опрос машину в сети не удерживает. Через час без входящих обращений она останавливается вместе с процессом бота. Как этого избежать при запуске бота — [Где работает бот](/docs/bots#где-работает-бот).

### Проверка

```bash
curl -H "X-Api-Key: YOUR_API_KEY" \
  https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID
```

У остановленной машины `data.status` равен `sleeping`, а действующий таймаут приходит в `data.sleepAfterMinutes`.

### Решение

Отключите авто-сон и разбудите машину:

```bash
# Отключить авто-сон — принимается только значение null,
# 0 отклоняется с VALIDATION_ERROR
curl -X PATCH https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/sleep \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"sleepAfterMinutes": null}'

# Разбудить и дождаться готовности
curl -X POST -H "X-Api-Key: YOUR_API_KEY" \
  "https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/wake?wait=true"
```

Приложение, развёрнутое через [Deploy API](/docs/infra/deploy/deploy), поднимается вместе с машиной: деплой создаёт systemd-юнит автозапуска, если не передавали `systemd: false`.

Проверяйте перепиской: напишите боту в чате Битрикс24 и дождитесь ответа — это подтверждает, что опрос снова работает. Накопленные за время сна события первым должен забрать бот: ответ [`GET /v1/bots/:botId/events`](/docs/bots/events/polling) сдвигает сохранённый на сервере курсор, поэтому события, отданные в ручной вызов, до бота уже не дойдут. Если ответа в чате нет, смотрите журнал сервиса — [`GET /v1/infra/servers/:id/logs`](/docs/infra/deploy/logs).

Допустимый набор значений таймаута, поведение вытесняемых тарифов и взаимное исключение с окнами пробуждения — [Настроить авто-сон](/docs/infra/lifecycle/sleep).

---

## TOKEN_MISSING при ключе авторизации

Симптом:

```json
{ "success": false, "error": { "code": "TOKEN_MISSING", "message": "API key has no tokens configured." } }
```

### Причина

Ключ `vibe_app_…` отправлен без заголовка `Authorization: Bearer <session_token>`. Ключ авторизации работает в паре с токеном пользовательской сессии — без Bearer у запроса нет контекста, от чьего имени обращаться к Битрикс24.

### Решение

Личный ключ `vibe_api_…` — Bearer не нужен:

```bash
curl https://vibecode.bitrix24.tech/v1/bots/42/events \
  -H "X-Api-Key: YOUR_API_KEY"
```

Ключ авторизации `vibe_app_…` — обязательно с Bearer:

```bash
curl https://vibecode.bitrix24.tech/v1/bots/42/events \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"
```

Получение `USER_SESSION_TOKEN` для OAuth-приложения — см. [Ключи и авторизация](/docs/keys-auth).

Эта ошибка возникает и в обработчике события портала, который вызывает V1 API в ответ на событие. У обработчика нет пользовательской сессии, поэтому ключ `vibe_app_` там не работает — используйте персональный ключ `vibe_api_`. Подробнее — [Обработчик на стороне приложения](/docs/infra/event-subscriptions/handler).

---

## Пустые events подряд

Симптом: ответ корректный, ошибок нет, но `events: []`, `nextOffset === storedOffset`, `persisted: false`.

### Что значат поля ответа

- `persisted: false` — курсор `lastOffset` в базе Вайбкод не сдвинулся, потому что Битрикс24 не отдал ни одного события.
- `nextOffset === storedOffset` — нечего обрабатывать.
- `hint` появляется после 5+ пустых опросов подряд — диагностическая подсказка.

### Это нормально, если

- бот только что зарегистрирован — никто ещё не писал
- очередь пуста — клиенты прочитали все сообщения
- между опросами нет активности в чатах с ботом.

### Когда нужно перейти к диагностике

Если выполняется хотя бы одно условие — возвращайтесь к разделу [События не приходят](#события-не-приходят):

- в чате есть непрочитанные сообщения боту
- прошло больше минуты с момента отправки сообщения
- появилось поле `hint`.

---

## BITRIX_ERROR: User is not subscribed

Симптом: `GET /v1/bots/:botId/events?withUserEvents=true` отдаёт 422 с этим сообщением.

### Причина

User-события (типы `ONIMV2*` — изменения в чатах, реакции пользователей) требуют отдельной подписки. Без подписки параметр `withUserEvents=true` не активирует доставку.

### Решение

Подписаться один раз перед использованием `withUserEvents=true`. Полный порядок настройки и список событий — в разделе [User-события](/docs/bots/events/user-events).

После подписки `GET /v1/bots/:botId/events?withUserEvents=true` начинает отдавать user-события вместе с bot-событиями в одном массиве.

---

## INTERNAL_ERROR при опросе событий

Симптом:

```json
{ "success": false, "error": { "code": "INTERNAL_ERROR", "message": "Internal server error" } }
```

### Что делать

1. **Не повторять запрос сразу.** Повторы без паузы продлевают состояние ошибки и сами становятся причиной перегрузки.
2. **Использовать растущую паузу между попытками** — старт 5 секунд, удвоение на каждой следующей неудаче, потолок 60 секунд. После успешного ответа интервал сбрасывается к рабочему значению (2-5 секунд между опросами).
3. **Не сбрасывать `offset`.** Сохранённый курсор не пострадал — продолжайте с того же значения. Сброс приведёт к повторной обработке уже доставленных событий.
4. **Если ошибка не уходит после нескольких циклов задержки** — отправьте тикет в поддержку с `botId`, временем первого появления, последним успешным `nextOffset` и интервалом между попытками. Не наращивайте частоту запросов «на всякий случай» — это ухудшит ситуацию.

### Готовый шаблон с растущей паузой

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

let backoffMs = 5000

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

    if (!json.success && json.error?.code === 'INTERNAL_ERROR') {
      console.warn(`INTERNAL_ERROR — пауза ${backoffMs} мс`)
      await new Promise(r => setTimeout(r, backoffMs))
      backoffMs = Math.min(backoffMs * 2, 60000)
      continue
    }

    backoffMs = 5000
    for (const event of json.data?.events ?? []) {
      // обработка события
    }
  } catch {
    await new Promise(r => setTimeout(r, backoffMs))
    backoffMs = Math.min(backoffMs * 2, 60000)
  }

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

---

**`B24_MARKET_SUBSCRIPTION_REQUIRED` при опросе.** Это отдельная парковка, не `BOT_DISABLED`:
счётчики авторизации не меняются. При HTTP `403`, `Retry-After: 3600` и
`error.details.retryable:false` полностью остановите polling. После продления вызовите
`GET /v1/me?refresh=tariff`: свежая проверка автоматически восстановит всех ботов аккаунта.
В ответе нет `upgradeUrl`; `/reauth` и `/resubscribe` этот барьер не снимают.

## Бот отключён (BOT_DISABLED)

Симптом:

```json
{ "success": false, "error": { "code": "BOT_DISABLED", "message": "Bot is disabled. This bot will not process API calls until it is re-enabled.", "details": { "reauthAllowed": true } } }
```

HTTP-код — `410 Gone`. Затронуты все эндпоинты бота: события, сообщения, чаты, команды, обновление, удаление.

`message` намеренно не раскрывает внутреннюю причину. Единственный клиентский признак способа
восстановления — строгий boolean `error.details.reauthAllowed`.

### Решение

При `reauthAllowed=true` вызовите [`POST /v1/bots/:botId/reauth`](/docs/bots/management/reauth). Проверка подтверждает доступ бота, при необходимости обновляет токен и снимает отключение. Если в ответ пришёл `410 REAUTH_REQUIRED` — доступ восстановить автоматически нельзя, ключ нужно авторизовать заново через OAuth или пересоздать личный ключ.

При `reauthAllowed=false` не вызывайте `/reauth`: обычные отключённые состояния возвращают
`409 BOT_REAUTH_NOT_ALLOWED`. Если владение или состояние изменилось во время проверки, ответ —
`409 BOT_REAUTH_STATE_CHANGED`, а более новое состояние остаётся без изменений. Ручная `/reauth`
также разрешена для активной проверки после переноса владения.

Сбросить только счётчик ошибок авторизации, без проверки доступа, можно через `PATCH /v1/bots/:botId` с телом `{"disabled": false}`:

```bash
curl -X PATCH https://vibecode.bitrix24.tech/v1/bots/42 \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"disabled": false}'
```

`PORTAL_DELETED` — бот восстанавливается автоматически, когда портал возвращается к статусу `ACTIVE`. Принудительное включение через `PATCH` для этой причины не требуется.

`PATCH … {"disabled": true}` запрещён — вернётся `400 DISABLE_NOT_ALLOWED`. Отключение системное, для удаления используйте `DELETE /v1/bots/:botId`.

---

## Код занят, а бота нет в списке

Симптом: `POST /v1/bots` отвечает `409 BOT_ALREADY_EXISTS`, а `GET /v1/bots` тем же ключом возвращает пустой массив `bots`.

### Причина

Бот зарегистрирован другим ключом этого портала — например, ключ пересоздали вместе с приложением. Список ботов фильтруется по вызывающему ключу, поэтому чужой бот в него не попадает, а уникальность кода проверяется в границах портала, поэтому код остаётся занятым.

### Решение

Идентификатор существующего бота приходит в поле `data.botId` ответа `409` — по нему владение переносится на ваш ключ, и бот продолжает работать с прежними чатами и историей. Порядок по шагам, требования к целевому ключу и коды ошибок — [Восстановление доступа к боту](/docs/bots/ownership-recovery).

---

## Отличия fetch от webhook

Вайбкод поддерживает два режима доставки событий: `fetch` (по умолчанию) и `webhook`. Режим задаётся полем `eventMode` при регистрации бота и не меняется после.

| | `fetch` | `webhook` |
|---|---|---|
| Как работает | Клиент сам запрашивает события через `GET /v1/bots/:botId/events` | Битрикс24 отправляет события HTTP POST на `webhookUrl` |
| Типы значений | Сохраняют тип: `number`, `boolean`, `null` | Всё приходит строками (`"1"`, `"true"`, `""`) — следствие сериализации тела на стороне Битрикс24 |
| Объект `bot` в событии | Без поля `auth` | Содержит `auth` с OAuth-токенами портала |
| Тайм-аут | Нет (длинный опрос) | 10 секунд — Битрикс24 ждёт 200 от вашего сервера и закрывает соединение |
| Повторная доставка | Серверное хранение offset — пропустить событие нельзя | Нет автоматических повторов при таймауте или 5xx ответе |
| Формат тела | JSON в ответе `GET /v1/bots/:botId/events` | `application/x-www-form-urlencoded` в собственном формате Битрикс24 (`event=…&data[bot][id]=…&auth[member_id]=…`) |
| Когда выбирать | Большинство сценариев, особенно AI-агенты и закрытые приложения на личном ключе | Когда нужно минимальное время реакции и есть публично доступный сервер |

**При `eventMode: "webhook"` `GET /v1/bots/:botId/events` всегда возвращает пустой массив** — события доставляются напрямую на `webhookUrl`, в очередь опроса они не попадают.

### webhook требует публично достижимого URL

В режиме `webhook` Битрикс24 отправляет события POST-запросом напрямую на `webhookUrl` — **без входа пользователя в Вайбкод**. Поэтому `webhookUrl` должен быть публично доступен из интернета.

Если `webhookUrl` ведёт на сервер Black Hole, дойдёт ли до приложения событие, зависит от ключа этого сервера.

**Ключ привязан к OAuth-приложению.** Событие несёт `auth[application_token]` этого приложения, платформа узнаёт отправителя и пропускает запрос при любой политике доступа. Менять политику не нужно.

**Личный ключ `vibe_api_…`.** Опознать отправителя нечем, поэтому событие принимает только политика `PUBLIC`. При `OWNER_ONLY` (по умолчанию), `NAMED_USERS`, `DEPARTMENT`, `PORTAL` и `AUTHENTICATED` запрос отклоняется, и событие до приложения не доходит. Варианта два. Перевести сервер в политику `PUBLIC` через [`PATCH /v1/infra/servers/:id/access-policy`](/docs/infra/access/access-policy) — она открывает субдомен всем без авторизации, включайте её осознанно. Либо получать события опросом: `eventMode: "fetch"` и [`GET /v1/bots/:botId/events`](/docs/bots/events/polling).

Вариант для обоих случаев — указать внешний публично доступный `webhookUrl`, не на субдомене Black Hole.

Сервер, созданный для AI-агента, всегда остаётся в политике `OWNER_ONLY` — сменить её нельзя. Для webhook-бота на таком сервере используйте внешний публично доступный `webhookUrl`.

Сервер должен работать в момент прихода события. Спящий сервер Black Hole событие не получит, а повторов доставки нет — для webhook-бота отключите автоматический переход в сон, чтобы сервер оставался доступен. Тот же таймаут останавливает и машину бота в режиме `fetch`, потому что исходящий опрос его не сбрасывает: разбор — [Бот работал и замолчал](#бот-работал-и-замолчал).

Достижимость `webhookUrl` при регистрации не проверяется — бот зарегистрируется и с недоступным адресом.

---

## Стикеры

Боты **не могут отправлять** стикеры пользователям. Это ограничение Bot API v2 Битрикс24.

Боты могут **получать** стикеры: если пользователь отправил стикер, событие `ONIMBOTV2MESSAGEADD` придёт, но поле `message.text` будет пустым. Реагировать на стикеры можно, отправив текстовое сообщение или вложение через `POST /v1/bots/:botId/messages`.

---

## Методы Bot API v2 не видны в списке REST-методов портала

Симптом: интеграция вызывает REST-метод `methods` на портале Битрикс24 без параметров и ищет в ответе имена методов Bot API v2, например `imbot.v2.Chat.Message.send`. Этих имён в ответе нет, и интеграция считает, что отправка сообщений и реакции бота недоступны.

### Причина

Общий список REST-методов портала неполон относительно Bot API v2. Часть методов бота присутствует в нём под именами прежнего поколения, методы второй версии в этот список не входят. Поэтому проверка «есть ли имя в списке» сообщает об отсутствии возможности, которая на портале работает. Это поведение платформы Битрикс24, а не ограничение Вайбкод.

Отсутствие имени в списке и отсутствие метода на портале дают разный ответ: вызов несуществующего имени возвращает отказ «метод не найден», а вызов метода Bot API v2 с неполными параметрами — ошибку о недостающих параметрах. Это объясняет симптом, но способом проверки доступности не является: возможности бота на Вайбкод определяет справочник эндпоинтов, а не ответы портала.

### Решение

Не используйте общий список REST-методов портала для проверки возможностей бота. Порядок работы:

1. Зарегистрируйте бота — [Зарегистрировать бота](/docs/bots/management/create), `POST /v1/bots`.
2. Получайте события — [Получить события (polling)](/docs/bots/events/polling), `GET /v1/bots/:botId/events`.
3. Отправляйте сообщения — [Отправить сообщение](/docs/bots/messages/send), `POST /v1/bots/:botId/messages`.
4. Ставьте и снимайте реакции — [Добавить реакцию](/docs/bots/ui/reaction-add), [Удалить реакцию](/docs/bots/ui/reaction-delete).

Полный перечень возможностей бота — [Справочник эндпоинтов](/docs/bots#справочник-эндпоинтов): все эндпоинты бот-платформы Вайбкод и метод Битрикс24, который стоит за каждым.

Ревизию бот-платформы портала отдаёт [Ревизия бот-платформы](/docs/bots/management/revision), `GET /v1/bots/revision`. Рост поля `data.rest` означает, что на портале появились новые REST-возможности бот-платформы. Это номер ревизии, а не перечень эндпоинтов: сопоставления «номер — возможность» нет, порога вида «при `rest` не ниже N доступны реакции» тоже нет.

---

## Куда обратиться

Если ни один из разделов выше не помог — оставьте тикет в разделе [Обратная связь](/docs/feedback). К тикету приложите:

- `botId` (число)
- ответ `GET /v1/bots/:botId` целиком
- последние 3 ответа `GET /v1/bots/:botId/events` с полями `nextOffset`, `storedOffset`, `persisted`, `hint`
- время первого появления симптома (UTC)
- тип ключа (`vibe_api_…` или `vibe_app_…`) — без самого ключа
- скриншот чата с непрочитанным сообщением, если есть.

---

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

- [Бот-платформа](/docs/bots)
- [Восстановление доступа к боту](/docs/bots/ownership-recovery)
- [Получить события (polling)](/docs/bots/events/polling)
- [User-события](/docs/bots/events/user-events)
- [Зарегистрировать бота](/docs/bots/management/create)
- [Ревизия бот-платформы](/docs/bots/management/revision)
- [Обработчик на стороне приложения](/docs/infra/event-subscriptions/handler)
- [Настроить авто-сон](/docs/infra/lifecycle/sleep)
- [Ключи и авторизация](/docs/keys-auth)
- [Коды ошибок](/docs/errors)
- [Лимиты и оптимизация](/docs/optimization)
