[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"docs-partner-connect":3,"docs-tabs-partner-connect":6},{"content":4,"lastmod":5},"\n# Partner Connect\n\nПодключение внешних сервисов к Битрикс24: ваше приложение запрашивает у пользователя разрешение на доступ к его порталу и получает API-ключ Вайбкод для дальнейших вызовов. Поток построен по схеме Authorization Code — той же, что у OAuth-провайдеров Google или GitHub.\n\n**Базовый URL:** `https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1` | **Авторизация:** `client_id` + `client_secret` партнёра | **Скоупы ключа:** запрашиваются на странице согласия\n\n## Содержание\n\n- [Когда применять](#когда-применять)\n- [Как это работает](#как-это-работает)\n- [Справочник эндпоинтов](#справочник-эндпоинтов)\n- [Полный сценарий](#полный-сценарий) — Express-обработчик от и до\n- [`GET \u002Fv1\u002Fconnect\u002Fauthorize`](#get-v1-connect-authorize) — старт потока, редирект на согласие\n- [`POST \u002Fv1\u002Fconnect\u002Ftoken`](#post-v1-connect-token) — обмен кода на API-ключ\n- [Использование API-ключа](#использование-api-ключа)\n- [Доступные скоупы](#доступные-скоупы)\n- [Время жизни и отзыв ключа](#время-жизни-и-отзыв-ключа)\n- [Безопасность](#безопасность)\n- [Регистрация партнёра](#регистрация-партнёра)\n- [Смотрите также](#смотрите-также)\n\n## Когда применять\n\nСценарий — внешний SaaS-продукт, который интегрируется с порталами Битрикс24 ваших клиентов: CRM-аналитика, синхронизация с 1С, чат-ассистент, конструктор лендингов. Кнопка «Подключить Битрикс24» на вашем сайте запускает поток: пользователь выбирает портал и подтверждает скоупы, ваш сервер получает постоянный API-ключ и работает с порталом от имени пользователя.\n\nЕсли вы пишете приложение, которое ставится **внутри** портала Битрикс24 и работает только с ним, — используйте обычный API-ключ, см. [Авторизация и ключи](\u002Fdocs\u002Fkeys-auth).\n\n## Как это работает\n\n```\nВаше приложение → [1. Redirect] → Вайбкод Consent Page → [2. Согласие]\n    ↑                                                          ↓\n    └──── [4. API-ключ] ←── [3. Code → redirect_uri] ──────────┘\n```\n\n1. **Redirect** — отправляете пользователя на `\u002Fv1\u002Fconnect\u002Fauthorize` с `client_id`, `redirect_uri`, `state` и списком скоупов.\n2. **Согласие** — пользователь видит страницу Вайбкод, выбирает портал и подтверждает или отклоняет запрошенные скоупы.\n3. **Код** — после одобрения пользователь возвращается на `redirect_uri` с параметрами `code` и `state`. При отказе — `redirect_uri?error=access_denied&state=...`.\n4. **Обмен** — сервер партнёра отправляет `POST \u002Fv1\u002Fconnect\u002Ftoken` и получает API-ключ.\n\n## Справочник эндпоинтов\n\n| Метод | Путь | Описание |\n|-------|------|----------|\n| GET | [`\u002Fv1\u002Fconnect\u002Fauthorize`](#get-v1-connect-authorize) | Старт потока: редирект на страницу согласия |\n| POST | [`\u002Fv1\u002Fconnect\u002Ftoken`](#post-v1-connect-token) | Обмен одноразового кода на постоянный API-ключ |\n\n## Полный сценарий\n\nПример Express-обработчика, который проводит пользователя через оба эндпоинта от и до. Перед запуском поместите `client_id` и `client_secret`, выданные командой Битрикс24 Вайбкод, в переменные окружения, а `redirect_uri` зарегистрируйте у партнёра.\n\n```javascript\nimport express from 'express'\nimport crypto from 'node:crypto'\n\nconst app = express()\nconst sessions = new Map() \u002F\u002F в продакшене — Redis или БД\n\nconst CLIENT_ID = process.env.PARTNER_CLIENT_ID\nconst CLIENT_SECRET = process.env.PARTNER_CLIENT_SECRET\nconst REDIRECT_URI = 'https:\u002F\u002Fyourapp.com\u002Fcallback'\n\n\u002F\u002F 1. Кнопка «Подключить Битрикс24» ведёт сюда\napp.get('\u002Fconnect', (req, res) => {\n  const state = crypto.randomBytes(16).toString('hex')\n  sessions.set(state, { userId: req.user.id, createdAt: Date.now() })\n\n  const params = new URLSearchParams({\n    client_id: CLIENT_ID,\n    redirect_uri: REDIRECT_URI,\n    scopes: 'crm,task',\n    state,\n  })\n  res.redirect(`https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fconnect\u002Fauthorize?${params}`)\n})\n\n\u002F\u002F 2. Вайбкод возвращает пользователя сюда после согласия или отказа\napp.get('\u002Fcallback', async (req, res) => {\n  const { code, state, error } = req.query\n\n  const session = sessions.get(state)\n  if (!session) return res.status(400).send('Неизвестный state')\n  sessions.delete(state)\n\n  if (error === 'access_denied') {\n    return res.redirect('\u002Fdashboard?connect=denied')\n  }\n\n  \u002F\u002F 3. Обмениваем код на API-ключ — серверный запрос с client_secret\n  const tokenRes = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fconnect\u002Ftoken', {\n    method: 'POST',\n    headers: { 'Content-Type': 'application\u002Fjson' },\n    body: JSON.stringify({\n      client_id: CLIENT_ID,\n      client_secret: CLIENT_SECRET,\n      code,\n      redirect_uri: REDIRECT_URI,\n    }),\n  })\n  const data = await tokenRes.json()\n\n  if (!data.success) {\n    return res.status(400).send(`Ошибка обмена: ${data.error.code}`)\n  }\n\n  \u002F\u002F 4. Сохраняем привязку: пользователь нашего сервиса ↔ портал Битрикс24\n  await db.connections.upsert({\n    userId: session.userId,\n    portalDomain: data.portal.domain,\n    portalName: data.portal.name,\n    apiKey: encrypt(data.api_key), \u002F\u002F секрет, шифруем перед хранением\n    scopes: data.scopes,\n  })\n\n  res.redirect('\u002Fdashboard?connect=ok')\n})\n\n\u002F\u002F 5. Дальше используем сохранённый ключ для вызовов от имени пользователя\nasync function listDeals(userId) {\n  const connection = await db.connections.findByUserId(userId)\n  const apiKey = decrypt(connection.apiKey)\n\n  const res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fdeals?limit=10', {\n    headers: { 'X-Api-Key': apiKey },\n  })\n  return res.json()\n}\n```\n\nКлючевые моменты сценария:\n\n- `state` генерируется на сервере и проверяется при возврате — без этой проверки злоумышленник может подсунуть пользователю чужой код.\n- `client_secret` хранится только на сервере и в браузер не попадает.\n- API-ключ шифруется перед записью в БД и расшифровывается только в момент вызова.\n- При `error=access_denied` пользователь видит понятное сообщение, а не страницу с ошибкой обмена.\n\n## GET \u002Fv1\u002Fconnect\u002Fauthorize\n\nПеренаправляет пользователя на страницу согласия Битрикс24 Вайбкод.\n\n**Query-параметры:**\n\n| Параметр | Тип | Обяз. | Описание |\n|----------|-----|:-----:|----------|\n| `client_id` | string | да | Идентификатор партнёра, выданный командой Битрикс24 Вайбкод |\n| `redirect_uri` | string | да | URL обратного вызова. Должен совпадать с одним из зарегистрированных у партнёра |\n| `state` | string | да | Произвольная строка, которая вернётся вместе с кодом. Защита от CSRF |\n| `scopes` | string | нет | Список скоупов через запятую: `crm,task,im`. Если не передать — применяются скоупы по умолчанию из настроек партнёра |\n\n**Пример URL:**\n\n```\nhttps:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fconnect\u002Fauthorize?client_id=YOUR_CLIENT_ID&redirect_uri=https:\u002F\u002Fyourapp.com\u002Fcallback&scopes=crm,task&state=abc123random\n```\n\n**Успешный редирект** после одобрения:\n\n```\nhttps:\u002F\u002Fyourapp.com\u002Fcallback?code=AUTH_CODE_HERE&state=abc123random\n```\n\n**Редирект при отказе** пользователя на странице согласия:\n\n```\nhttps:\u002F\u002Fyourapp.com\u002Fcallback?error=access_denied&state=abc123random\n```\n\n### Ошибки\n\n| HTTP | Код | Описание |\n|------|-----|----------|\n| 400 | `INVALID_REQUEST` | Не передан один из `client_id`, `redirect_uri`, `state` |\n| 400 | `INVALID_CLIENT` | `client_id` не зарегистрирован или партнёр отключён |\n| 400 | `INVALID_REDIRECT_URI` | `redirect_uri` не совпадает ни с одним из зарегистрированных у партнёра |\n| 400 | `INVALID_SCOPE` | Один или несколько скоупов не входят в список разрешённых для Битрикс24 |\n\nПолный справочник общих ошибок API — [Ошибки](\u002Fdocs\u002Ferrors).\n\n## POST \u002Fv1\u002Fconnect\u002Ftoken\n\nОбменивает одноразовый код авторизации на постоянный API-ключ. Принимает `application\u002Fjson` и `application\u002Fx-www-form-urlencoded`.\n\n**Поля запроса (body):**\n\n| Поле | Тип | Обяз. | Описание |\n|------|-----|:-----:|----------|\n| `client_id` | string | да | Идентификатор партнёра |\n| `client_secret` | string | да | Секрет партнёра. Передавать только с серверной стороны |\n| `code` | string | да | Код из параметра `code` редиректа |\n| `redirect_uri` | string | да | Тот же `redirect_uri`, что был передан в `\u002Fv1\u002Fconnect\u002Fauthorize` |\n\n### Примеры\n\n#### curl\n\n```bash\ncurl -X POST https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fconnect\u002Ftoken \\\n  -H \"Content-Type: application\u002Fx-www-form-urlencoded\" \\\n  -d client_id=YOUR_CLIENT_ID \\\n  -d client_secret=YOUR_CLIENT_SECRET \\\n  -d code=RECEIVED_CODE \\\n  -d redirect_uri=https:\u002F\u002Fyourapp.com\u002Fcallback\n```\n\n#### JavaScript\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fconnect\u002Ftoken', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application\u002Fjson' },\n  body: JSON.stringify({\n    client_id: 'YOUR_CLIENT_ID',\n    client_secret: 'YOUR_CLIENT_SECRET',\n    code: receivedCode,\n    redirect_uri: 'https:\u002F\u002Fyourapp.com\u002Fcallback',\n  }),\n})\n\nconst data = await res.json()\n\u002F\u002F data.api_key — постоянный API-ключ Вайбкод\n\u002F\u002F data.portal — выбранный пользователем портал\n\u002F\u002F data.scopes — подтверждённые скоупы\n\u002F\u002F data.user — пользователь, выдавший доступ\n```\n\n### Поля ответа\n\n| Поле | Тип | Описание |\n|------|-----|----------|\n| `success` | boolean | `true` при успешном обмене |\n| `api_key` | string | API-ключ Вайбкод в формате `vibe_app_...`. Передавать в заголовке `X-Api-Key` при последующих вызовах |\n| `portal.domain` | string | Домен портала Битрикс24, например `example.bitrix24.ru` |\n| `portal.name` | string | Название портала |\n| `scopes` | string[] | Список скоупов, которые пользователь подтвердил. Может быть короче запрошенного, если пользователь снял часть |\n| `user.name` | string | Имя пользователя, выдавшего доступ |\n| `user.email` | string | Электронная почта пользователя |\n\n### Пример ответа\n\n```json\n{\n  \"success\": true,\n  \"api_key\": \"vibe_app_...\",\n  \"portal\": {\n    \"domain\": \"example.bitrix24.ru\",\n    \"name\": \"Моя компания\"\n  },\n  \"scopes\": [\"crm\", \"task\"],\n  \"user\": {\n    \"name\": \"Иван Иванов\",\n    \"email\": \"ivan@example.com\"\n  }\n}\n```\n\n### Пример ответа при ошибке\n\n400 — отсутствует обязательный параметр:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"INVALID_REQUEST\",\n    \"message\": \"Missing required parameters\"\n  }\n}\n```\n\n### Ошибки\n\n| HTTP | Код | Описание |\n|------|-----|----------|\n| 400 | `INVALID_REQUEST` | Не передан один из `client_id`, `client_secret`, `code`, `redirect_uri` |\n| 400 | `INVALID_CODE` | Код не существует, истёк (5 минут), уже был использован, либо `redirect_uri` отличается от того, что был передан в `\u002Fv1\u002Fconnect\u002Fauthorize` |\n| 401 | `INVALID_CLIENT` | `client_id` неизвестен или `client_secret` не совпадает |\n| 403 | `PARTNER_DISABLED` | Учётная запись партнёра приостановлена |\n\nПолный справочник общих ошибок API — [Ошибки](\u002Fdocs\u002Ferrors).\n\n## Использование API-ключа\n\nПолученный ключ имеет тип `APP` и работает как стандартный API-ключ Вайбкод. Передавайте его в заголовке `X-Api-Key`:\n\n```bash\ncurl -H \"X-Api-Key: vibe_app_...\" \\\n  https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fdeals\n```\n\nОдин и тот же ключ можно использовать с любым эндпоинтом Вайбкод API в пределах подтверждённых скоупов: список сделок, batch-запросы, поиск, агрегация и т. д.\n\nПартнёрский ключ работает с одним заголовком `X-Api-Key` и **не требует** `Authorization: Bearer \u003Csession_token>`. Это отличает его от ключей OAuth-приложений из каталога Вайбкод с тем же префиксом `vibe_app_...` — там сессия пользователя обязательна.\n\n## Доступные скоупы\n\nПри вызове `\u002Fv1\u002Fconnect\u002Fauthorize` передавайте те же скоупы, что и при создании стандартного API-ключа в портале Битрикс24. На странице согласия пользователь видит список и может снять отдельные пункты — итоговый набор приходит в поле `scopes` ответа `\u002Fv1\u002Fconnect\u002Ftoken`.\n\nПолный список поддерживаемых значений (32 скоупа: `crm`, `task`, `tasks`, `im`, `imbot`, `imopenlines`, `call`, `telephony`, `bizproc`, `calendar`, `timeman`, `catalog`, `sale`, `lists`, `disk`, `entity`, `user`, `user_basic`, `user_brief`, `user.userfield`, `department`, `landing`, `documentgenerator`, `sign.b2e`, `sonet_group`, `log`, `vote`, `ai_admin`, `biconnector`, `booking`, `delivery`, `pay_system`, `main`, `placement`, `userfieldtype`) описан в разделе [Авторизация и ключи](\u002Fdocs\u002Fkeys-auth).\n\n## Время жизни и отзыв ключа\n\n- **Код авторизации (`code`)** действует **5 минут** и одноразовый. После обмена через `\u002Fv1\u002Fconnect\u002Ftoken` повторный вызов с тем же кодом вернёт `INVALID_CODE`.\n- **Стейт согласия** (внутреннее состояние страницы согласия) живёт 10 минут — если пользователь не подтвердит за это время, ссылку придётся выдавать заново.\n- **API-ключ** не имеет срока истечения. Действует, пока:\n  - пользователь не отзовёт доступ в портале (на странице управления выданными правами в личном кабинете),\n  - либо команда Битрикс24 Вайбкод не приостановит партнёрское приложение.\n\nПри отзыве ключа все запросы с ним возвращают `401 KEY_INACTIVE`. Если ключ удалён или неизвестен — `401 INVALID_API_KEY`. Партнёр должен корректно обработать оба кода и предложить пользователю повторно авторизоваться.\n\n## Безопасность\n\n- **State-параметр** — генерируйте криптостойкую случайную строку на каждый запрос и сверяйте при возврате на `redirect_uri`. Защищает от CSRF.\n- **`client_secret` — только на сервере.** Никогда не передавайте секрет в браузер, мобильное приложение или клиентский код. Обмен кода на ключ выполняется только серверным запросом.\n- **Хранение ключа.** API-ключ — секрет, который даёт доступ к данным пользователя. Храните в зашифрованном виде, ограничивайте доступ к строке подключения, не логируйте.\n- **Привязка `redirect_uri`.** Значение в `\u002Fv1\u002Fconnect\u002Fauthorize` и `\u002Fv1\u002Fconnect\u002Ftoken` должно совпадать символ в символ — несоответствие приведёт к `INVALID_CODE`.\n\n## Регистрация партнёра\n\nСамостоятельная регистрация пока не предусмотрена — `client_id` и `client_secret` выдаёт команда Битрикс24 Вайбкод после ревью заявки. Чтобы оставить заявку, напишите на `lev@bitrix.ru`.\n\nВ заявке укажите:\n\n- название и краткое описание приложения,\n- сценарий использования,\n- список запрашиваемых скоупов,\n- один или несколько `redirect_uri`, которые будете использовать.\n\n## Смотрите также\n\n- [Авторизация и ключи](\u002Fdocs\u002Fkeys-auth) — общие правила работы с API-ключами Вайбкод, типы ключей (включая OAuth-приложения), список скоупов\n- [Управляющие ключи](\u002Fdocs\u002Fmanagement-keys) — программное создание ключей для собственного портала\n- [Ошибки API](\u002Fdocs\u002Ferrors) — общий справочник кодов ошибок\n","2026-07-07",{}]