[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"docs-infra\u002Fevent-subscriptions\u002Fhandler":3,"docs-tabs-infra\u002Fevent-subscriptions\u002Fhandler":6},{"content":4,"lastmod":5},"\n## Обработчик на стороне приложения\n\nПриём доставленного события в приложении на Black Hole-сервере. Платформа доставляет каждое событие POST-запросом на субдомен приложения по пути `appPath` в формате `application\u002Fx-www-form-urlencoded` — это стандартное тело события Битрикс24. Обработчик читает `event` и `data`, сверяет `auth[application_token]` со своим `application_token` и отвечает `2xx`. Платформа повторяет доставку при ответе не `2xx` и будит спящий сервер.\n\n```javascript\n\u002F\u002F Express-обработчик: поля формы Битрикс24 приходят в req.body\nimport express from 'express'\n\nconst APP_TOKEN = process.env.APPLICATION_TOKEN \u002F\u002F application_token приложения\nconst app = express()\napp.use(express.urlencoded({ extended: true }))\n\napp.post('\u002Fapi\u002Fwebhooks\u002Fb24', (req, res) => {\n  \u002F\u002F Сверка токена приложения — события без верного токена отклоняются\n  if (req.body.auth?.application_token !== APP_TOKEN) {\n    return res.status(403).json({ ok: false })\n  }\n\n  const event = req.body.event              \u002F\u002F например \"ONTASKADD\"\n  const taskId = req.body.data?.FIELDS?.ID  \u002F\u002F ID сущности из события\n\n  \u002F\u002F Повторное событие не должно сработать дважды — платформа может доставить его снова\n  console.log(`Событие ${event}, задача #${taskId}`)\n\n  \u002F\u002F Ответить 2xx, иначе платформа повторит доставку\n  res.status(200).json({ ok: true })\n})\n```\n\n## Тело события\n\nПример тела, которое приходит в обработчик:\n\n```\nevent=ONTASKADD&data[FIELDS][ID]=20152&ts=1780843200&auth[access_token]=\u003Cтокен Битрикс24>&auth[refresh_token]=\u003Cтокен обновления Битрикс24>&auth[application_token]=\u003Capplication_token приложения>&auth[domain]=your-portal.bitrix24.ru&auth[member_id]=...\n```\n\nТело несёт токены пользователя Битрикс24. `auth[application_token]` обработчик сверяет, чтобы отклонить чужие события. `auth[access_token]` — токен Битрикс24 для прямых вызовов REST Битрикс24. Как ключ V1 API напрямую он не работает, но его можно обменять на токен сессии — это второй способ авторизации ниже.\n\n## Авторизация вызовов V1 API из обработчика\n\nОбработчик часто вызывает V1 API в ответ на событие — читает связанную сущность или создаёт новую. Платформа доставляет событие сама и **не добавляет заголовков авторизации**: в запросе приходит только `Content-Type` и тело события. Авторизацию вызова обработчик задаёт сам. Есть два рабочих способа — выбор зависит от того, под чьим ключом должны идти вызовы.\n\n### Способ 1. Персональный ключ `vibe_api_`\n\nСамый короткий путь: персональный ключ в заголовке `X-Api-Key`, сессия не нужна. Вызовы идут от лица владельца ключа. Подходит, когда их не обязательно делать под тем же приложением, что и подписка.\n\n```javascript\napp.post('\u002Fapi\u002Fwebhooks\u002Fb24', async (req, res) => {\n  if (req.body.auth?.application_token !== APP_TOKEN) {\n    return res.status(403).json({ ok: false })\n  }\n\n  const taskId = req.body.data?.FIELDS?.ID\n\n  \u002F\u002F Вызов V1 API — персональный ключ в заголовке X-Api-Key\n  const task = await fetch(\n    `https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Ftasks\u002F${taskId}`,\n    { headers: { 'X-Api-Key': process.env.VIBE_API_KEY } },\n  ).then((r) => r.json())\n\n  console.log('Задача из события:', task.data)\n\n  res.status(200).json({ ok: true })\n})\n```\n\nПерсональный ключ `vibe_api_` создают в личном кабинете — порядок создания описан в [Ключах и авторизации](\u002Fdocs\u002Fkeys-auth). Скоупы Битрикс24 закрепляются за ключом при выпуске: отметьте те группы данных, к которым обращается обработчик (для примера с задачами — `tasks`).\n\n### Способ 2. Ключ авторизации `vibe_app_` под тем же приложением\n\nЕсли вызовы должны идти под тем же ключом авторизации, что и подписка, то есть от лица пользователя портала — обработчику нужна сессия. Тело события несёт токены этого пользователя: `auth[access_token]`, `auth[member_id]`, `auth[domain]` и `auth[refresh_token]`. Их обменивают на токен сессии `vibe_session_` запросом `POST \u002Fv1\u002Foauth\u002Fplacement-session` с телом `{ app_key, access_token, member_id, domain, refresh_token }`. Полученную сессию передают в `Authorization: Bearer` рядом с `X-Api-Key`:\n\n```bash\ncurl https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Ftasks\u002F20152 \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\"\n```\n\nКак получить сессию из токенов события — раздел [«Приложение на своём сервере»](\u002Fdocs\u002Fkeys-auth#приложение-на-своём-сервере) в «Ключах и авторизации». Сессия живёт 24 часа, продления нет.\n\n### Частые ошибки авторизации\n\nТри сочетания заголовков, которые не сработают, и код ответа для каждого:\n\n| Что передали | Ответ | Причина |\n|---|---|---|\n| Ключ авторизации `vibe_app_` в `X-Api-Key` без `Bearer` | `401 TOKEN_MISSING` | На самом ключе портальных токенов нет — нужна сессия в `Authorization: Bearer` рядом с `X-Api-Key` (Способ 2) |\n| Ключ авторизации `vibe_app_` в `Authorization: Bearer` | `401 WRONG_AUTH_SCHEME` | В `Bearer` идёт токен сессии `vibe_session_`, а не ключ приложения |\n| Токен `auth[access_token]` из события в `Authorization: Bearer` | `401 MISSING_API_KEY` | Это токен Битрикс24, а не ключ V1. В `Bearer` V1 API принимает только токены `vibe_` — токен Битрикс24 сначала обменивают на сессию (Способ 2) |\n\nПодробный разбор `TOKEN_MISSING` — [Диагностика проблем бот-платформы](\u002Fdocs\u002Fbots\u002Ftroubleshooting#token_missing-при-ключе-авторизации).\n\n## Известные особенности\n\n- **Доставка проходит через туннель — публичный URL приложению не нужен.** Платформа регистрирует обработчик на своей стороне, Битрикс24 шлёт событие туда, а платформа доставляет его в приложение через туннель Black Hole с проверкой `auth[application_token]`. Своего публичного адреса приложению не требуется.\n- **Спящий сервер просыпается под доставку.** Если на момент события сервер спит, платформа будит его и доставляет событие после подключения туннеля. Поэтому первое событие после простоя приходит с задержкой на пробуждение.\n- **Доставка надёжная, но не бесконечная.** Неуспешные доставки повторяются с нарастающей задержкой. После исчерпания попыток доставка переходит в `FAILED`, подписка помечается `DEGRADED`, владелец получает уведомление. Статусы доставок видны в [`GET \u002Fv1\u002Finfra\u002Fservers\u002F:id\u002Fevent-subscriptions`](.\u002Flist.md).\n- **Повторная доставка не должна дублировать эффект.** Одно и то же событие может прийти повторно. Обрабатывайте его так, чтобы второй приём с тем же `data[FIELDS][ID]` не сделал работу дважды.\n\n## Смотрите также\n\n- [Подписки на события портала](\u002Fdocs\u002Finfra\u002Fevent-subscriptions)\n- [Создать подписку](\u002Fdocs\u002Finfra\u002Fevent-subscriptions\u002Fcreate)\n- [Список подписок](\u002Fdocs\u002Finfra\u002Fevent-subscriptions\u002Flist)\n- [Ключи и авторизация](\u002Fdocs\u002Fkeys-auth)\n- [Диагностика проблем бот-платформы](\u002Fdocs\u002Fbots\u002Ftroubleshooting)\n","2026-07-13",{}]