# VibeCode — Complete Documentation # https://vibecode.bitrix24.tech # Generated: 2026-08-14T03:25:49.371Z --- # Начало работы с Битрикс24 Вайбкод Битрикс24 Вайбкод — платформа, где искусственный интеллект (AI) создаёт приложения для Битрикс24. Вы описываете задачу обычными словами — и получаете рабочее приложение за часы, без программиста и без навыков разработки. ## Почему это для вас - **Без навыков программирования.** AI пишет код — вам не нужно разбираться в API, серверах и базах данных. - **Часы, а не месяцы.** Не нужно искать разработчика, ставить техзадание и ждать неделями. От идеи до работающего приложения — один разговор с AI-моделью. - **Под вашим контролем.** Доступ к данным открывает ключ, который вы создаёте и в любой момент отзываете сами. Приложение работает на отдельном сервере, закрытом от интернета. - **Дешевле работы программиста.** Разработку делает AI, оплата — за работу сервера и отдельные функции. ## Что понадобится Перед началом убедитесь, что у вас есть: - **Портал Битрикс24 с активной подпиской BitrixGPT + Маркетплейс.** С ней доступна вся платформа Вайбкод — создание ключей, обращение к данным портала, серверы, деплой и публикация приложений. Без активной подписки эти возможности закрыты. - **Если ваш Битрикс24 коробочный — сначала подключите его к платформе.** Как это сделать, описано в [Подключении коробочного Битрикс24](./connect-self-hosted-bitrix24.md). Облачный портал подключать отдельно не нужно. - **AI-инструмент, который сам работает с файлами и выполняет команды** — например, Claude Code, Cursor или OpenAI Codex. Такой инструмент не просто отвечает в чате, а действует автономно: сам читает документацию, создаёт файлы приложения, пишет код и отправляет запросы к платформе Вайбкод. Обычный чат с нейросетью, где можно только переписываться, для этого не подойдёт — иначе все шаги пришлось бы выполнять вручную. ## Шаг 1. Создайте ключ Ключ — это доступ к данным вашего Битрикс24, который вы передаёте AI-модели. Есть два вида ключей: - **Для себя** (`vibe_api_…`) — приложение работает от вашего имени. Подходит для личных сводок, отчётов, серверных автоматизаций и фоновых задач по расписанию (cron) — запросы идут по заголовку `X-Api-Key`, токен сессии не нужен. Создаётся в разделе [Ключи API](/keys). - **Для команды и для встраивания в портал** (`vibe_app_…`) — каждый сотрудник входит через свой Битрикс24 и видит свои данные. Этот же ключ нужен, чтобы приложение открывалось внутри Битрикс24 — в левом меню, вкладке CRM или виджете (см. [Места встраивания](/docs/apps/placements)). Создаётся в разделе [Ключи авторизации](/apps). Не уверены — начните с ключа «для себя»: переключиться на командный можно позже. Если приложение должно открываться внутри Битрикс24, сразу создавайте ключ авторизации (`vibe_app_…`). Для фоновой автоматизации без пользователя у экрана — cron, планировщик, серверные скрипты — выбирайте ключ API (`vibe_api_…`). Ключ авторизации (`vibe_app_…`) на каждый запрос к данным требует заголовок `Authorization: Bearer` с токеном сессии, а сессия живёт 24 часа без автопродления — автоматическому скрипту нечем заново пройти авторизацию каждые сутки. Подробнее — [Создание и использование ключа](./keys-auth.md). 1. Войдите в [личный кабинет](/dashboard). 2. Откройте [Ключи API](/keys) (для себя) или [Ключи авторизации](/apps) (для команды и встраивания в портал). 3. Нажмите **Создать**, укажите название и отметьте [разрешения](./scopes.md) — с какими данными приложение сможет работать. 4. Скопируйте ключ — он показывается один раз. Подробный разбор формы создания — [Создание и использование ключа](./keys-auth.md). ## Шаг 2. Дайте ключ AI-модели Откройте Claude Code, Cursor или другой AI-инструмент и вставьте промпт: ``` Мой API ключ для платформы Вайбкод: vibe_api_xxx... Документация: https://vibecode.bitrix24.tech/v1/me Сделай мне приложение [описание приложения] и задеплой на вайбкод ``` Для ключа авторизации (приложение для команды или со встраиванием в портал): ``` Мой API ключ для платформы Вайбкод: vibe_app_xxx... Документация: https://vibecode.bitrix24.tech/v1/me Сделай мне приложение [описание приложения] с авторизацией, встрой его в Битрикс24 и задеплой на вайбкод ``` Модель вызовет `GET /v1/me` с вашим ключом и получит доступные данные, разрешения и инструкции по размещению приложения. ## Шаг 3. Что произойдёт дальше AI-модель делает всё сама: 1. Узнаёт по вашему ключу, к каким данным и возможностям есть доступ (`GET /v1/me`). 2. Пишет код приложения, используя данные вашего Битрикс24 (сделки, задачи, контакты и другие). 3. Создаёт сервер и размещает приложение через `POST /v1/infra/servers/:id/deploy`. 4. Приложение доступно по адресу вида `https://app-xxx.vibecode.bitrix24.tech`. Сервер можно создать и заранее, вручную в разделе [Black Hole](/black-hole). Подробнее — [Инфраструктура](./infra.md). ## Что дальше - [Создание и использование ключа](./keys-auth.md) — как создать ключ, ограничить срок действия и отозвать в любой момент. - [Разрешения (скоупы)](./scopes.md) — что означают разрешения и какие данные вы открываете приложению. - [Бот-платформа](./bots.md) — как сделать чат-бота для клиентов или сотрудников. Готовые примеры: [аналитика воронки продаж](./recipes/crm-analytics.md), [Telegram-бот для CRM](./recipes/telegram-bot.md), [массовая рассылка по контактам](./recipes/mass-messaging.md), [автоматизация задач](./recipes/task-automation.md), [синхронизация с 1С/ERP](./recipes/erp-sync.md). Для разработчика и AI-модели: [работа с данными](./entity-api.md), [фильтрация](./filtering.md), [Batch API](./batch.md), [оптимизация](./optimization.md), [инфраструктура](./infra.md), [коды ошибок](./errors.md). --- # Создание и использование ключа Ключ — это учётные данные для доступа к API Вайбкод. Эта страница проводит через создание ключа в личном кабинете шаг за шагом и разбирает каждый параметр формы: название, скоупы, срок действия, лимит запросов и список разрешённых IP. **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` Скоуп — это разрешение на доступ к определённой группе данных портала. Какие скоупы выбрать под задачу — на отдельной странице [Скоупы](./scopes.md). ## Разделы документации - [Самоописание ключа](/docs/keys-auth/me) — что `GET /v1/me` рассказывает о ключе, портале, тарифе и доступных возможностях - [Авторизация пользователей приложения](/docs/keys-auth/oauth) — вход через Битрикс24 и обмен на токен сессии для приложений от лица разных пользователей - [Справочник API для модели](/docs/keys-auth/guide) — `GET /v1/guide`, контракт полей всех сущностей без токена сессии - [Режим доступа](/docs/keys-auth/access-mode) — ключ только на чтение, политика портала, блокировка записи ## Типы ключей | Тип | Префикс | Назначение | Авторизация | |-----|---------|------------|-------------| | **API-ключ** | `vibe_api_` | Доступ к данным портала через API Вайбкод | Заголовок `X-Api-Key` | | **Ключ авторизации** | `vibe_app_` | Встраивание приложения в портал и OAuth-авторизация Битрикс24 | `X-Api-Key` + токен сессии | | **Менеджмент-ключ** | `vibe_live_` | Администрирование платформы | Заголовок `X-Api-Key` | **API-ключ (`vibe_api_`).** Создаётся в личном кабинете и привязан к одному порталу Битрикс24. Все запросы идут от лица владельца ключа, токен сессии не требуется. Подходит для личных сводных панелей, скриптов, серверных интеграций и ботов на своём портале. **Ключ авторизации (`vibe_app_`).** Привязан к Вайбкод-приложению с OAuth-учётными данными Битрикс24. Каждый запрос отправляется от лица пользователя, установившего приложение и прошедшего авторизацию, — поэтому нужен заголовок `Authorization: Bearer`. Подходит для приложений из каталога, которые работают от лица разных пользователей того портала, где приложение зарегистрировано. Этот же ключ нужен, чтобы приложение открывалось внутри Битрикс24 — в левом меню, вкладке CRM или виджете (раздел [Встраивание приложения в портал](#встраивание-приложения-в-портал)). **Менеджмент-ключ (`vibe_live_`).** Не привязан к одному порталу, предназначен для администрирования: управления ключами, просмотра порталов, работы с обратной связью. Доступа к данным сущностей Битрикс24 не имеет. Полное описание — [Менеджмент-ключи](./management-keys.md). Дальше — создание обоих ключей портала: API-ключа (`vibe_api_`) и ключа авторизации (`vibe_app_`). Формы отличаются, отличие описано ниже. Менеджмент-ключ (`vibe_live_`) описан отдельно — [Менеджмент-ключи](./management-keys.md). ## Создание API-ключа 1. Войдите в [личный кабинет](/dashboard). 2. Откройте раздел [Ключи API](/keys). 3. Нажмите **Создать**. 4. Заполните форму (шаги ниже). 5. Скопируйте ключ — он показывается один раз. ### Шаг 1. Название Произвольное название для самого себя — по нему ключ виден в списке. На доступ не влияет. Заведите отдельный ключ с понятным названием для каждого сервиса или интеграции — это упрощает отзыв при компрометации. ### Шаг 2. Скоупы В форме скоупы сгруппированы во вкладки «Битрикс24» и «Вайбкод», нужно отметить минимум один. Полный список скоупов, описание каждого и подбор набора под задачу — на странице [Скоупы](./scopes.md). Короткий ориентир: `crm` — данные CRM, `tasks` — задачи, `imbot` + `im` — чат-бот, `disk` — файлы. Скоупы Вайбкод (`vibe:infra`, `vibe:ai`, `vibe:search`, `vibe:storage`, `vibe:feedback`) отмечены в форме заранее — ключ, выпущенный без правок, получает их все. Галочки при этом рабочие: снимите ненужные, и ключ выпустится ровно с оставшимися. Ключ только с `vibe:storage` вернёт `403` на создание сервера и на вызовы AI. Набор скоупов Битрикс24 закрепляется за ключом в момент выпуска. Если добавить скоуп Битрикс24 в настройках уже существующего ключа, `GET /v1/me` покажет его в списке, но запросы, которым он нужен, вернут `BITRIX_ACCESS_DENIED`: к данным Битрикс24 ключ обращается с тем набором скоупов, с которым был выпущен. Чтобы выдать ключу новый скоуп Битрикс24: - **API-ключ (`vibe_api_`)** — [перевыпустите ключ](#перевыпуск) или создайте новый с отмеченным скоупом. - **Ключ авторизации (`vibe_app_`)** — создайте приложение заново с нужным скоупом и пройдите авторизацию заново (перевыпуск ключа здесь скоуп не выдаёт). Скоуп выдаётся при выпуске только если он доступен на портале Битрикс24. Если после перевыпуска или повторной авторизации вызов всё ещё возвращает `BITRIX_ACCESS_DENIED`, значит скоуп для этого ключа на портале не предоставлен. ### Шаг 3. Срок действия Когда ключ перестанет действовать. Варианты: без ограничения, 30, 90, 180 или 365 дней. После истечения срока запросы с ключом отклоняются с кодом `KEY_EXPIRED`. Для серверных интеграций задавайте конечный срок и обновляйте ключ заранее. ### Шаг 4. Лимит запросов Необязательный индивидуальный лимит для этого ключа. Если поле пустое — применяются общие лимиты платформы и портала (раздел «Лимиты запросов» ниже). Значение, действующее для ключа, возвращает `GET /v1/me` в поле `rateLimit.requestsPerSecond`. ### Шаг 5. Список разрешённых IP В блоке «Расширенные настройки». Ограничивает вызовы ключа списком IP-адресов. Поддерживаются точные адреса IPv4 и IPv6, по одному в строке. Подсети в формате CIDR (бесклассовая адресация) не поддерживаются. ``` 192.168.1.100 203.0.113.42 2001:db8::1 ``` Запрос с адреса вне списка отклоняется с кодом `403 IP_NOT_ALLOWED`. Если список пуст — ограничения по IP нет. ### Шаг 6. Сохраните ключ Полный ключ показывается **один раз** сразу после создания. Скопируйте и сохраните его в надёжном месте — повторно его получить нельзя, только перевыпустить. ## Создание ключа авторизации Ключ авторизации (`vibe_app_`) создаётся в разделе [Ключи авторизации](/apps) личного кабинета. Форма короче, чем у API-ключа: всего два поля. 1. Откройте раздел [Ключи авторизации](/apps) и нажмите **Создать**. 2. **Название** — под ним приложение видно в списке. 3. **Скоупы** — те же две группы «Битрикс24» и «Вайбкод», минимум один. Подбор набора описан на странице [Скоупы](./scopes.md). 4. Скопируйте ключ — он показывается один раз. Срок действия, лимит запросов и список разрешённых IP в этой форме не задаются — этим она и отличается от формы API-ключа. После создания ключ авторизации работает в паре с токеном сессии: каждый запрос отправляется с заголовками `X-Api-Key` и `Authorization: Bearer` (раздел «Передача ключа»). ## Встраивание приложения в портал Если приложение должно открываться **внутри Битрикс24** — пунктом в левом меню, вкладкой в карточке CRM или виджетом на рабочем столе, — для этого нужен **ключ авторизации** (`vibe_app_`). API-ключ (`vibe_api_`) встраивание в интерфейс портала не поддерживает: с ним приложение обращается к данным, но не размещается в окне Битрикс24. Ключ авторизации даёт две возможности, которых нет у API-ключа: - **Размещение в интерфейсе.** Приложение появляется в выбранном месте портала — за это отвечает [привязка места встраивания](/docs/apps/placements/bind). Доступные места возвращает [справочник](/docs/apps/placements/available), полный порядок работы — [Места встраивания](/docs/apps/placements). - **Прозрачная авторизация.** Пользователь открывает приложение внутри Битрикс24 без отдельного входа: Gateway сам определяет, кто открыл приложение, и передаёт его данные серверу приложения. Браузер токен сессии не видит. Порядок действий: 1. Создайте ключ авторизации в разделе [Ключи авторизации](/apps) — форма описана выше в разделе «Создание ключа авторизации». 2. Передайте AI-модели именно ключ авторизации (`vibe_app_`) и попросите приложение со встраиванием в портал. 3. Модель вызовет `GET /v1/me` с этим ключом и получит раздел `placements` с полным порядком встраивания. Полный жизненный цикл встроенного приложения, паттерн BFF — отдельный сервер-посредник для фронтенда и примеры обработчика на Node, Python и Go — [Авторизация в приложении на BlackHole](./infra/app-runtime.md). ### Приложение на своём сервере Если приложение размещено на собственном сервере, а не за BlackHole, и открывается как размещение, страница согласия Битрикс24 внутри `iframe` не открывается. Токен сессии текущего пользователя получают через одноразовый код или `POST /v1/oauth/placement-session` — по тому, чей обработчик принимает размещение. Порядок для обоих случаев — [Авторизация пользователей приложения](/docs/keys-auth/oauth#приложение-на-своём-сервере). ## Передача ключа Ключ передаётся в заголовке `X-Api-Key`: ```bash curl -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/deals ``` Клиенты, которые умеют отправлять только `Authorization: Bearer` (например, OpenAI-совместимые), могут передать сам API-ключ (`vibe_api_…`) в этом заголовке вместо `X-Api-Key` — для ключа оба заголовка равнозначны. Это работает на всех V1-эндпоинтах, включая бот-платформу: ```bash curl -H "Authorization: Bearer YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/bots ``` У ключа авторизации (`vibe_app_…`) заголовок `Authorization: Bearer` занят токеном сессии, поэтому сам ключ всегда идёт в `X-Api-Key`. Способ с одним заголовком `Authorization: Bearer` применим только к ключам `vibe_api_` и `vibe_live_`. Для ключа авторизации (`vibe_app_`) дополнительно передаётся токен сессии в заголовке `Authorization: Bearer`: ```bash curl -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ https://vibecode.bitrix24.tech/v1/deals ``` Если для ключа `vibe_app_` не передан `Authorization: Bearer`, эндпоинты, которым нужен пользовательский контекст, возвращают `401 TOKEN_MISSING`: у запроса нет данных, от чьего имени обращаться к Битрикс24. Эндпоинты `/v1/me`, `/v1/guide` и `/v1/oauth/*` работают без `Bearer`. Это касается и эндпоинтов схемы — `GET /v1//fields` и `GET /v1/userfields/*`: они выглядят как статическая схема, но запрашивают метаданные полей (включая пользовательские) у Битрикс24 в реальном времени, поэтому тоже требуют пользовательского контекста. Для сценария «узнать доступные поля до встраивания приложения и появления сессии пользователя» используйте персональный API-ключ (`vibe_api_…`) — он отдаёт схему по одному заголовку `X-Api-Key`, без `Bearer`. Ответ `401 TOKEN_MISSING` для такого вызова сам подсказывает оба пути. Что каким способом читать: | Что нужно | Чем авторизоваться | Куда идти | |---|---|---| | Статический контракт полей (типы, `readonly`, `enum`, `required`, `createOnly`) — до установки, без сессии | ключ авторизации по `X-Api-Key` (без `Bearer`) | [`GET /v1/guide`](/docs/keys-auth/guide) → поле `data.entities[].fieldsDetailed` | | Названия полей для отображения, живые поля портала и пользовательские поля `UF_CRM_*` | сессия (`Bearer`) на ключе авторизации или персональный API-ключ (`vibe_api_…`) | `GET /v1//fields`, `GET /v1/userfields/*` | **Токен сессии живёт 24 часа и не обновляется.** `POST /v1/oauth/token` (и `GET /v1/oauth/poll`) выдают `access_token` с `expires_in: 86400` — без `refresh_token` и без запроса на обновление. Механизма продления нет — это сознательное решение. После истечения 24 часов получите новый токен сессии, заново пройдя авторизацию OAuth: `GET /v1/oauth/authorize` → `POST /v1/oauth/token`. После истечения вызовы за пользователя возвращают `401 INVALID_SESSION` — это сигнал заново авторизоваться. Для фоновых сценариев — расписания, серверные интеграции, скрипты без пользователя у экрана, которому нечем пройти авторизацию заново каждые 24 часа — используйте персональный API-ключ (`vibe_api_…`): он работает от лица владельца ключа без токена сессии, и единственное ограничение по сроку — собственный срок действия ключа (см. выше). Ключ авторизации (`vibe_app_…`) предназначен для приложений, где пользователь присутствует и проходит OAuth. Эндпоинты создания инфраструктуры (`POST /v1/infra/servers`, а также `POST /api/agents` и `POST /api/managed-bots` через личный кабинет) требуют, чтобы платформа точно знала, **кто** создаёт сервер — это нужно для тарифной проверки и учёта в лимитах. Для ключей `vibe_app_` это значит наличие `Authorization: Bearer `. На чтение (`GET /v1/infra/servers`, `GET /v1/me`) сессия не нужна. Как `GET /v1/me` отвечает с сессией и без неё — [Самоописание ключа](/docs/keys-auth/me). ## Сколько ключей можно создать Число ключей на одного пользователя портала ограничено. По умолчанию — 10 ключей. Значение задаёт администратор аккаунта в кабинете, на странице «Настройки» → карточка «Лимиты для пользователей» → поле «Макс. ключей на пользователя», и может поднять его до 100. В этот лимит входят все ключи пользователя на портале — и API-ключи (`vibe_api_`), и ключи авторизации (`vibe_app_`), которые создаются при регистрации приложений. Отдельного лимита на приложения нет. Приложения расходуют тот же счётчик, что и личные ключи. Когда лимит достигнут, создание нового ключа или приложения возвращает `409 KEY_LIMIT_REACHED`. В счёт лимита идут ключи в любом состоянии, кроме отозванного, поэтому истёкший ключ место не освобождает — чтобы освободить место, отзовите неиспользуемый ключ. Состояние квоты приходит вместе с отказом, в `error.details`: `limit` — сколько ключей разрешено, `used` — сколько занято. В `used` входят и ключи авторизации приложений, и ключи, выписанные самой платформой, поэтому число бывает больше, чем список ключей в кабинете: там показаны не все из них. Расхождение ожидаемое, а не потеря записей. ## Жизненный цикл ключа ``` Создание → Активен → Перевыпуск / Отзыв / Удаление ``` ### Состояния ключа | Состояние | Значение в API | Описание | |-----------|----------------|----------| | **Активен** | `ACTIVE` | Ключ готов к использованию | | **Истёк** | `ACTIVE` | Дата в поле `expiresAt` прошла. Поле `status` при этом остаётся `ACTIVE` — истечение определяется по дате, а запросы отклоняются с кодом `401 KEY_EXPIRED` | | **Отозван** | `REVOKED` | Ключ деактивирован, запросы отклоняются | ### Готовность к вызовам Битрикс24 `status: ACTIVE` означает, что платформа принимает ключ, — но не то, что вызовы к порталу выполнимы. Личный ключ (`vibe_api_`) ходит в Битрикс24 по вебхуку, и вебхука на ключе может не быть: например, у портала нет активной подписки на Битрикс24 Маркет в момент выдачи ключа. Такой ключ проходит авторизацию, работает с эндпоинтами самой платформы Вайбкод — и отвечает `401 TOKEN_MISSING` на любой вызов к порталу. Готовность видна двумя способами: | Где | Что смотреть | |-----|--------------| | `GET /v1/keys` и `GET /v1/keys/{id}` | признак `b24Ready`: `true` — вебхук есть, `false` — нет, `null` — к ключу не применимо (ключ приложения, управляющий ключ или ключ без скоупов Битрикс24) | | [`GET /v1/me`](/docs/keys-auth/me) | блок `b24Credentials` у личного ключа: `ready`, а при `ready: false` — `reason`, `paywallCode`, `upgradeUrl` и подсказка `hint` | Причины и действия по каждой из них — [Коды ошибок](./errors.md#token_missing-401). Общий порядок: устранить причину на портале, затем **переподключить ключ** — `POST /api/keys/:id/reconnect` выдаёт вебхук существующему ключу, не меняя саму строку ключа. Новый ключ нужен только там, где переподключение не применимо: ключи приложения, системные ключи и ключи без скоупов Битрикс24. Ответ `/v1/me` кэшируется на 30 секунд, поэтому сразу после починки читайте его как `GET /v1/me?refresh=tariff`. ### Перевыпуск Перевыпуск создаёт новый ключ и оставляет старому переходный период 24 часа — это позволяет обновить ключ в приложениях без простоя: 1. Запустите перевыпуск в личном кабинете. 2. Получите новый ключ. 3. Обновите ключ в своих приложениях. 4. Старый ключ действует ещё 24 часа. 5. По истечении переходного периода старый ключ становится недействительным. ### Отзыв и удаление Отзыв переводит ключ в состояние `REVOKED`: последующие запросы отклоняются с `401 KEY_INACTIVE`. Если на ключе есть активные серверы, удаление возвращает `409 KEY_HAS_ACTIVE_SERVERS`: полное число серверов — в поле `details.activeServerCount`, а в `details.servers` приходит список не больше чем из 10 самых новых. Смените у них управляющий ключ — [Восстановление доступа к серверу](/docs/infra/server-access-recovery). Удалять сами серверы для этого не нужно. Если ключом управляется агент или бот, удаление возвращает `409 KEY_HAS_LINKED_AGENT`: число агентов — в поле `details.linkedAgentCount`, число ботов — в `details.linkedBotCount`, а в `details.agents` приходит список не больше чем из 10 связанных агентов. Сначала удалите агента или бота. Ключ с именем `Connect: <приложение>` выдан стороннему приложению через [Partner Connect](/docs/partner-connect) — им управляют не здесь, а в разделе «Подключённые приложения» вашего профиля. Отзыв там гасит сразу все ключи, которые вы выдали этому приложению для этого портала; отзыв одной строки в списке ключей погасит только её. ### Если ключ скомпрометирован 1. Отзовите ключ в личном кабинете. 2. Создайте новый ключ с теми же скоупами. 3. Обновите ключ во всех приложениях. 4. Если на отозванном ключе были серверы, смените у них управляющий ключ на новый — [Восстановление доступа к серверу](/docs/infra/server-access-recovery). 5. Проверьте журнал запросов на обращения с неизвестных адресов. 6. Включите список разрешённых IP. ## Рекомендации по безопасности - Храните ключи в переменных окружения или менеджере секретов, не в коде и не в git. - Не передавайте ключи через мессенджеры и почту. - Назначайте ключу только необходимые скоупы — подбор набора описан на странице [Скоупы](./scopes.md). - Заводите отдельный ключ для каждого сервиса и отзывайте неиспользуемые. - Для серверных интеграций включайте список разрешённых IP и конечный срок действия. - Перевыпускайте ключи по расписанию (например, раз в 90 дней). ## Лимиты запросов К каждому ключу одновременно применяются две независимые системы лимитов: лимит платформы Вайбкод и лимит портала Битрикс24. ### Лимит платформы Вайбкод | Параметр | Значение | |----------|----------| | Лимит запросов | 300 запросов в минуту на источник | | Окно лимита | Скользящее окно 60 секунд | | Заголовок лимита | `X-RateLimit-Limit` | | Заголовок остатка | `X-RateLimit-Remaining` | | Заголовок сброса | `X-RateLimit-Reset` (секунды до сброса окна) | При превышении возвращается `429 Too Many Requests` с кодом `RATE_LIMITED`. ``` X-RateLimit-Limit: 300 X-RateLimit-Remaining: 245 X-RateLimit-Reset: 25 ``` ### Лимит портала Битрикс24 Портал ограничивает скорость обращений (по умолчанию 10 запросов в секунду, лимит делится между всеми ключами портала). При превышении возвращается `502 BITRIX_UNAVAILABLE`. Действующее для ключа значение возвращает `GET /v1/me` в поле `rateLimit.requestsPerSecond`. Один вызов считается за единицу. Один `POST /v1/batch` с 50 операциями расходует одну единицу. ### Рекомендации при лимитах - Объединяйте запросы через `POST /v1/batch` (до 50 операций за вызов). - Кэшируйте данные, которые не меняются между вызовами. - При `429` повторяйте запрос с увеличением паузы (1 с → 2 с → 4 с). - Опирайтесь на заголовки `X-RateLimit-*`, чтобы не доводить до отказа. ### Коды ошибок ключа | HTTP | Код | Когда возвращается | |------|-----|---------------------| | 401 | `KEY_INACTIVE` | Ключ отозван или заблокирован платформой | | 401 | `KEY_EXPIRED` | У ключа задан срок действия, и он прошёл | | 401 | `INVALID_API_KEY` | Ключ не найден | | 401 | `TOKEN_MISSING` | У ключа нет кредов Битрикс24: для `vibe_app_` не передан `Authorization: Bearer`, для `vibe_api_` — на ключе нет вебхука портала (причина в `error.details`, см. [Коды ошибок](./errors.md)) | | 401 | `WRONG_AUTH_SCHEME` | Ключ авторизации `vibe_app_` передан в заголовке `Authorization: Bearer`. Ключ приложения передаётся в `X-Api-Key`, а `Authorization: Bearer` несёт сессионный токен. Клиенту, который умеет только `Bearer`, подходит личный ключ `vibe_api_` | | 403 | `IP_NOT_ALLOWED` | Запрос с адреса вне списка разрешённых IP | | 403 | `WRITE_BLOCKED_READONLY_KEY` | У ключа задан режим «только чтение», а вызов выполняет запись — [Режим доступа](/docs/keys-auth/access-mode) | Полный справочник кодов — [Коды ошибок](./errors.md). ## Справочник эндпоинтов | Метод | Путь | Описание | |-------|------|----------| | GET | [`/v1/me`](/docs/keys-auth/me) | Самоописание ключа: тип, портал, скоупы, лимиты, доступные возможности | | GET | [`/v1/guide`](/docs/keys-auth/guide) | Контракт полей всех сущностей и правила работы с API | | GET, POST | [`/v1/oauth/*`](/docs/keys-auth/oauth) | Авторизация пользователей приложения: вход через Битрикс24, обмен на токен сессии | ## Смотрите также - [Самоописание ключа](/docs/keys-auth/me) - [Авторизация пользователей приложения](/docs/keys-auth/oauth) - [Справочник API для модели](/docs/keys-auth/guide) - [Режим доступа](/docs/keys-auth/access-mode) - [Восстановление доступа к серверу](/docs/infra/server-access-recovery) - [Подключение коробочного Битрикс24](/docs/connect-self-hosted-bitrix24) - [Скоупы](/docs/scopes) - [Менеджмент-ключи](/docs/management-keys) - [Коды ошибок](/docs/errors) --- # Обзор API Вайбкод предоставляет единый REST-интерфейс для работы с сущностями Битрикс24: CRM, задачи, пользователи, календарь, диск, каталог, документооборот и другие. Формат запроса, ответа и ошибок у всех сущностей одинаковый. > Базовый URL: `https://vibecode.bitrix24.tech` > Авторизация: заголовок `X-Api-Key: ваш_ключ` > Ключи `vibe_app_…` дополнительно требуют заголовок `Authorization: Bearer` с токеном сессии на каждый запрос к сущностям. Для фоновых задач (cron, планировщик) без пользователя у экрана берите ключ `vibe_api_…`. Подробнее — [Создание и использование ключа](./keys-auth.md). ## Доступные операции Ниже описан стандартный набор операций. Путь строится по шаблону `/v1/{entity}`. Набор операций у каждой сущности свой: у части сущностей отдельные операции недоступны. Какие операции доступны сущности, показывают колонка «Операции» в [Справочнике сущностей](/docs/entities-index) и поле `operations` в ответе [`GET /v1/guide`](/docs/keys-auth/guide). Запрос к операции, которой у сущности нет, отвечает `404 ROUTE_NOT_FOUND` — [Коды ошибок](./errors.md). ### Список — `GET /v1/{entity}` Получить записи с пагинацией, сортировкой и выборкой полей. ```bash curl -H "X-Api-Key: $KEY" \ "https://vibecode.bitrix24.tech/v1/deals?limit=100&offset=0" ``` Параметры: | Параметр | Тип | Описание | |----------|-----|---------| | `limit` | number | Количество записей (по умолчанию 50, максимум 5000). Значение `0` размером страницы не является: параметр отбрасывается, применяется значение по умолчанию, а в ответ добавляется предупреждение `LIMIT_ZERO_IGNORED` в `meta.warnings` | | `offset` | number | Пропустить N записей | | `select` | string[] | Выборка полей: `?select=id,title,amount`. Принимаются канонические имена из `GET /v1/{entity}/fields`, исходные имена Битрикс24 у объявленных полей и взаимозаменяемые имена дат `updatedAt` / `updatedTime`, `createdAt` / `createdTime`. Незнакомое имя даёт предупреждение `UNKNOWN_SELECT_FIELD` в `meta.warnings`, у событий календаря — ошибку `400`. Значение `*` (и `UF_*`, в любом регистре) означает «вернуть все поля» — отбор не применяется, а незнакомое имя рядом с ним даёт предупреждение вместо ошибки | | `order` | object | Сортировка: `?order[createdAt]=desc` | | `withTotal` | string | Нужно ли количество: `true` или `false`, ровно эти два значения. `false` — единственный способ гарантированно убрать `meta.total` из ответа. При `limit` не больше 50 он заодно отменяет подсчёт, при `limit` больше 50 — убирает число, а не подсчёт. Без параметра значение берётся из настройки ключа, затем из платформенного умолчания, и тогда на короткой странице точное количество приходит и без заказа — см. [Листание и количество записей](#листание-и-количество-записей) | **Авто-пагинация:** при `limit > 50` Вайбкод автоматически запрашивает несколько страниц у Битрикс24 и возвращает все записи в одном ответе. ### Получить по ID — `GET /v1/{entity}/{id}` ```bash curl -H "X-Api-Key: $KEY" \ "https://vibecode.bitrix24.tech/v1/deals/123" ``` Ответ: `{ success: true, data: { id: 123, title: "...", ... } }` Параметр `select` работает и при получении записи по `id` — ответ содержит только перечисленные поля. Поддерживаются три формы: список через запятую `?select=id,title,stageId`, повторяющийся ключ `?select[]=id&select[]=title` и индексируемый `?select[0]=id&select[1]=title`. Поле `id` возвращается всегда. Незнакомое имя поля не отклоняется — ответ дополняется предупреждением `UNKNOWN_SELECT_FIELD` в `meta.warnings`. Исключение — события календаря: там незнакомое имя отвечает ошибкой `400`. Пользовательское поле указывается именем из схемы — [Пользовательские поля (UF)](#пользовательские-поля-uf). Значение `*` (и `UF_*`) — привычная для Битрикс24 запись «вернуть все поля»: отбор не применяется, приходит полная запись. Параметр совместим с `include` — связанные данные подгружаются до отбора полей. ### Создать — `POST /v1/{entity}` ```bash curl -X POST -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \ "https://vibecode.bitrix24.tech/v1/deals" \ -d '{"title": "Новая сделка", "stageId": "NEW", "amount": 150000}' ``` Ответ: `{ success: true, data: { id: 456, ... } }` (HTTP 201) Тело без единого поля возвращает `400 EMPTY_CREATE_BODY`, а у сущностей с обязательными полями создания — `400 MISSING_REQUIRED_FIELDS` с именем первого недостающего поля. Оба кода — [Коды ошибок](./errors.md). ### Обновить — `PATCH /v1/{entity}/{id}` ```bash curl -X PATCH -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \ "https://vibecode.bitrix24.tech/v1/deals/123" \ -d '{"stageId": "WON", "amount": 200000}' ``` Тело без единого поля возвращает `400 EMPTY_UPDATE_BODY` — [Коды ошибок](./errors.md). ### Удалить — `DELETE /v1/{entity}/{id}` ```bash curl -X DELETE -H "X-Api-Key: $KEY" \ "https://vibecode.bitrix24.tech/v1/deals/123" ``` ### Поиск — `POST /v1/{entity}/search` Поиск с фильтрацией. Подробнее о синтаксисе фильтров: [Фильтрация](./filtering.md) ```bash curl -X POST -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \ "https://vibecode.bitrix24.tech/v1/deals/search" \ -d '{"filter": {"stageId": "NEW", "amount": {"$gte": 100000}}, "sort": {"createdAt": "desc"}, "limit": 200}' ``` Параметры: | Параметр | Тип | Описание | |----------|-----|---------| | `filter` | object | Условия фильтрации ([три синтаксиса](./filtering.md)) | | `sort` | string \| object \| array | Сортировка. Поддерживаются: `"id"` / `"-amount"` / `"id,-createdAt"` (string), `{ id: "asc", amount: "desc" }` или `{ id: 1, amount: -1 }` (object), `["id", "-amount"]` (array). Некорректный тип → `400 INVALID_SORT_TYPE`. Подробнее про пагинацию — см. [filtering.md](./filtering.md#постраничный-вывод). | | `limit` | number | Количество записей (по умолчанию 50, максимум 5000, авто-пагинация при > 50). Значение `0` отбрасывается — см. предупреждение `LIMIT_ZERO_IGNORED` | | `offset` | number | Пропустить N записей | | `autoWindow` | boolean | `false` — отключить разбивку по дате для больших выборок | | `withTotal` | boolean | Нужно ли количество. `false` — единственный способ гарантированно убрать `meta.total` из ответа. При `limit` не больше 50 он заодно отменяет подсчёт, при `limit` больше 50 — убирает число, а не подсчёт. Без поля значение берётся из настройки ключа, затем из платформенного умолчания, и тогда на короткой странице точное количество приходит и без заказа — см. [Листание и количество записей](#листание-и-количество-записей) | **Windowed search:** для больших наборов данных поиск автоматически разбивает запрос на временные окна. Если это вызывает таймауты — отключите через `autoWindow: false`. ### Агрегация — `POST /v1/{entity}/aggregate` Подсчёт количества и числовые агрегации (`sum`, `avg`, `min`, `max`) с фильтрацией. Набор операций каждой сущности перечислен в [Справочнике сущностей](/docs/entities-index). У сущностей без агрегации количество записей приходит в `meta.total` ответа списка. ```bash curl -X POST -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "amount", "function": "sum" }, { "field": "amount", "function": "avg" } ], "filter": { "stageId": "WON" } }' \ "https://vibecode.bitrix24.tech/v1/deals/aggregate" ``` Параметры (body): | Параметр | Тип | Описание | |----------|-----|---------| | `aggregate` | array | Массив агрегаций: `{ "field": "amount", "function": "sum" }`. Функции: `count`, `sum`, `avg`, `min`, `max`. Без массива — только `count` | | `filter` | object | Фильтрация по полям сущности | | `groupBy` | string \| string[] | Поле или массив полей для группировки (максимум 5). Допустимые значения — из списка `aggregatable` конкретной сущности. У сущностей без этого списка (например, `statuses`, `currencies`, `deal-categories`) группировка не поддерживается, доступен `count` с фильтром | > **Как это работает:** `count` считается одним быстрым вызовом в Битрикс24. Для `sum`/`avg`/`min`/`max` платформа подгружает записи под фильтр (до 5000 — больше помечается `meta.truncated: true`) и считает на стороне Вайбкод. Полное поведение на выборке шире 5000 — [Агрегация POST — потолок 5000 записей](#агрегация-post-потолок-5000-записей). При некорректном поле ответ содержит список доступных. > **Пользовательские поля (UF)** поддерживаются в `sum`/`avg`/`min`/`max` для UF-типов `integer`, `double`, `money`. `groupBy` принимает UF-поля любого типа. Подробно — в разделе [Агрегация POST — UF-поля](#агрегация-post-uf-поля) ниже. > **Смарт-процессы (items)** используют path-параметр: `POST /v1/items/:entityTypeId/aggregate`. Зарезервированные `entityTypeId` (1, 2, 3, 4, 7, 31) обслуживаются специализированными API сделок, лидов, контактов, компаний, предложений, счетов. ### Агрегация POST — потолок 5000 записей Потолок действует на запросе, которому для ответа нужны сами записи: это числовые функции и группировка. Простой `count` без `groupBy` под него не подпадает — он считается на стороне Битрикс24 и отвечает на выборке любого размера. Поведение на выборке шире 5000 записей сейчас раскатывается по аккаунтам, поэтому вариантов два: - **Пока возможность не включена на аккаунте** — приходит `200`, в ответе `meta.truncated: true`, результат посчитан по первым 5000 записям. - **После включения** — приходит `422 AGGREGATION_LIMIT_EXCEEDED`, и ни одна запись не выгружается. В тексте ошибки перечислено, что делать дальше. Смысл замены: на крупной выборке выгрузка первых 5000 всё равно не успевала, запрос обрывался по таймауту, и усечённый ответ до вызывающего чаще всего не доходил вовсе. Действие в обоих случаях одно: сузить фильтр либо взять `count` без группировки. Клиент, который сегодня ветвится по `meta.truncated`, после включения возможности на его аккаунте начнёт получать `422` — предусмотрите обе ветки. **`meta.truncated` теперь поднимается ещё в одном случае — и это касается ВСЕХ сущностей, не только дел.** Если записей обработано меньше, чем всего под фильтр (страница записей до нас не дошла), ответ ставит `truncated: true` и добавляет `meta.recordsShortfall` — сколько записей не хватило. Раньше в этом случае приходило `truncated: false`, то есть группы и числовые агрегации считались по части записей, а ответ этого не сообщал. `count` и `meta.totalRecords` остаются полными. У сделок группировка по стадиям отвечает на воронке любого размера, минуя этот потолок, — [Агрегация сделок](./entities/deals/aggregate.md). ### Агрегация POST — сужающий фильтр у дел У дел ограничение другого рода, и оно касается даже простого `count`: Битрикс24 не успевает посчитать все дела аккаунта за отведённое на вызов время. Поэтому агрегация дел требует **одного** сужения — пара `ownerTypeId` + `ownerId`, либо `responsibleId`, либо граница по дате на `createdAt` / `updatedAt` / `deadline`. Без сужения приходит `400 MISSING_REQUIRED_FILTER` с перечнем допустимых сужений, а если требование на аккаунте ещё не включено — `422 AGGREGATION_LIMIT_EXCEEDED` в тот момент, когда Битрикс24 действительно не ответил. Ни то, ни другое повторять бессмысленно. Подробно — [Агрегация дел](./entities/activities/aggregate.md). ### Агрегация POST — UF-поля Канонический POST-вариант агрегации принимает массив выражений и поддерживает пользовательские поля. Имя поля — то же, что в схеме сущности: на другое написание приходит `400 INVALID_PARAMS` со списком доступных полей. ```bash curl -X POST https://vibecode.bitrix24.tech/v1/deals/aggregate \ -H "X-Api-Key: $KEY" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "function": "sum", "field": "amount" }, { "function": "sum", "field": "ufCrmBudget" }, { "function": "avg", "field": "ufCrmScore" } ], "groupBy": "ufCrmPriority" }' ``` **Правила UF-поддержки:** | Функция | Принимает UF-типы | |---------|-------------------| | `sum`, `avg`, `min`, `max` | только `integer`, `double`, `money` | | `groupBy` | любой UF-тип (string, enumeration, date, integer, …) | **Поля типа `money`** хранятся в Битрикс24 как строка `"сумма|валюта"` (например `"1500.50|RUB"`). Агрегат извлекает числовую часть до `|` — все арифметические операции корректны. **Ошибки:** | HTTP | Код | Когда | |------|-----|-------| | 400 | `INVALID_PARAMS` | UF-тип не из списка `integer`/`double`/`money` для `sum`/`avg`/`min`/`max` — в `message` указан фактический тип | | 400 | `INVALID_PARAMS` | Поле не найдено ни в схеме, ни в UF-кэше — в `message` перечислены доступные стандартные и UF-поля | **Кэш UF-полей:** одно обращение к `crm.{entity}.fields` на комбинацию `портал+сущность` (+entityTypeId для items). TTL 5 минут — повторные агрегаты в пределах окна не вызывают дополнительных запросов. ### Схема полей — `GET /v1/{entity}/fields` Получить описание всех полей сущности с типами. ```bash curl -H "X-Api-Key: $KEY" \ "https://vibecode.bitrix24.tech/v1/deals/fields" ``` Метаданные каждого поля в ответе содержат отображаемое название `label` и пояснение назначения `description`, где они заданы для поля. Названия полей не нужно искать в отдельном справочнике — они приходят вместе со схемой. Названия и пояснения приходят на русском языке. Заголовками запроса язык не переключается. Названия полей, которые платформа берёт напрямую с портала, включая пользовательские, приходят на языке портала. ### Пакетные операции — `POST /v1/{entity}/batch` Массовое создание, обновление или удаление записей одной сущности. ```json { "action": "create", "items": [{ "title": "Сделка 1" }, { "title": "Сделка 2" }] } ``` Для работы с **разными сущностями** в одном запросе используйте [Batch API](./batch.md). ## Формат ответа Все эндпоинты возвращают единый формат: ```json { "success": true, "data": [ ... ], "meta": { "total": 150, "hasMore": true } } ``` | Поле | Описание | |------|---------| | `success` | `true` при успешном выполнении | | `data` | Массив записей (list/search) или объект (get/create) | | `meta.total` | Общее количество записей под фильтр (для list/search). Необязательное поле: если количество не заказывалось, его в ответе нет — см. [Листание и количество записей](#листание-и-количество-записей) | | `meta.hasMore` | Есть ли ещё записи для загрузки | | `meta.nextAfterId` | Идентификатор последней отданной записи, строкой. Приходит у списка и у поиска при сортировке строго по `id` по возрастанию, пока `meta.hasMore` равен `true`. Передаётся обратно как `filter[>id]`. Сущности с курсором перечислены в [Листании и количестве записей](#листание-и-количество-записей) | | `meta.pageErrorSample` | Приходит у списка и у поиска, когда часть страниц не загрузилась: `code` и `message` первой ошибки. Ответ при этом содержит непрерывное начало выборки, а не все записи. `code` — либо код ошибки Битрикс24, либо код самого Вайбкод. Последних три. `KEYSET_DISCONTINUITY` означает, что обход прервал сам Вайбкод, обнаружив разрыв в последовательности страниц, и вернул непрерывное начало вместо возможных дублей. `PAGE2_COUNT_FAILED` — не удался подсчёт записей (тайм-аут, лимит запросов, ошибка портала). `LAZY_COUNT_NO_PROGRESS` — метод вернул те же записи вместо следующих. `meta.total` отсутствует только у двух последних: там подсчёт не состоялся. При остальных обрывах количество уже сосчитано, и `meta.total` приходит рядом | | `meta.windowErrorSample` | То же для поиска по окнам: `code` и `message` первого сорвавшегося окна. Приходит вместе с `meta.windowErrors` — числом неудачных окон. При полном отказе поиск возвращает ошибку, а не частичный ответ | | `meta.warnings` | Массив предупреждений о выдаче: у списка, поиска, получения записи по `id` и запроса схемы полей. У каждого есть `code` и `message`, а `field` — только когда предупреждение привязано к конкретному полю. Коды `LIMIT_ZERO_IGNORED` и `UNKNOWN_SELECT_FIELD` описаны в параметрах выше. `WINDOW_TRUNCATED` — оконный поиск отдал не всё, разбор в [неполной выдаче](./optimization.md#неполная-выдача). `OFFSET_BEYOND_FETCHED_PAGE` — страница вышла пустой на постраничном обходе, разбор в [обходе по страницам вручную](./filtering.md#идти-по-страницам-вручную) | Форма выше — про сущности этого справочника. Другие семейства маршрутов кладут служебные поля иначе: - **Глобальный [POST /v1/batch](./batch.md)** — `results`, `errors`, `summary`, `totals` и `meta` лежат внутри `data`, с разбивкой по `id` каждого вызова. - **Выделенные маршруты** — чаты, почта, лента, база знаний, звонки, рабочий день — несут свою форму `data`, она описана на страницах этих разделов. ### Листание и количество записей Листайте по `meta.hasMore`, а не по арифметике от `meta.total`. Признак «есть ещё» выводится из полноты страницы: пришла полная — возможно, есть ещё, пришла неполная — список закончился. Цикл «читай, пока `hasMore`» доходит до конца всегда. Если коллекция ровно кратна `limit`, последний шаг вернёт пустой список — это штатный признак конца, а не ошибка. При сортировке строго по `id` по возрастанию ответ дополнительно несёт `meta.nextAfterId` — идентификатор последней отданной записи. Передайте его обратно как `filter[>id]`, и следующая страница начнётся ровно за ней. Такое листание не зависит от смещения и не дорожает к концу коллекции, поэтому для обходов в десятки тысяч записей оно предпочтительнее растущего `offset`. Готовый цикл обхода — [Постраничный вывод](./filtering.md#постраничный-вывод). Курсор доступен у сделок, лидов, контактов, компаний, предложений и элементов смарт-процессов. У остальных сущностей `meta.nextAfterId` в ответе нет: страницы там берутся `offset`, а размер выборки сокращается фильтром. Количество записей — отдельный вопрос, и стоит он у Битрикс24 несоразмерно дорого: посчитать коллекцию заметно дороже, чем отдать из неё страницу. Поэтому: - **Нужна цифра** — спросите её прямо: `POST /v1/{entity}/aggregate` с функцией `count` возвращает количество одним вызовом, без выгрузки записей. - **Цифра не нужна** — уберите её из ответа: `withTotal=false` в запросе списка или настройка `totalDefault` на API-ключе, если так работает вся интеграция. Про то, в каких случаях `meta.total` при этом всё же приходит, — ниже в этом разделе. **Важно:** Нагрузку это снимает только на одностраничном вызове (`limit` не больше 50): там подсчёт действительно не заказывается. На многостраничном (`limit` больше 50) подсчёт платформе нужен, чтобы спланировать обход, поэтому параметр убирает число, а не стоимость. Ставить его ради экономии там незачем: дешевле вызов не станет, а точное количество, которое короткая первая страница отдаёт бесплатно, будет отброшено. - **Не эмулируйте счётчик обходом.** Пролистать коллекцию, чтобы посчитать строки, — это десятки и сотни вызовов вместо одного и самый дорогой способ узнать одну цифру. Для этого есть `aggregate` с `count`. Когда подсчёт не заказан, `meta.total` в ответе чаще всего отсутствует — но не всегда. Если страница пришла короче запрошенного `limit`, количество известно из самой страницы, и точное число всё равно приходит. Полная картина: | Что было в запросе | `meta.total` в ответе | |---|---| | Подсчёт заказан — умолчание или `withTotal=true` | приходит | | Передан `withTotal=false` | не приходит никогда | | Подсчёт отключён настройкой ключа или платформенным умолчанием, `offset = 0`, страница короче `limit` | приходит, точное число — в том числе `0` | | Подсчёт отключён настройкой ключа или платформенным умолчанием, страница полная либо `offset` больше нуля | не приходит | Таблица описывает вызов, на котором подсчёт **можно** пропустить. Там, где пропустить его нельзя, `withTotal=false` просто игнорируется и `meta.total` приходит как раньше. Поэтому проверяйте наличие поля в конкретном ответе, а не выводите его из настроек. Короче: если подсчёт не заказан, `total` приходит только на вызове с `offset = 0` и только если страница пришла короче запрошенного. Если подсчёт заказан — умолчанием или явным `withTotal=true` — он приходит всегда. Обратите внимание на разницу между параметром и настройкой: явный `withTotal=false` в запросе убирает и точное число из короткой страницы, а настройка `totalDefault` на ключе — нет. Поэтому два одинаковых запроса от двух разных ключей могут вернуть ответы разной формы. Из «подсчёт заказан — приходит всегда» есть одно исключение — частичный ответ, у которого сорвался сам подсчёт. Если в ответе есть `meta.pageErrorSample` с кодом `PAGE2_COUNT_FAILED` или `LAZY_COUNT_NO_PROGRESS`, `meta.total` отсутствует: количество не сосчитано, а число отданных строк его не заменяет. При остальных обрывах — `KEYSET_DISCONTINUITY` и любой код Битрикс24 — подсчёт состоялся до обрыва, и `meta.total` приходит рядом с `meta.pageErrorSample`. И тот и другой ответ приходит с кодом `200`, содержит непрерывное начало выборки и `meta.hasMore`, равный `true`. Сам подсчёт платформа выполняет, только когда без него не обойтись. На форме ответа это не сказывается: на многостраничном вызове (`limit` больше 50) `meta.total` приходит так же, как приходил, — просто иногда количество оказывается известно бесплатно. `meta.total` — информативное поле. Оно может отставать от текущего состояния коллекции до минуты, поэтому число отданных строк иногда оказывается больше него. Полнота данных от `meta.total` не зависит: за неё отвечают `meta.hasMore` и `meta.nextAfterId`. Действующее для вашего ключа умолчание по `meta.total` показывает блок `totalDefault` в [GET /v1/me](./keys-auth/me.md): `key` — настройка ключа, `platform` — платформенное умолчание, `effective` — что получится, если запрос не передаст `withTotal`. ## Преобразование полей Вайбкод автоматически преобразует имена полей при отправке запроса. В запросах всегда используйте camelCase: ```json { "title": "Сделка", "stageId": "NEW", "assignedById": 1 } ``` В ответах объявленные поля сущностей приходят в camelCase — `id`, `title`, `stageId`, `responsibleId`. Пользовательские поля портала — отдельный случай. Их состав зависит от портала, заранее они не описаны, а часть полей носит имя, сгенерированное самим Битрикс24. Имя, под которым такое поле принимается в запросе и приходит в ответе, берите из схемы `GET /v1/{entity}/fields` — написание различается по сущностям. Имена и форматы значений собраны в разделе [Пользовательские поля (UF)](#пользовательские-поля-uf). Отличается не только регистр — у части полей отличается само имя. Например, сумма сделки в Вайбкод называется `amount`, а исходное имя этого поля в Битрикс24 — `opportunity`. Имя Вайбкод стоит в колонке «Поле» схемы `GET /v1/{entity}/fields`, исходное имя Битрикс24 — в колонке «Битрикс24». В запросах и при чтении ответа используйте имя из колонки «Поле» — под ним поле и приходит в ответе, исходное имя Битрикс24 не возвращается. Список соответствий для каждой сущности — на её странице полей, например [Поля сделки](./entities/deals/fields.md). ## Часовой пояс на записи Дата-время, записанное без пояса (`2026-07-15T13:00:00`), Битрикс24 читает в поясе того аккаунта, через который платформа пишет на портал, — а не в вашем. Клиент из Берлина, отправивший `13:00`, получал сохранённые `10:00` по Гринвичу вместо `11:00`: разница в час летом и в два зимой. Чтобы этого не было, объявите свой пояс заголовком запроса: ``` X-Vibe-Timezone: Europe/Berlin ``` Значение — имя пояса из базы IANA. В браузере оно берётся из `Intl.DateTimeFormat().resolvedOptions().timeZone`, серверная интеграция подставляет пояс, в котором ведёт свои данные. **Заголовок необязателен и ничего не ломает.** Без него, с неизвестным именем пояса или с мусором вместо имени поведение остаётся прежним — значение уходит на портал как есть. Отказа не будет: заголовок добавлен так, чтобы ни один существующий вызов не изменил поведения молча. **Смещение получает только запись вида `ГГГГ-ММ-ДДTЧЧ:ММ`, где пояс не указан, и только в тех полях, где заголовок действует.** Секунды и доли секунды не обязательны и на подстановку не влияют, а перечень полей — ниже. Остальные формы даты-времени уходят на портал без изменений, и заголовок на них не действует: | Что отправлено | Что уходит на портал | |---|---| | `2026-09-15T13:00:00` | `2026-09-15T13:00:00+02:00` — смещение подставлено | | `2026-09-15T13:00`, `2026-09-15T13:00:00.500` | смещение подставлено так же — без секунд и с долями секунды | | `2026-09-15T13:00:00Z` или со смещением | как есть — пояс объявлен вами, платформа его не переписывает | | `2026-09-15 13:00:00` через пробел | как есть — читается в поясе портального аккаунта | | `15.09.2026 13:00` в местной форме | как есть — читается в поясе портального аккаунта | Две последние формы отказа не вызывают: ответ приходит успешным, а сохранённое время отличается на разницу между вашим поясом и поясом портала. Для заголовка `Europe/Berlin` и портала в поясе UTC+3 запись `2026-09-15T13:00:00` сохраняется как `2026-09-15T11:00:00Z`, а те же 13:00 через пробел — как `2026-09-15T10:00:00Z`. **Переход на летнее время учитывается по каждому значению отдельно.** Смещение берётся то, которое действовало в поясе на саму дату из значения, а не на момент запроса. Одна и та же интеграция, записывающая июльскую и январскую даты в одном запросе, получит корректные обе. **Пояс подставляется не всем полям подряд, а только проверенным.** Битрикс24 объявляет частью полей тип «дата и время», а хранит в них голую дату — подставленное смещение сдвинуло бы у такого поля день. Поэтому список полей открывается по мере живой проверки каждого. Сегодня в нём поля задачи: `deadline`, `startDatePlan`, `endDatePlan`, а также служебные `createdDate`, `changedDate`, `closedDate` — значение вида `2019-05-15T13:47:00` получает у них смещение вашего пояса, а не читается в поясе владельца ключа. Где заголовок действует, видно по машинному описанию API — у операции он объявлен в списке параметров. Отдельно стоят [события календаря](./entities/calendar-events.md): у них пояс задаётся собственными параметрами запроса (`timezoneFrom` / `timezoneTo`), поэтому заголовок для них игнорируется — иначе событие сдвинулось бы дважды. **Заголовок влияет только на запись.** На фильтр он не действует — значения фильтра читаются в поясе портального аккаунта независимо от заголовка. Что из этого следует для поиска по датам и как пересчитать границы — [Часовой пояс в значении фильтра](./filtering.md#часовой-пояс-в-значении-фильтра). ## Мультиполя (email, телефон, сайт) Контактные поля `email`, `phone` и `web` хранят несколько значений с типами. Набор зависит от сущности — `email` и `phone` есть у контактов, компаний и лидов, `web` только у компаний. Формат отличается на запись и на чтение. **На запись** — массив объектов `[{ "value": "petrov@example.com", "typeId": "WORK" }]`. Также принимается одиночная строка `"petrov@example.com"` и массив строк. Значение `typeId` зависит от поля — `WORK` / `HOME` / `MOBILE` / `OTHER` для телефона, `WORK` / `HOME` / `MAILING` / `OTHER` для email. По умолчанию `WORK`. ```json { "email": [{ "value": "petrov@example.com", "typeId": "WORK" }] } ``` Форма с ключами `VALUE` и `VALUE_TYPE` в верхнем регистре не принимается — `400 INVALID_MULTIFIELD_SHAPE`. Используйте camelCase `value` и `typeId`. **На чтение** — первичное значение приходит строкой (`"email": "petrov@example.com"`), а полный набор значений с типами лежит в массиве `fm`. Значения по типам доступны в отдельных полях (`emailWork`, `phoneMobile`). Точный набор `typeId` и полей чтения для каждой сущности — на её странице, например [Контакты](./entities/contacts.md) и [Компании](./entities/companies.md). ## Пользовательские поля (UF) Пользовательские поля портала читаются и записываются наравне с объявленными полями сущности — отдельного эндпоинта для значений нет. Создание, изменение и удаление самих полей — в разделе [Пользовательские поля](./userfields.md). ### Имя поля Рабочее имя одно — то, под которым поле стоит в схеме `GET /v1/{entity}/fields`. Под этим именем поле принимается в теле запроса, в `filter` и в `select`, под ним же оно приходит в ответе. Написание различается по сущностям, и вывести его из имени, заданного при создании, нельзя: | Сущность | Примеры имён в схеме | |----------|----------------------| | Сделки, лиды, контакты, компании, предложения | `ufCrmProjectCode`, `ufCrm_1729594209` | | Элементы смарт-процессов | `ufCrm3_1628508847` | | Реквизиты | `UF_CRM_1698325419` | | Сотрудники | `UF_USR_1619099890455`, `UF_PHONE_INNER` | Список определений полей и схема сущности называют одно и то же поле по-разному. Поле, созданное на сделках как `fieldName: "PROJECT_CODE"`, стоит в ответе `GET /v1/userfields/deals` под именем `UF_CRM_PROJECT_CODE`, а в схеме сделки и во всех запросах — под именем `ufCrmProjectCode`. **Имя, которого нет в схеме, не даёт ошибки при записи.** У сделок, лидов, контактов, компаний, предложений и элементов смарт-процессов значение, отправленное под именем `UF_CRM_PROJECT_CODE` вместо `ufCrmProjectCode`, не сохраняется: ответ приходит с кодом `200` или `201`, а поле остаётся пустым. В `select` такое имя не добавляет поле в ответ, в агрегации — на него приходит `400 INVALID_PARAMS` со списком доступных полей. Поведение отбора — [Неизвестное имя поля в фильтре](./filtering.md#неизвестное-имя-поля-в-фильтре). ### Формат значения по типам Тип поля задаётся при создании параметром `userTypeId` и приходит в схеме сущности в поле `type`. Примеры ниже сняты на портале в поясе UTC+3. | Тип | Что отправлять | Что приходит в ответе | |-----|----------------|----------------------| | `string` | `"Договор №17"` | Та же строка | | `integer` | `42` или `"15"` | Число. Дробное значение обрезается до целого — `3.7` сохраняется как `3` | | `double` | `3.14` или `"7.25"` | Число, округлённое до числа знаков после запятой, заданного настройкой `PRECISION` этого поля. При `PRECISION` равном `2` значение `3.14159` приходит как `3.14`. Поле, созданное без `settings`, получает `PRECISION` равный `0` и хранит целые: `3.14` приходит как `3`, а `3.99` — как `4` | | `boolean` | `true`, `false`, `"Y"`, `"N"`. Значения `1`, `0`, `"1"` и `"0"` сохраняются как отрицательное значение — `false` у сделок, `"N"` у остальных | У сделок — `true` или `false`. У контактов, лидов, компаний, предложений и элементов смарт-процессов — строки `"Y"` и `"N"` | | `enumeration` | Идентификатор варианта — `"3821"`. Варианты поля перечислены в массиве `items` схемы сущности | Идентификатор числом — `3821`. Текст варианта вместо идентификатора сохраняется как `0` | | `datetime` | `"2026-08-10T12:30:00"` — время читается в поясе портала. Смещение можно указать явно | У сделок — момент времени по Гринвичу, `"2026-08-10T09:30:00.000Z"`. У контактов, лидов, компаний, предложений и элементов смарт-процессов — то же время со смещением портала, `"2026-08-10T12:30:00+03:00"` | | `date` | `"2026-08-10"` | Полный момент времени со смещением портала — `"2026-08-10T03:00:00+03:00"` | | `money` | `"100\|USD"` — сумма и код валюты через вертикальную черту. Значение без кода валюты сохраняется в базовой валюте портала | `"100\|USD"`. Отправленное `100` приходит как `"100\|RUB"`, `"250.50\|RUB"` — как `"250.5\|RUB"` | | `url` | `"https://example.com/contract"` | Та же строка | | `address` | `"Москва, Тверская 1\|55.7601;37.6055"` — адрес и координаты разделяет вертикальная черта, широту и долготу — знак `;` | Та же строка. Широта и долгота, разделённые вертикальной чертой вместо `;`, не сохраняются | | `employee` | `1` — идентификатор сотрудника, список: `GET /v1/users` | `1` | | `crm` | `"L_1000739"` — буквенный префикс типа и идентификатор записи: `L_` лид, `C_` контакт | Та же строка | | `crm_status` | `"NEW"` — значение `statusId`, список: `GET /v1/statuses` | Та же строка | | `file` | `["contract.pdf", "BASE64_CONTENT"]` — имя файла и содержимое в Base64 | У поля с одним значением — объект с полями `id`, `url`, `urlMachine`, у множественного — массив таких объектов. Подробнее — [Файлы в CRM](./recipes/crm-files.md) | Настройка `PRECISION` задаётся при создании поля — `"settings": { "PRECISION": 2 }`, см. [Создать поле](./userfields/crm/create.md). Заголовок `X-Vibe-Timezone` из раздела [Часовой пояс на записи](#часовой-пояс-на-записи) на пользовательские поля не действует: значение без смещения читается в поясе портала. Значения типов `employee`, `crm` и `crm_status` сохраняются без сверки со справочником портала: идентификатор несуществующего сотрудника или значение вне справочника принимаются и возвращаются как есть. Проверяйте их на своей стороне. ### Несколько значений в одном поле Признак множественности приходит в списке определений полей — поле `multiple` со значением `Y` или `N`. Для сделок, лидов, контактов, компаний, предложений и реквизитов это `GET /v1/userfields/:entity`, для смарт-процессов — `GET /v1/items/:entityTypeId/userfields`. У пользовательского поля в схеме `GET /v1/{entity}/fields` этого признака нет. Значение множественного поля передаётся массивом и заменяет прежний набор целиком: ```json { "ufCrmProjectTags": ["первое", "второе"] } ``` Одиночное значение вместо массива не сохраняется. Пустой массив и `null` оставляют прежние значения — очистить множественное поле пустым массивом или `null` нельзя. ### Очистка значения Поле с одним значением очищается значением `null` или пустой строкой, а файловое поле с одним значением — пустым массивом. В ответе очищенное поле приходит как `null`. Множественное поле ничем из перечисленного не очищается. ## Особые сущности ### Smart Processes (Items) Смарт-процессы используют `entityTypeId` в URL: `GET /v1/items/{entityTypeId}`. ```bash # Список записей смарт-процесса с entityTypeId = 1058 curl -H "X-Api-Key: $KEY" \ "https://vibecode.bitrix24.tech/v1/items/1058?limit=10" ``` Список доступных смарт-процессов: `GET /v1/smart-processes`. ### Calendar Events Требуют обязательные параметры: `type` (user/group/company) и `ownerId`. ```bash curl -H "X-Api-Key: $KEY" \ "https://vibecode.bitrix24.tech/v1/calendar-events?type=user&ownerId=1" ``` ### Files Требуют `folderId`. Получите его из `GET /v1/storages` → поле `rootFolderId`. ## Лимиты 10 запросов/секунду — лимит Битрикс24 на уровне портала, общий для всех ключей. **Как укладываться в лимит:** - [Batch API](./batch.md) — 50 вызовов за 1 единицу лимита - `POST /v1/{entity}/batch` — до 500 записей CRUD за 10 единиц (а не за 500) - `POST /v1/{entity}/aggregate` — `count` идёт одним быстрым вызовом, а `sum`/`avg`/`min`/`max` подгружают до 5000 записей и считаются на стороне Вайбкод - Параметр `select` — загрузка только нужных полей сокращает объём ответа Подробнее: [Оптимизация](./optimization.md) — паттерны для дашбордов, массовых операций, сканирования больших объёмов ## Запись ключом в режиме «только чтение» Ключ с режимом доступа «только чтение» выполняет чтение и получает `403 WRITE_BLOCKED_READONLY_KEY` на любой вызов записи — создание, обновление, удаление, действие над сущностью. Полное описание кода и полей `details` — [Коды ошибок](./errors.md). Как переключить режим и как работает политика портала — [Режим доступа](./keys-auth/access-mode.md). ## Паттерны использования | Задача | Подход | |--------|--------| | Дашборд / аналитика | `POST /v1/{entity}/aggregate` — счётчики и суммы по фильтру | | Массовое обновление | `POST /v1/{entity}/batch` с action=update | | Данные из нескольких сущностей | `POST /v1/batch` — deals + tasks + contacts в 1 запросе | | Запись + связанные данные | `?include=company,contact` — [связанные данные](./includes.md) в одном ответе | | Сканирование десятков тысяч записей | Курсор по `id` — `order[id]=asc` плюс `filter[>id]` из `meta.nextAfterId`, см. [Листание и количество записей](#листание-и-количество-записей). Где курсора нет — `POST /v1/{entity}/search` с `limit` до 5000 и сужением фильтра | ## Смотрите также - [Связанные данные (include)](./includes.md) — загрузка связанных сущностей в одном запросе - [Фильтрация](./filtering.md) — три синтаксиса фильтров, даты, NOT-фильтры - [Batch API](./batch.md) — до 50 вызовов в одном запросе - [Все сущности](./entities-index.md) — полный список сущностей со ссылками - [Оптимизация](./optimization.md) — rate limits, паттерны производительности - [Коды ошибок](./errors.md) — справочник ошибок платформы --- # Фильтрация и поиск Три синтаксиса фильтрации для API сущностей. Все стили можно **смешивать** в одном запросе. > Фильтрация работает в двух местах: > - `GET /v1/{entity}?filter[field]=value` — параметр URL для списка > - `POST /v1/{entity}/search` — тело запроса `{ "filter": { ... } }` **Быстрый переход:** [Как передать фильтр в GET-запросе](#как-передать-фильтр-в-get-запросе) · [Фильтр по телефону и почте](#фильтр-по-телефону-и-почте) · [Логика ИЛИ](#логика-или) · [Эндпоинт поиска](#эндпоинт-поиска) · [Постраничный вывод](#постраничный-вывод) · [Коды ошибок](#коды-ошибок) ## Как передать фильтр в GET-запросе У параметра `filter` две равноправные формы записи. Выберите одну и передайте в ней весь фильтр целиком. **Скобочная запись** — каждое условие отдельным параметром URL: ```bash GET /v1/deals?filter[stageId]=NEW&filter[amount][$gte]=50000 ``` **JSON-объект** — весь фильтр одним значением. Та же форма, что в теле `POST /v1/{entity}/search`: ```bash GET /v1/deals?filter={"stageId":"NEW","amount":{"$gte":50000}} ``` Значение JSON-формы нужно закодировать для URL: ```javascript const filter = { stageId: 'NEW', amount: { $gte: 50000 } } const query = `filter=${encodeURIComponent(JSON.stringify(filter))}&limit=50` ``` Значение, которое не является ни скобочной записью, ни JSON-объектом, отклоняется с `400 INVALID_FILTER` — вместо того чтобы молча вернуть всю коллекцию. Пустое `?filter=` означает «без фильтра». > **Две формы в одном запросе смешивать нельзя.** В запросе `?filter={"id":3}&filter[amount]=5` до фильтра доходит только одна из них: разборщик строки запроса пишет обе в одно и то же место, и вторая замещает первую. Ответ при этом выглядит корректно отфильтрованным, хотя половина условий не применена, поэтому такой запрос отклоняется с `400 INVALID_FILTER`. ## Синтаксис 1: операторы со знаком `$` Операторы с префиксом `$` внутри объекта поля. ```json { "filter": { "amount": { "$gte": 50000 }, "stageId": { "$ne": "LOST" }, "createdAt": { "$gte": "2026-01-01T00:00:00" } } } ``` Найдёт записи с суммой от 50 000, стадией, отличной от LOST, созданные с начала 2026 года. ### Доступные операторы | Оператор | Значение | Пример | |----------|---------|--------| | `$gt` | > (больше) | `{ "amount": { "$gt": 10000 } }` | | `$gte` | >= (больше или равно) | `{ "amount": { "$gte": 50000 } }` | | `$lt` | < (меньше) | `{ "amount": { "$lt": 100000 } }` | | `$lte` | <= (меньше или равно) | `{ "amount": { "$lte": 200000 } }` | | `$ne` | != (не равно) | `{ "stageId": { "$ne": "LOST" } }` | | `$contains` | поиск по подстроке | `{ "title": { "$contains": "поставка" } }` | | `$in` | входит в массив (IN) | `{ "stageId": { "$in": ["NEW", "WON"] } }` | | `$nin` | НЕ входит в массив (NOT IN) | `{ "categoryId": { "$nin": [1, 3] } }` | Точное совпадение задаётся значением напрямую, без оператора: `{ "stageId": "NEW" }`. > **Исключить набор значений.** «Поле НЕ входит в список» задаётся оператором `$nin`: `{ "categoryId": { "$nin": [1, 3] } }` вернёт сделки всех направлений, кроме 1 и 3. Родные префиксы Битрикс24 `@` (IN) и `!@` (NOT IN) в имени поля (`{ "@categoryId": [...] }`, `{ "!@categoryId": [...] }`) НЕ поддерживаются — используйте операторы `$in` / `$nin`. ### Комбинирование Несколько условий на одном поле объединяются логикой И. Условия на разные поля — тоже логикой И. Для ИЛИ-логики см. раздел [Логика ИЛИ](#логика-или) ниже. ```json { "filter": { "amount": { "$gte": 50000, "$lte": 200000 }, "stageId": { "$ne": "LOST" } } } ``` Найдёт записи с суммой от 50 000 до 200 000 и стадией, отличной от LOST. ## Синтаксис 2: префикс в имени поля Оператор как часть имени поля. Форма, которую напрямую понимает Битрикс24. ```json { "filter": { ">=amount": 50000, "<=amount": 200000, "!stageId": "LOST" } } ``` Найдёт записи с суммой от 50 000 до 200 000 и стадией, отличной от LOST. ### Операторы | Префикс | Значение | |---------|---------| | `>=` | больше или равно | | `>` | больше | | `<=` | меньше или равно | | `<` | меньше | | `!` | не равно | | `%` | подстрока | ## Синтаксис 3: оператор как ключ объекта Оператор как ключ вложенного объекта. Та же форма, что в синтаксисе 2, но с разделением имени поля и условия. ```json { "filter": { "amount": { ">=": 50000 }, "stageId": { "!": "LOST" } } } ``` Найдёт записи с суммой от 50 000 и стадией, отличной от LOST. ## Фильтрация по дате Поля даты (`createdAt`, `updatedAt`, `closedAt`, `beginDate` и др.) принимают строки **ISO 8601**: ```json { "filter": { "createdAt": { "$gte": "2026-01-01T00:00:00" }, "closedAt": { "$lte": "2026-03-31T23:59:59" } } } ``` Найдёт записи, созданные с начала 2026 года и закрытые до конца марта. ### Примеры ```json { "filter": { ">=createdAt": "2026-03-01T00:00:00" } } ``` Найдёт записи, созданные с 1 марта 2026. ```json { "filter": { "updatedAt": { "$gte": "2026-05-01T00:00:00" } } } ``` Найдёт записи, обновлённые с указанного момента. ### Часовой пояс в значении фильтра Значения фильтра всегда читаются в поясе портального аккаунта. Битрикс24 обрабатывает фильтр по дате без учёта пояса: значение с суффиксом (`Z` или `+02:00`) он молча отбрасывает вместе со всем условием — запрос возвращает успех и всю таблицу. Поэтому платформа срезает суффикс сама, и в Битрикс24 уходит голое `ГГГГ-ММ-ДДTЧЧ:ММ:СС`. Указывать пояс в значении фильтра бессмысленно, а полагаться на него — опасно. Заголовок `X-Vibe-Timezone`, [которым клиент объявляет свой пояс](./entity-api.md#часовой-пояс-на-записи), действует **только на запись**. Значит запись `2026-07-15T13:00:00` с этим заголовком и фильтр по тому же литералу не совпадут: запись легла на портал со смещением вашего пояса, а фильтр ищет в поясе портала. Пересчитайте границы фильтра в пояс портала сами. Границы диапазона задаются операторами `$gte`/`$lte` — или эквивалентными `>=`/`<=` из синтаксисов выше. Ключи `from`/`to` в значении поля не поддерживаются и вернут `400 INVALID_FILTER_OPERATOR`: ```json { "filter": { "createdAt": { "$gte": "2026-06-01T00:00:00", "$lte": "2026-06-30T23:59:59" } } } ``` ## NOT-фильтры Исключение значений: ```json { "filter": { "stageId": { "$ne": "LOST" } } } ``` ```json { "filter": { "!stageId": "LOST" } } ``` ```json { "filter": { "stageId": { "!": "LOST" } } } ``` Все три варианта найдут записи, у которых стадия отличается от LOST. ## Фильтр по заполненности (не пусто / не null) Отобрать только записи, где поле **заполнено**, — например контакты с заполненным идентификатором налогоплательщика, чтобы не тянуть всю базу при дедупликации. Сравнение с `null` через оператор `$ne` делает эту выборку на стороне Битрикс24: ```json { "filter": { "ufCrm_taxId": { "$ne": null } } } ``` Найдёт только записи, где `ufCrm_taxId` заполнено. Эквивалентная форма — сравнение с пустой строкой `{ "$ne": "" }`. Работает и для пользовательских (UF) полей, и для стандартных (`post`, `phone`, `email` и др.). Обратное условие — «поле пусто» — задаётся точным сравнением с `null`: ```json { "filter": { "ufCrm_taxId": null } } ``` Вместе две выборки дают полное разбиение набора (заполненные + пустые = все). > **Важно для GET-запросов.** URL не умеет передавать настоящий `null` — в строке запроса он превращается в текст `"null"`, и фильтр начинает искать буквальную строку «null» (вернёт мусор). Для «не пусто» в GET передавайте **пустое значение**, а не слово `null`: > > - Правильно: `GET /v1/contacts?filter[ufCrm_taxId][$ne]=` — поле заполнено > - Неправильно: `GET /v1/contacts?filter[ufCrm_taxId][$ne]=null` — ищет текст «null», а это другое условие > > Либо используйте `POST /v1/contacts/search` с телом `{ "filter": { "ufCrm_taxId": { "$ne": null } } }` — в JSON-теле `null` передаётся корректно. ## Фильтр по телефону и почте Поля `phone` и `email` у лидов, контактов и компаний ведут себя не так, как остальные. У них две особенности, которые надо знать до того, как писать фильтр. **Значение сравнивается целиком, вместе со знаками.** Запись с номером `+7 (999) 123-45-67` найдётся только по этой же строке: ```json { "filter": { "phone": "+7 (999) 123-45-67" } } ``` Плюс, пробелы, скобки и дефисы — часть сохранённого значения. Поэтому та же запись не найдётся ни по `79991234567`, ни по `89991234567`. В каком виде номер попадёт в базу, решает портал: один и тот же телефон может лежать в ней и как `+7 (999) 123-45-67`, и как `89991234567`. Ваша программа заранее не знает, какой вид выбран, поэтому фильтр по точному значению годится только тогда, когда сохранённая строка уже известна. **У записи может быть несколько номеров, а фильтр видит только первый.** Если у контакта записаны рабочий и мобильный телефоны, фильтр найдёт его по рабочему — тому, который приходит в поле `phone` в ответе. По мобильному фильтр вернёт пустой список. ### Найти запись по номеру телефона Обе особенности снимает [Поиск дубликатов](./duplicates.md) — отдельный эндпоинт `POST /v1/duplicates/find`. Он сравнивает номера по существу, а не по написанию, и проверяет все номера записи, а не только первый: ```bash curl -X POST https://vibecode.bitrix24.tech/v1/duplicates/find \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "type": "phone", "values": ["+79991234567"] }' ``` Запросы `+7 (999) 123-45-67`, `+79991234567` и `89991234567` найдут одну и ту же запись. Номер передаётся целиком: без кода страны или без ведущей «8» он не опознаётся. В ответе приходят ID найденных лидов, контактов и компаний. ### Поиск по части значения Точное сравнение — не единственная форма. Оператор `$contains` ищет кусок текста внутри сохранённого значения, и для почты это рабочий способ: ```json { "filter": { "email": { "$contains": "@example.com" } } } ``` Найдёт записи с почтой в домене `example.com`. Для телефона результат зависит от того, где внутри сохранённого номера стоят пробелы и дефисы, и от того, первый это номер записи или нет. Поэтому запись по номеру ищут поиском дубликатов, а не оператором `$contains`. ## Логика ИЛИ Все условия в объекте `filter` объединяются логикой И. Логический оператор ИЛИ между разными полями нельзя выразить прямо в `filter` — попытка передать `LOGIC: "OR"` или `$or` возвращает `400 INVALID_FILTER_OPERATOR`. Ниже три способа получить тот же результат. ### Способ 1: `$in` — несколько значений одного поля Когда нужно «поле равно A **или** B **или** C», используйте оператор `$in` из таблицы выше: ```json { "filter": { "stageId": { "$in": ["NEW", "WON"] } } } ``` Найдёт сделки в стадии NEW или WON. Оператор работает на любом поле, для которого имеет смысл точное сравнение: `assignedById`, `categoryId`, `id`, `sourceId` и так далее. ### Способ 2: Batch — несколько фильтров одним запросом Когда условия ИЛИ затрагивают разные поля («сделки в стадии NEW **или** с суммой больше 100 000»), вынесите каждое условие в отдельный вызов внутри [Batch API](./batch.md): ```json { "calls": [ { "id": "by_stage", "entity": "deals", "action": "list", "params": { "filter": { "stageId": "NEW" }, "limit": 200 } }, { "id": "by_amount", "entity": "deals", "action": "list", "params": { "filter": { "amount": { "$gte": 100000 } }, "limit": 200 } } ] } ``` Ответ придёт в форме `data.results.by_stage` и `data.results.by_amount` — два независимых массива, которые клиент объединяет самостоятельно. ### Способ 3: параллельные запросы + клиентская склейка Когда нужен единый список без дубликатов, выполните вызовы параллельно и объедините результаты по `id`: ```js const [a, b] = await Promise.all([ fetch('/v1/deals/search', { method: 'POST', headers: { 'X-Api-Key': key, 'Content-Type': 'application/json' }, body: JSON.stringify({ filter: { stageId: 'NEW' }, limit: 200 }), }), fetch('/v1/deals/search', { method: 'POST', headers: { 'X-Api-Key': key, 'Content-Type': 'application/json' }, body: JSON.stringify({ filter: { stageId: 'WON' }, limit: 200 }), }), ]) const { data: dataA } = await a.json() const { data: dataB } = await b.json() const byId = new Map(dataA.map(d => [d.id, d])) for (const d of dataB) byId.set(d.id, d) const merged = [...byId.values()] ``` `Map` по `id` устраняет повторы, если запись попадает под оба условия. ### Чего делать нельзя ```json { "filter": { "LOGIC": "OR", "0": { "stageId": "NEW" }, "1": { "stageId": "WON" } } } ``` Ответ: ```json { "success": false, "error": { "code": "INVALID_FILTER_OPERATOR", "message": "INVALID_FILTER_OPERATOR: 'LOGIC' is not supported. OR/AND logic cannot be expressed in a single filter. For same-field OR use { field: { $in: [v1, v2] } }. For cross-field OR run parallel requests via POST /v1/batch. AND is the default — combine conditions as sibling keys in one filter object." } } ``` Аналогично попытка передать `$or` возвращает `400` с подсказкой использовать Batch API. ## Смешивание синтаксисов Речь идёт о стилях записи операторов внутри одного фильтра. Две формы передачи самого параметра `filter` в GET-запросе — скобочную и JSON — смешивать нельзя, см. [Как передать фильтр в GET-запросе](#как-передать-фильтр-в-get-запросе). Все три стиля можно комбинировать в одном фильтре: ```json { "filter": { "amount": { "$gte": 50000 }, "!stageId": "LOST", "createdAt": { ">=": "2026-01-01T00:00:00" } } } ``` Найдёт записи с суммой от 50 000, стадией, отличной от LOST, созданные с начала 2026 года. Здесь все три синтаксиса используются вместе. ## Эндпоинт поиска `POST /v1/{entity}/search` — полнофункциональный поиск: ```bash curl -X POST -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \ "https://vibecode.bitrix24.tech/v1/deals/search" \ -d '{ "filter": { "stageId": { "$ne": "LOST" }, "amount": { "$gte": 100000 } }, "sort": { "amount": "desc" }, "limit": 200 }' ``` | Параметр | Тип | Описание | |----------|-----|---------| | `filter` | object | Условия фильтрации | | `sort` | string, object или array | Сортировка. Принимаются три формы: строка (`"id"` / `"-amount"` / `"id,-createdAt"`), объект (`{ id: "asc", amount: "desc" }` — ключи в порядке вставки) или массив (`["id", "-amount"]`). Вместо `asc`/`desc` принимаются `1`/`-1`. Некорректный тип возвращает `400 INVALID_SORT_TYPE`, неизвестное направление — `INVALID_SORT_DIRECTION`. | | `limit` | number | Количество записей (по умолчанию 50, максимум 5000) | | `offset` | number | Пропустить N записей | | `autoWindow` | boolean | `false` — отключить разбивку по дате | ## Фильтр передан не объектом `filter` — это объект условий. Строка, число, булево значение или массив вместо него отклоняются с кодом `INVALID_FILTER_SHAPE`, и в сообщении сказано, что именно пришло. ``` POST /v1/tasks/search { "filter": [{ "responsibleId": 1 }] } → 400 INVALID_FILTER_SHAPE POST /v1/tasks/search { "filter": { "responsibleId": 1 } } → 200 ``` В строке запроса действует другое правило: условия пишутся скобочной формой (`?filter[responsibleId]=1`), а `filter`, закодированный в JSON одной строкой, разбирается и применяется — значение, которое не является ни той, ни другой формой, отклоняется с кодом `INVALID_FILTER`. Раньше такие значения молча терялись: Битрикс24 получал вызов вообще без отбора и отвечал `200` со всей коллекцией — то же самое, что и с неизвестным именем поля, только на уровне формы, а не имени. ## Неизвестное имя поля в фильтре Имя поля, которого нет у сущности, отклоняется до вызова Битрикс24 — ответ `400` с кодом `UNKNOWN_FILTER_FIELD` и списком доступных имён в сообщении. **Сверяться нужно с этим списком, а не с `GET /v1/{entity}/fields`:** тот отвечает на другой вопрос — какие поля у сущности есть, — и на части сущностей он шире, потому что дополняет схему живым ответом Битрикс24, а фильтровать по такому полю нельзя. Сверх перечисленного принимаются пользовательские поля, а у сущностей, где он объявлен, — ключ `id`. Пользовательское поле указывается тем же именем, под которым оно стоит в схеме сущности: `ufCrmProjectCode` у сделок, `UF_CRM_1698325419` у реквизитов. На другое написание того же поля у сделок, контактов и элементов смарт-процессов приходит `400 UNKNOWN_FILTER_FIELD`, а у остальных сущностей имя отбрасывается: условие не применяется и приходит вся коллекция. Формат имён и значений — [Пользовательские поля (UF)](/docs/entity-api#пользовательские-поля-uf). Исключение — реквизиты: там принимаются оба написания одного поля, `UF_CRM_1698325419` и `ufCrm_1698325419`, и отбор применяется одинаково. Раньше второе написание отбрасывалось. Написание с подчёркиванием перед буквой (`ufCrm_taxId`) остаётся неизвестным именем: Битрикс24 такого имени не даёт, вывести из него настоящее нельзя, и условие по-прежнему теряется. Проверка идёт по имени, а не по значению: операторы, диапазоны, `$in`/`$nin` и логика И работают без изменений. У смарт-процессов сверх перечисленного принимаются динамические связи `parentId`. **Почему это важно.** Битрикс24 неизвестный ключ фильтра не отклоняет, а молча выбрасывает и отвечает `200` со ВСЕЙ коллекцией. То есть опечатка в имени поля выглядела как успешный запрос с неправдоподобно большим результатом — а не как ошибка. Отказ до вызова превращает эту ситуацию в явную. **Где проверка ещё НЕ включена.** У части сущностей схема полей заведомо уже настоящего контракта Битрикс24, поэтому включать проверку нельзя — она отклонила бы работающее поле. Там поведение прежнее: неизвестное имя уходит в Битрикс24 и молча теряется. Узнать, включена ли проверка у конкретной сущности, можно одним запросом: отправьте фильтр по заведомо несуществующему имени и посмотрите на код ответа. **Отдельный случай — метод вообще без фильтра.** У нескольких сущностей метод Битрикс24 не принимает фильтр ни в каком виде (он читает только именованные аргументы). Там отклоняется любой ключ фильтра, с кодом `UNSUPPORTED_FILTER`. В сообщении перечислены параметры, которые метод принимает. ## Коды ошибок | HTTP | Код | Условие | |------|-----|---------| | 400 | `INVALID_FILTER` | Значение `filter` не является ни скобочной записью, ни JSON-объектом — либо в одном запросе смешаны обе формы (см. [Как передать фильтр в GET-запросе](#как-передать-фильтр-в-get-запросе)) | | 400 | `INVALID_FILTER_OPERATOR` | Неизвестный оператор в значении поля или попытка передать `LOGIC` / `$or` | | 400 | `INVALID_FILTER_SHAPE` | `filter` в теле запроса передан не объектом — строкой, числом или массивом | | 400 | `INVALID_FILTER_FIELD` | Имя поля начинается с родного префикса Битрикс24 `@` (IN) или `!@` (NOT IN) — используйте операторы `$in` / `$nin` | | 400 | `UNKNOWN_FILTER_FIELD` | Поле отсутствует у сущности — см. [Неизвестное имя поля в фильтре](#неизвестное-имя-поля-в-фильтре) | | 400 | `UNSUPPORTED_FILTER` | Метод Битрикс24 у этой сущности не принимает фильтр. В сообщении перечислены принимаемые параметры | | 400 | `INVALID_SORT_TYPE` | `sort` не строка, не объект и не массив | | 400 | `INVALID_SORT_DIRECTION` | Направление сортировки не `asc` / `desc` / `1` / `-1` | | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset > 0` при широком диапазоне дат (см. [Постраничный вывод](#постраничный-вывод)) | | — | `WINDOWED_SEARCH_FAILED` | Больше не возвращается: при полном отказе авто-окон возвращается реальный код Битрикс24 — `UNKNOWN_FILTER_FIELD` / `INVALID_PARAMS` / `BITRIX_ACCESS_DENIED` / `RATE_LIMITED` / `BITRIX_UNAVAILABLE` / `BITRIX_TIMEOUT` (503) | Полный список общих ошибок API — [Коды ошибок](./errors.md). ## Примеры по сущностям ### Сделки — по стадии и сумме ```json { "filter": { "stageId": "NEW", "amount": { "$gte": 100000 } }, "sort": { "createdAt": "desc" } } ``` Найдёт сделки в стадии NEW с суммой от 100 000, отсортированные по дате создания (новые первыми). ### Контакты — по телефону Телефон фильтром не ищут: он сравнивается со всей сохранённой строкой и только по первому номеру записи — см. [Фильтр по телефону и почте](#фильтр-по-телефону-и-почте). Номер ищут отдельным эндпоинтом `POST /v1/duplicates/find` — [Поиск дубликатов](./duplicates.md): ```bash curl -X POST https://vibecode.bitrix24.tech/v1/duplicates/find \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "type": "phone", "values": ["+79161234567"], "entityType": "contact" }' ``` Вернёт ID контактов с этим номером в любом его написании. ### Задачи — незакрытые ```json { "filter": { "status": { "$ne": 5 } } } ``` Найдёт все задачи со статусом, отличным от 5 (завершена). Статусы: 2 = ждёт выполнения, 3 = выполняется, 4 = ожидает контроля, 5 = завершена, 6 = отложена. ### Лиды — за период ```json { "filter": { "createdAt": { "$gte": "2026-01-01T00:00:00", "$lte": "2026-03-31T23:59:59" } } } ``` Найдёт лиды, созданные в первом квартале 2026 года. ### Календарные события ```json { "filter": { "dateFrom": { "$gte": "2026-04-01T00:00:00" } } } ``` Найдёт события с датой начала от 1 апреля 2026. Для `calendar-events` обязательны параметры `type` и `ownerId` в URL: `/v1/calendar-events?type=user&ownerId=1`. ## Фильтрация в Batch Фильтры работают и в [Batch API](./batch.md): ```json { "calls": [ { "id": "new_deals", "entity": "deals", "action": "list", "params": { "filter": { "stageId": "NEW" } } }, { "id": "search_contacts", "entity": "contacts", "action": "search", "params": { "filter": { "email": { "$contains": "@example.com" } } } } ] } ``` Одним запросом получит список сделок в стадии NEW и найдёт контакты с адресом в домене `example.com`. ## Постраничный вывод Три готовых способа — выбирайте по задаче. Для отдельного ответа границей цикла служит `meta.hasMore`, а не арифметика от `meta.total`: признак «есть ещё» выводится из полноты страницы. Само поле `meta.total` необязательное — его может не быть, если количество не заказывалось. Ни один способ не создаёт неизменяемый снимок коллекции и не обещает полный обход при изменениях данных или прав доступа. ### Получить весь результат сразу Подходит для отчётов, выгрузок и любых случаев, когда нужны все записи. Укажите `limit` до 5000 — сервис вернёт весь подходящий результат одним ответом. Одного ответа хватает не всегда. Когда поиск разбивает диапазон дат на окна, выдача упирается либо в потолок в 5000 записей, либо в размер одного чтения окна. Признак этого приходит в `meta.warnings` кодом `WINDOW_TRUNCATED` — разбор в [неполной выдаче](./optimization.md#неполная-выдача). ```js const res = await fetch('/v1/deals/search', { method: 'POST', headers: { 'X-Api-Key': key, 'Content-Type': 'application/json' }, body: JSON.stringify({ filter: { closedAt: { $gte: '2026-03-22T00:00:00Z', $lte: '2026-04-22T00:00:00Z' } }, limit: 5000, }), }) const { data, meta } = await res.json() // data — все записи; meta.hasMore говорит, осталось ли что-то за пределами limit ``` ### Идти по курсору `nextAfterId` Этот способ применим к методам, ответы которых содержат `meta.nextAfterId`, и является основным для больших обходов. Отсортируйте по `id` по возрастанию, отключите точный подсчёт через `withTotal: false` и передавайте `meta.nextAfterId` предыдущего ответа обратно в фильтр `>id`. Запрашивайте через `select` только нужные поля и обязательно включайте `id`. Курсор не зависит от смещения и не дорожает к концу коллекции. Каждый вызов читает одну короткую страницу, а прерванный обход продолжается с последнего `meta.nextAfterId`, не начиная сначала. Курсор доступен у сделок, лидов, контактов, компаний, предложений и элементов смарт-процессов. У остальных сущностей `meta.nextAfterId` в ответе нет — для них подходят два других способа. ```js let after = null while (true) { const res = await fetch('/v1/deals/search', { method: 'POST', headers: { 'X-Api-Key': key, 'Content-Type': 'application/json' }, body: JSON.stringify({ filter: { ...(after ? { '>id': after } : {}) }, sort: 'id', select: ['id', 'title'], limit: 50, withTotal: false, }), }) const { data, meta } = await res.json() for (const deal of data) process(deal) if (!meta.hasMore) break if (!meta.nextAfterId) { throw new Error('В ответе нет meta.nextAfterId при meta.hasMore=true') } after = meta.nextAfterId } ``` Внутренний запрос следует рекомендованной схеме Битрикс24: `start=-1`, `order=ID ASC`, фильтр `ID` больше последнего полученного идентификатора. Клиент не передаёт `start` в тело запроса к этому эндпоинту — у подкоманд пакета он принимается, см. [Пакетные запросы](./batch.md). Вайбкод применяет его только к методам, для которых подтверждена совместная работа фильтра по `id` и `start=-1`. Для остальных методов сервис сохраняет корректность вызова и может не применить режим без подсчёта. `withTotal: false` убирает `meta.total` и, в поддерживаемом режиме, отдельный `COUNT`. Не обходите коллекцию ради подсчёта. Если точная цифра нужна, сначала прочитайте `operations.search.paginationStability.counting` сущности в `GET /v1/guide`. Когда указание содержит путь агрегации, используйте функцию `count`. Когда указание есть, но пути нет, дешёвого точного подсчёта нет — читайте `meta.total`, только когда поле пришло, а обход ограничивайте по `meta.hasMore`. Если весь блок `counting` отсутствует вместе с общей операцией поиска, не угадывайте путь агрегации: перейдите по указателю на документацию сущности или домена из того же руководства и используйте только явно описанную операцию счёта. Обход предполагает, что записи не удаляются, а права доступа не меняются до его завершения. Если любое из условий нарушено, часть записей может быть пропущена. API Вайбкод не обещает полный обход как инвариант клиента. ### Идти по страницам вручную Подходит, когда нужно обрабатывать записи порциями (например, импорт по 50 штук с сохранением прогресса). Добавьте `autoWindow: false`, сортировку по `id` и увеличивайте `offset` на каждой итерации. `offset` считается по записям, а `meta.hasMore` учитывает уже пропущенное, поэтому цикл останавливается по нему. ```js let offset = 0 while (true) { const res = await fetch('/v1/deals/search', { method: 'POST', headers: { 'X-Api-Key': key, 'Content-Type': 'application/json' }, body: JSON.stringify({ filter: { closedAt: { $gte: '2026-03-22T00:00:00Z', $lte: '2026-04-22T00:00:00Z' } }, sort: 'id', limit: 50, offset, autoWindow: false, }), }) const { data, meta } = await res.json() if (data.length === 0) break // защита от бесконечного цикла на пустой странице for (const deal of data) process(deal) offset += data.length if (!meta.hasMore) break } ``` Пустая страница в середине обхода — отдельный случай. Когда на запрошенной позиции доступно меньше строк, чем пропускает `offset`, страница выходит пустой, хотя записи под фильтр ещё есть. Ответ тогда несёт `meta.warnings` с кодом `OFFSET_BEYOND_FETCHED_PAGE` и полем `field: "offset"`. Проверяйте этот код перед выходом из цикла: увеличьте `limit`, сузьте фильтр или перейдите на курсор. ### Чего делать нельзя Не запускайте параллельные запросы с разным `offset` на одном фильтре — сервис вернёт `400 UNSTABLE_OFFSET_PAGINATION`. Выберите один из трёх способов выше. Не обходите коллекцию постранично, чтобы узнать количество записей. Пролистать пять тысяч сделок ради цифры «4863» — это сто вызовов вместо одного. Если точная цифра нужна, используйте функцию `count` только по пути, явно указанному в `operations.search.paginationStability.counting`. Когда весь блок отсутствует вместе с общей операцией поиска, следуйте указателю на документацию сущности или домена из `GET /v1/guide` и не угадывайте путь. ## Смотрите также - [Обзор API](./entity-api.md) - [Поиск дубликатов](./duplicates.md) - [Связанные данные](./includes.md) - [Batch API](./batch.md) - [Все сущности](./entities-index.md) - [Коды ошибок](./errors.md) --- # Коды ошибок Справочник кодов ошибок API Вайбкод: единый формат ответа, перечень кодов, типичные причины и способы устранения. Применяется ко всем эндпоинтам `/v1/...`. ## Формат ответа при ошибке Каждый ответ с ошибкой возвращается в едином виде. `error` — объект. ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|----------| | `success` | boolean | да | При ошибке всегда `false` | | `error.code` | string | да | Машиночитаемый код ошибки. Используйте для различения типов ошибок в коде клиента | | `error.message` | string | да | Описание ошибки для разработчика. Язык заранее не известен и зависит от источника: технические сообщения платформы приходят на английском, сообщения от Битрикс24 — на языке портала, сообщения о сбоях облачного провайдера локализуются под язык пользователя. Не разбирайте текст и не полагайтесь на его язык — ветвитесь по `error.code` | | `error.hint` | string \| object | нет | Подсказка для разработчика: что попробовать дальше, на какие пределы обратить внимание. Строка с текстом либо, на эндпоинтах создания инфраструктуры `POST /v1/infra/servers`, объект с полями `reason`, `recovery` и `example` — в `example` готовое тело запроса для исправления | | `error.userMessage` | string | нет | Сообщение для конечного пользователя на русском языке. Появляется в биллинговых, инфраструктурных и тарифных ошибках, при перегрузке очереди портала и в отказах лимитера рабочего времени портала | | `error.details` | object | нет | Машиночитаемый контекст отдельных кодов. Примеры: `reason` в `INVALID_STATE`, `deployableKeys` в `INFRA_FORBIDDEN_FOR_COWORK_KEY`, `upgradeUrl` в отказах по подписке, `method` и `switchUrl` в `WRITE_BLOCKED_READONLY_KEY`. Набор полей зависит от кода — читайте его описание | | `error.warning` | string | нет | Появляется при повторяющихся одинаковых ошибках на одном ключе — вероятный признак ошибки в коде клиента. Счётчик эвристический, поэтому предупреждение не гарантирует наличие ошибки | | `error.retryAfter` | number | нет | Секунды до следующей попытки. Появляется в `429` (rate-limit, очередь портала — `QUEUE_OVERFLOW`/`QUEUE_TIMEOUT`, лимитер рабочего времени портала — `OPERATION_TIME_LIMIT`) и в транзиентных `503` (`BITRIX_TIMEOUT`, `POOL_EXHAUSTED`, `DB_TRANSIENT`, `SERVICE_UNAVAILABLE`). У `LARGE_BODY_BACKEND_BUSY` поле приходит не на всех путях отказа — там берите срок из заголовка `Retry-After` | | `error.b24Code` | string | нет | Машиночитаемый код причины от Битрикс24 в ответах `422 BITRIX_ERROR`. Приходит не всегда — только когда Битрикс24 прислал отдельный код | | `error.release` | string | нет | Идентификатор обновления Битрикс24, которого ждёт портал: имя модуля и номер версии одной строкой, например `imopenlines 26.700.0`. Приходит только в [`METHOD_NOT_YET_AVAILABLE`](#method_not_yet_available-422) | | `error.scope` | string | нет | Радиус отказа по лимиту: `"apiKey"` — приостановлен только вызывающий ключ, `"portal"` — пауза действует на весь портал Битрикс24 и её видят все его ключи. Появляется в [`OPERATION_TIME_LIMIT`](#operation_time_limit-429) (`"apiKey"`), [`TIMEOUT_QUARANTINE`](#timeout_quarantine-429) (`"portal"`) и [`FEEDBACK_QUOTA_EXCEEDED`](./feedback/submit.md) (оба значения). Различает «чинить свой код» и «ждать вместе с порталом» | Пример ответа с дополнительными полями (`429 RATE_LIMITED`): ```json { "success": false, "error": { "code": "RATE_LIMITED", "message": "QUERY_LIMIT_EXCEEDED", "hint": "Wait 1-2 seconds and retry. Use POST /v1/batch to combine up to 50 calls in 1 request.", "retryAfter": 2 } } ``` HTTP-заголовок `Retry-After` дублирует значение `error.retryAfter` для совместимости со стандартом HTTP. Есть отказы, где поле в теле не приходит, а заголовок — приходит, поэтому опирайтесь на заголовок. ## Сводная таблица кодов Таблица покрывает основные коды, которые встречаются на любом эндпоинте API Вайбкод. Доменные коды (`BOT_NOT_FOUND`, `SERVER_NOT_RUNNING`, `AGENT_LIMIT_REACHED` и подобные) описаны на страницах соответствующих разделов. ### Авторизация и ключи | Код | HTTP | Когда возникает | |-----|------|-----------------| | `MISSING_API_KEY` | 401 | Запрос без заголовка `X-Api-Key` | | `INVALID_API_KEY` | 401 | Ключ не найден в системе или формат не распознан | | `INVALID_APP_KEY` | 401 | Передан `vibe_app_*`, но без сопровождающего `Authorization: Bearer ...` | | `WRONG_AUTH_SCHEME` | 401 | API-ключ передан в заголовке `Authorization: Bearer`. Ключ OAuth-приложения (`vibe_app_*`) передаётся в `X-Api-Key`, а `Authorization: Bearer` несёт сессионный токен (`vibe_session_*`). Клиенту, который умеет только Bearer, используйте личный ключ (`vibe_api_*`) — он принимается в `Authorization: Bearer` | | `TOKEN_EXPIRED` | 401 | Срок действия OAuth-токена истёк | | `TOKEN_REFRESH_FAILED` | 401 | Не удалось обновить OAuth-токен на стороне Битрикс24 | | `WRONG_KEY_TYPE` | 401 | Тип ключа не подходит к эндпоинту: например, management-ключ на entity-маршруте | | `WRONG_KEY` | 403 | Сервер существует, но привязан к другому API-ключу. Операции над содержимым приложения — [выкладка](./infra/deploy/deploy.md), [команда](./infra/deploy/exec.md), [загрузка файла](./infra/deploy/upload.md) и [чтение логов](./infra/deploy/logs.md) — принимают либо управляющий ключ сервера, либо ключ, приложение которого привязано к этому серверу. Управление машиной, токены доступа и загрузка значка требуют управляющего ключа. В ответе — `hint` с восстановлением из двух шагов: перепривязать сервер в кабинете и сменить ключ, которым обращается клиент. Подробнее — [восстановление доступа](./infra/server-access-recovery.md) | | `TOKEN_MISSING` | 401 | У ключа нет кредов Битрикс24. Для личного ключа (`vibe_api_*`) — нет вебхука портала, причина приходит в `error.details`. Для ключа приложения (`vibe_app_*`) — не передан `Authorization: Bearer` с токеном сессии | | `SESSION_REQUIRED` | 401 | Операция с [местами встраивания](./apps/placements.md) выполнена без заголовка `Authorization: Bearer` с токеном сессии там, где аккаунт его требует | | `SESSION_APP_MISMATCH` | 403 | Сессия в `Authorization: Bearer` выписана другому приложению или другому аккаунту Битрикс24, чем ключ в `X-Api-Key`. Передайте ключ авторизации того приложения, которое выписало сессию через [`POST /v1/oauth/token`](./keys-auth/oauth.md) | | `PERSONAL_KEY_WEBHOOK_SCOPES_INVALID` | 400 | Выписка или обновление ключа портала, где `placement` и `entity` запрошены, а кроме них в наборе прав ничего нет. Ключ портала стоит на входящем вебхуке Битрикс24, а такие права вебхук не несёт — добавьте право на данные либо заведите OAuth-приложение. Приходит на создании и обновлении ключа, подробнее — [менеджмент-ключи](./management-keys.md) | | `ACCOUNT_PENDING_ERASURE` | 503 | Аккаунт владельца ключа ждёт удаления данных — на это время ключ заморожен. В ответе заголовок `Retry-After: 3600`. Действует на любой ключ владельца, включая [менеджмент-ключ](./management-keys.md). Отмена запроса на удаление возвращает ключу работу, перевыпускать его не нужно | ### Состояние аккаунта Битрикс24 Состояние аккаунта, к которому привязан ключ, проверяется на каждом вызове. Отказы этой группы не привязаны к эндпоинту: пока аккаунт в одном из перечисленных состояний, ключ получает их на маршрутах `/v1/...`, у которых нет собственного отказа для этого состояния, и повтор запроса ничего не меняет. | Код | HTTP | Когда возникает | |-----|------|-----------------| | `PORTAL_SUSPENDED` | 403 | Аккаунт приостановлен | | `PORTAL_DELETED` | 403 | Аккаунт удалён | | `PORTAL_BLOCKED` | 403 | Аккаунт заблокирован. Рядом с кодом приходит `blockedAt` — момент блокировки в формате ISO 8601. Причину блокировки ответ не раскрывает | | `NO_PORTAL` | 401 | Ключ не привязан ни к одному аккаунту. Исключение — маршруты [хранилища](./storage.md): непривязанный ключ получает там `403 STORAGE_REQUIRES_PORTAL_BINDING`. Тот же код с HTTP `500` приходит на маршрутах [авторизации пользователей приложения](./keys-auth/oauth.md) и означает там другое — приложение не связано с аккаунтом | ### Авторизация пользователей приложения (OAuth) | Код | HTTP | Когда возникает | |-----|------|-----------------| | `INVALID_REDIRECT_URI` | 400 | `redirect_uri` не зарегистрирован у приложения на входе `GET /v1/oauth/authorize` | | `INVALID_STATE` | 400 | `state` не найден или истёк за 20 минут на приёме ответа Битрикс24. В `error.details.reason` — `NOT_FOUND` или `EXPIRED` | | `INVALID_CODE` | 400 | Код авторизации не найден или принадлежит другому приложению | | `CODE_EXPIRED` | 400 | Срок действия кода авторизации прошёл — 5 минут | | `CODE_ALREADY_USED` | 400 | Код авторизации уже обменян на токен сессии | | `REDIRECT_URI_MISMATCH` | 400 | `redirect_uri` при обмене кода не совпадает с переданным на входе | | `DOMAIN_MISMATCH` | 400 | `domain` в `POST /v1/oauth/placement-session` не совпадает с порталом приложения | | `USER_AUTH_REQUIRED` | 401 | Токен пользователя Битрикс24 не подтвердил авторизацию на портале | | `MISSING_TOKEN` | 400 | `POST /v1/oauth/revoke` без заголовка `Authorization: Bearer` с токеном сессии | Отказ на приёме возврата может прийти не кодом, а параметром `?error=` в адресе `redirect_uri` — `token_exchange_failed`, `invalid_domain` или `profile_fetch_failed`. Полное описание потока — [Авторизация пользователей приложения](./keys-auth/oauth.md). ### Права и скоупы | Код | HTTP | Когда возникает | |-----|------|-----------------| | `SCOPE_DENIED` | 403 | У ключа нет нужного скоупа (например, `crm` для сделок, `imbot` для ботов) | | `WRITE_BLOCKED_READONLY_KEY` | 403 | У ключа задан режим «только чтение», а вызов выполняет запись | | `INFRA_FORBIDDEN_FOR_COWORK_KEY` | 403 | Ключ подписки Cowork (`vibe:cowork`) — только data-plane: запрещены provision / deploy / exec / upload / lifecycle сервера и публикация в каталог. Используйте проектный ключ с правами на деплой. В `error.details.deployableKeys` ответ перечисляет ваши другие активные ключи с правом деплоя (name / prefix / suffix, до 5) | | `INFRA_SCOPE_REQUIRED` | 403 | У ключа нет скоупа `vibe:infra` — управление инфраструктурой недоступно. Добавьте скоуп или используйте ключ с правами на инфраструктуру | | `KEY_POLICY_READONLY_REQUIRED` | 403 | Политика портала разрешает обычным пользователям создавать только ключи с режимом «только чтение» — выпуск ключа с записью отклонён | | `MANAGEMENT_KEY_READ_ONLY` | 403 | Management-ключ без прав на запись пытается выполнить `POST/PATCH/DELETE` | | `MANAGEMENT_KEY_NO_ENTITY_ACCESS` | 403 | Management-ключ обращается к entity-эндпоинту — нужен APP-ключ с нужным скоупом | | `BITRIX_ACCESS_DENIED` | 403 | Битрикс24 ответил `ACCESS_DENIED`: у пользователя нет прав на операцию или сущность | | `OAUTH_REQUIRED` | 403 | Эндпоинт требует пользовательский контекст — нужен ключ типа `vibe_app_*` + Bearer-токен | | `WAITLIST_PENDING` | 403 | Аккаунт ожидает активации в waitlist | | `OAUTH_SCOPE_CHANGE_REQUIRES_REISSUE` | 403 | Попытка добавить право Битрикс24 к OAuth-app-ключу (`vibe_app_*`) через `PATCH /v1/keys/:id` или к приложению через `PATCH /v1/apps/:id`. Права OAuth-приложения фиксируются при выпуске — снятие прав работает, а для нового права создайте приложение заново с нужным набором и пройдите авторизацию заново: перевыпуск ключа права не выдаёт | | `OAUTH_APP_REQUIRED` | 400 | Операция с [местами встраивания](./apps/placements.md) выполнена личным ключом `vibe_api_*`. Привязка, отвязка и список привязанных мест доступны только ключу авторизации приложения `vibe_app_*` | | `PLACEMENT_SCOPE_MISSING` | 403 | У ключа нет скоупа `placement` — [привязка и отвязка мест встраивания](./apps/placements.md) недоступны | | `SESSION_REQUIRES_ADMIN` | 403 | Привязка места встраивания на коробочном аккаунте выполняется под учётной записью без прав администратора аккаунта | | `B24_EMBEDDING_APP_NOT_FOUND` | 404 | Битрикс24 не знает идентификатор приложения: локальное приложение на аккаунте удалили или переустановили. Создайте локальное приложение заново и вызовите `POST /v1/apps/:id/relink-oauth` с новыми `bitrixClientId` и `bitrixClientSecret`. Не путать с `APP_NOT_FOUND` — тот про связку ключа и приложения на стороне платформы Вайбкод | | `B24_EMBEDDING_INSTALL_DENIED` | 403 | Битрикс24 отказал в установке встройки при действующей подписке: у пользователя, чьим ключом разработчика идёт вызов, нет права ставить локальные приложения и/или нет доступа к самому приложению. Подписка считается действующей в двух случаях — её подтвердил Битрикс24 либо проверку выполнить не удалось, а аккаунт уже числится подписанным в Вайбкод. Если действующей подписки нет ни по одному из источников, тот же отказ приходит как `502` | | `APP_NOT_REGISTERED` | 400 | У приложения нет идентификатора приложения Битрикс24 — [привязать или отвязать место встраивания](./apps/placements.md) нельзя | | `BOX_NO_DEVELOPER_KEY` | 400 | У автора приложения не настроен ключ разработчика — операция с местами встраивания на коробочном аккаунте недоступна | | `OAUTH_APP_KEY_CANNOT_RELINK` | 403 | `POST /v1/apps/:id/relink-oauth` вызван ключом самого OAuth-приложения (`vibe_app_*`). Перепривязывать учётные данные приложения таким ключом нельзя — используйте личный ключ (`vibe_api_*`) или кабинет | ### Валидация запроса | Код | HTTP | Когда возникает | |-----|------|-----------------| | `VALIDATION_ERROR` | 400 | Тело или query не прошли проверку схемы. `message` содержит подробности по полям | | `INVALID_JSON_BODY` | 400 | Тело запроса не разбирается как JSON. Приходит до проверки схемы, поэтому полей в `message` нет. Этот код возвращают маршруты сущностей `/v1/<сущность>`, а также `/v1/apps`, `/v1/bots`, `/v1/keys`, `/v1/note`, все операции сервера `/v1/infra/servers/:id`, `/v1/infra/runtimes`, маршруты пользовательских полей, чатов `/v1/chats/*` и открытых линий `/v1/openlines/*` | | `FST_ERR_CTP_INVALID_JSON_BODY` | 400 | Тот же случай — тело не разбирается как JSON — на остальных маршрутах: [`POST /v1/search`](./search/run.md), [`POST /v1/research`](./search/research.md), [`POST /v1/batch`](./batch.md) и прочих | | `fst_err_ctp_invalid_json_body` | 400 | Тот же случай на OpenAI-совместимых маршрутах [AI Router](./ai.md) — `/v1/ai/`, `/v1/chat/`, `/v1/models`, `/v1/audio/`. На них коды приводятся к нижнему регистру, а ответ идёт в OpenAI-конверте: `error.type`, `error.code`, без поля `success` | | `INVALID_PARAMS` | 400 | Битрикс24 вернул `INVALID_PARAMS` или route-handler нашёл некорректное значение параметра | | `INVALID_REQUEST` | 400 | Структура запроса не соответствует требуемой — например, `calls` в `/v1/batch` пустой массив или содержит больше 50 элементов, [создание сервера](./infra/servers/create.md) без обязательных полей, не-объект вместо тела на маршрутах пользовательских полей | | `MISSING_PARAMS` | 400 | Не передан обязательный параметр, явно перечисленный в схеме эндпоинта | | `MISSING_REQUIRED_FILTER` | 400 | Не передан обязательный фильтр для list-эндпоинтов, требующих контекста: `timelines` (`entityType` + `entityId`), `catalog-products` и `catalog-sections` (`iblockId`), `catalog-product-property-enums` (`propertyId`). Он же приходит на [агрегацию дел](./entities/activities/aggregate.md) без сужающего фильтра — там достаточно одного сужения из нескольких, и `message` их перечисляет | | `MISSING_REQUIRED_PARAMS` | 400 | Не переданы обязательные параметры контекста для поиска или списка вложенных данных: `files` требует `folderId`, `folders` — `parentId`, `calendar-events` — `type` и `ownerId`. `message` перечисляет недостающие поля | | `MISSING_REQUIRED_FIELDS` | 400 | Не передано поле тела, объявленное обязательным при создании сущности. `message` называет недостающее поле | | `MISSING_FIELD` | 400 | Создание [пользовательского поля](./userfields.md) без `userTypeId`. `message` приводит примеры допустимых типов | | `EMPTY_CREATE_BODY` | 400 | Тело запроса на создание пустое — не передано ни одного поля | | `EMPTY_UPDATE_BODY` | 400 | Тело запроса на обновление пустое — не передано ни одного поля | | `INVALID_FILTER_FIELD` | 400 | Имя поля фильтра начинается с родного префикса Битрикс24 `@` (IN) или `!@` (NOT IN) — используйте операторы `$in` / `$nin` | | `UNKNOWN_FILTER_FIELD` | 400 | Фильтрация по полю, которого нет в схеме сущности (для сущностей с полной схемой полей). Когда поле отклонил валидатор Вайбкод, `message` перечисляет допустимые имена после слова `Available`. Когда поле отклонил Битрикс24, список полей приходит в `error.hint` | | `UNKNOWN_SELECT_FIELD` | 400 | Отбор полей `select` по имени, которого нет в схеме событий календаря — единственной сущности, где незнакомое имя отклоняется. `message` перечисляет допустимые имена после слова `Available`. На остальных сущностях запрос выполняется, а имя перечисляется предупреждением в `meta.warnings`. Рядом со значением `*` незнакомое имя тоже не отклоняется — приходит предупреждение | | `UNKNOWN_SORT_FIELD` | 400 | Сортировка по несуществующему полю (для сущностей, у которых валидатор сортировки активен) | | `BATCH_LIMIT_EXCEEDED` | 400 | Запрос содержит больше 50 элементов в массивной операции (vipchats, task-comments и подобные) | | `MESSAGE_REQUIRED` | 400 | `POST /v1/chats/{dialogId}/messages` без текста: поле `message` пустое и нет блока `attach`. Частая причина — текст передан под неизвестным именем поля, например `text`. Ответ перечисляет нераспознанные поля | | `INVALID_EVENT` | 400 | Код события подписки портала не соответствует формату `^[A-Z][A-Z0-9_]+$`. См. [Подписки на события портала](./infra/event-subscriptions.md) | | `INVALID_APP_PATH` | 400 | Путь доставки `appPath` не начинается с `/` либо содержит управляющие символы. См. [Подписки на события портала](./infra/event-subscriptions.md) | | `PLATFORM_HANDLER_UNRESOLVABLE` | 400 | Адрес обработчика указывает на технический адрес сервера приложения, а платформенный обработчик определить не удалось. Место встраивания не зарегистрировано. См. [Привязать место](./apps/placements/bind.md) | Пустое тело с заголовком `Content-Type: application/json` принимается как `{}` на маршрутах `/v1/infra/*`, а также на **всех** маршрутах пользовательских полей: `/v1/userfields/:entity`, `/v1/userfields/:entity/types` и `/v1/userfields/:entity/:id`, те же три пути под `/v1/items/:entityTypeId/userfields`, а также короткие адреса счетов `/v1/userfields/invoices`, `/v1/userfields/invoices/types` и `/v1/userfields/invoices/:id`. Операции, которым тело не нужно — [`POST /v1/infra/servers/:id/wake`](./infra/lifecycle/wake.md), [`DELETE /v1/infra/servers/:id/access-tokens/:tokenId`](./infra/access-tokens.md) и подобные, — отвечают по существу, а не отклоняют запрос на разборе тела. Так ведут себя клиенты, которые ставят этот заголовок на любой запрос (например, axios и PowerShell `Invoke-RestMethod`). Дальше запрос проверяет сама операция, и код отказа зависит от маршрута — берите его из таблицы выше или со страницы нужной операции. Тело, которое не разбирается как JSON, на этих маршрутах отклоняется кодом `INVALID_JSON_BODY`, то есть пустое и битое тело различаются. ### Размер тела запроса | Код | HTTP | Когда возникает | |-----|------|-----------------| | `PAYLOAD_TOO_LARGE` | 413 | Тело запроса больше потолка этого маршрута | | `LARGE_BODY_BACKEND_BUSY` | 429 | Платформа уже обрабатывает предельное число крупных тел. Запрос не выполнялся, повторите его через `Retry-After` секунд | Потолок зависит от маршрута. По умолчанию — 1 МБ. Создание и обновление записей, файлы ботов и чатов, `note.file.add` — 40 МиБ. Загрузка на Диск — 70 МБ. Файл внутри тела едет в base64 и растёт примерно на треть, поэтому исходный файл при потолке 40 МиБ — чуть меньше 30 МиБ. Тот же код приходит от пограничного слоя на его собственном пороге. Тело под необъявленным типом содержимого — например, `text/plain` — на маршрутах сущностей, пользовательских полей, чатов, заметок и ключей отклоняется кодом `415 FST_ERR_CTP_INVALID_MEDIA_TYPE`, а пустое тело под тем же типом принимается там как `{}`. На `/v1/infra/*` и `/v1/apps`, включая публикацию исходников и места встраивания, потолок тела для непонятого типа равен одному байту, поэтому тот же запрос отвечает `413`. Крупным считается тело больше 1 МиБ — это тот же порог, что и потолок по умолчанию, — и число одновременно обрабатываемых крупных тел ограничено. Отказ приходит только там, где потолок тела поднят: записи сущностей, файлы ботов и файлы чатов. На загрузке на Диск и на `note.file.add` его не бывает. Когда свободного места нет, приходит `429 LARGE_BODY_BACKEND_BUSY` с заголовком `Retry-After: 5`. Так же отвечает запрос без заголовка `Content-Length`, если объём переваливает тот же порог уже по ходу передачи. Срок повтора берите из заголовка: поле `error.retryAfter` в теле этого отказа приходит не на всех путях. Исключение — маршруты AI (`/v1/ai/*`, `/v1/chat/*`, `/v1/audio/*`, `/v1/models`): у них конверт ошибки, совместимый с OpenAI, и на превышении тела в `error.code` приходит служебный код фреймворка в нижнем регистре, а не `PAYLOAD_TOO_LARGE`. ### Загрузка файлов | Код | HTTP | Когда возникает | |-----|------|-----------------| | `STORAGE_FORBIDDEN_CONTENT_TYPE` | 415 | Для `PUBLIC`-объектов запрещены типы `text/html`, `application/javascript`, `application/x-javascript`, `image/svg+xml` — они опасны межсайтовым выполнением скриптов. Загружайте такой файл как `PRIVATE` | ### Предусловия подписок на события портала | Код | HTTP | Когда возникает | |-----|------|-----------------| | `NOT_OAUTH_APP` | 400 | Сервер не привязан к OAuth-приложению с `application_token` — подписку на событие зарегистрировать нельзя | | `NO_USER_TOKEN` | 400 | У приложения нет OAuth-токена — сначала авторизуйте приложение на портале | Полное описание операций — [Подписки на события портала](./infra/event-subscriptions.md). ### Установка приложения через модуль-коннектор | Код | HTTP | Когда возникает | |-----|------|-----------------| | `CONNECTOR_APP_INSTALL_FORBIDDEN` | 403 | Администратор аккаунта Битрикс24 запретил этому сотруднику устанавливать приложения. Право выдаёт администратор аккаунта, повтор запроса состояние не меняет | | `CONNECTOR_MODULE_NOT_INSTALLED` | 409 | Модуль-коннектор на аккаунте не установлен. Состояние постоянное — пока модуль не установят, повтор бессмыслен | | `CONNECTOR_APP_INSTALL_FAILED` | 502 | Другой сбой установки на стороне модуля-коннектора. Запрос можно повторить | | `CONNECTOR_REST_UNAVAILABLE` | 502 | Подписка или пробный период действуют, но Битрикс24 отказал в выписке парного ключа. Исходная причина — в `error.details.reason`, `error.details.retryable: true` говорит, что состояние временное | Коды приходят на [создании приложения](./apps/create.md) там, где приложение устанавливает модуль-коннектор: на коробочном аккаунте, а на облачном — когда такой выпуск для аккаунта включён. При любом из этих отказов ни приложение, ни парный ключ не создаются. ### Ресурс не найден | Код | HTTP | Когда возникает | |-----|------|-----------------| | `ROUTE_NOT_FOUND` | 404 | Маршрута или HTTP-глагола не существует: опечатка в пути, несуществующая сущность, неподдерживаемый метод, а также операция, которой у этой сущности нет. Сверьте путь со списком в `GET /v1/guide` | | `ENTITY_NOT_FOUND` | 404 | Запись CRM-сущности с указанным `id` не существует. Канонический код для `/v1/deals/:id`, `/v1/contacts/:id` и подобных | | `NOT_FOUND` | 404 | Только `GET /:id`: Битрикс24 вернул `success`, но `result` пустой (применимо к нескольким смарт-методам) | | `OPERATION_NOT_FOUND` | 404 | Операции выкладки с таким идентификатором нет, она принадлежит другому ключу либо запись уже удалена. Три случая отвечают одинаково намеренно — см. [Исход выкладки](./infra/deploy/operation-status.md) | Доменные `*_NOT_FOUND` (`BOT_NOT_FOUND`, `SERVER_NOT_FOUND`, `AGENT_NOT_FOUND`, `APP_NOT_FOUND`, `PORTAL_NOT_FOUND`, `USER_NOT_FOUND`, `FILE_NOT_FOUND`, `SUBSCRIPTION_NOT_FOUND`) описаны на страницах соответствующих разделов. `B24_EMBEDDING_APP_NOT_FOUND` (404) — отдельный случай: приложение есть на платформе Вайбкод, но Битрикс24 не знает его идентификатор, потому что локальное приложение на аккаунте удалили или переустановили. Лечится пересозданием локального приложения и вызовом `POST /v1/apps/:id/relink-oauth` с новыми `bitrixClientId` и `bitrixClientSecret`. Не путать с `APP_NOT_FOUND` — тот про связку ключа и приложения на стороне платформы Вайбкод. **Два вида 404.** Один и тот же HTTP-статус `404` означает два разных состояния — различайте их по `error.code`. `ROUTE_NOT_FOUND` — маршрута или глагола не существует, повторять запрос бессмысленно: проверьте путь по `GET /v1/guide`. `ENTITY_NOT_FOUND` и доменные коды вида `*_NOT_FOUND` — маршрут существует, не найден запрошенный объект. Оба состояния отвечают в едином конверте V1. Маршрута не существует: ```json { "success": false, "error": { "code": "ROUTE_NOT_FOUND", "message": "Route GET:/v1/dealz not found. Check GET /v1/guide for available endpoints and verbs." } } ``` Маршрут существует, объекта нет: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ### Конфликты состояния | Код | HTTP | Когда возникает | |-----|------|-----------------| | `CONFLICT` | 409 | Текущее состояние ресурса несовместимо с запросом | | `ALREADY_EXISTS` | 409 | Запись с такими ключевыми полями уже существует | | `EVENT_BOUND_ELSEWHERE` | 409 | Событие портала уже привязано к другому серверу того же OAuth-приложения. См. [Подписки на события портала](./infra/event-subscriptions.md) | | `OAUTH_CLIENT_ID_IN_USE` | 409 | `POST /v1/apps/:id/relink-oauth`: указанный `bitrixClientId` уже привязан к другому приложению. Один `client_id` — одно приложение | | `OPERATION_OUTCOME_EXPIRED` | 410 | Операция выкладки ваша и она точно была, но её исход больше не хранится (срок — 7 суток). См. [Исход выкладки](./infra/deploy/operation-status.md) | ### Биллинг и тариф Возникают на эндпоинтах создания и пробуждения инфраструктуры (серверы, агенты, управляемые боты). Ответ содержит `userMessage` на русском языке для показа в интерфейсе клиента. | Код | HTTP | Когда возникает | |-----|------|-----------------| | `BILLING_EXHAUSTED` | 402 | Баланс ушёл в красную зону, аккаунт заморожен. Нужен top-up | | `ACCOUNT_FROZEN` | 402 | Платёжный аккаунт заморожен по другим причинам | | `COMMERCIAL_PLAN_REQUIRED` | 402 | Бесплатный тариф Битрикс24, пробный период недоступен или уже использован | | `MARKETPLACE_REQUIRED` | 402 | На портале нет активной подписки BitrixGPT + Маркетплейс — оформите её, чтобы открыть создание серверов, деплой и пробуждение | | `INT_VIBE_PLUS_REQUIRED` | 402 | На портале не подключён тариф Vibe+. Подключите тариф Vibe+ и повторите запрос | | `TRIAL_EXPIRED` | 402 | 14-дневный пробный период завершён | | `TRIAL_PORTAL_LIMIT` | 402 | На пробном периоде превышен общий лимит серверов на портал | | `TRIAL_USER_LIMIT` | 402 | На пробном периоде превышен лимит серверов на пользователя | | `PLAN_NOT_ALLOWED_ON_TRIAL` | 402 | Запрошенный план сервера/агента недоступен на пробном периоде | | `SERVER_WAKE_BLOCKED` | 403 | Пробуждение сервера заблокировано по небиллинговой причине | | `B24_MARKET_SUBSCRIPTION_REQUIRED` | 403 | На аккаунте нет активной подписки BitrixGPT + Маркетплейс. Приходит на [привязке места встраивания](./apps/placements/bind.md) и на установке приложения — в том числе на коробочном портале, где ключ выдаёт модуль-коннектор | | `B24_MARKET_TRIAL_USED` | 403 | Пробный период подписки BitrixGPT + Маркетплейс уже использован — привязка места встраивания и установка приложения требуют платной подписки | | `INT_TARIFF_REQUIRED` | 403 | Аккаунт работает по тарифной модели доступа, при этом как [привязка места встраивания](./apps/placements/bind.md), так и установка приложения требуют коммерческого тарифа Битрикс24 | ### Ограничение частоты | Код | HTTP | Когда возникает | |-----|------|-----------------| | `RATE_LIMITED` | 429 | Битрикс24 ограничил частоту запросов или превышен внутренний лимит. В ответе — `retryAfter` (секунды) и заголовок `Retry-After` | | `ERROR_LOOP_DETECTED` | 429 | Блокировка на стороне Вайбкод: один и тот же запрос повторяется с одинаковой ошибкой. Сигнал о баге в коде клиента. Каждый N-й запрос пробрасывается дальше для проверки восстановления | | `OPERATION_TIME_LIMIT` | 429 | Битрикс24 приостановил ЭТОТ метод для ВАШЕГО ключа примерно на 5 минут: метод исчерпал бюджет рабочего времени. В ответе `scope: "apiKey"`, `retryAfter` и заголовок `Retry-After`. Остальные методы и другие ключи портала работают | | `TIMEOUT_QUARANTINE` | 429 | Блокировка на стороне Вайбкод: метод несколько раз подряд не ответил порталу за отведённое вызову время, и пара «портал + метод» поставлена на паузу. В ответе `scope: "portal"`, `retryAfter` и заголовок `Retry-After`. Пауза общая для ВСЕХ ключей портала и снимается автоматически | ### Backend и сторонние сервисы | Код | HTTP | Когда возникает | |-----|------|-----------------| | `BITRIX_ERROR` | 422 | Битрикс24 вернул бизнес-ошибку, не подпадающую под более узкие категории (`ACCESS_DENIED`, `NOT_FOUND`, `INVALID_PARAMS`) | | `AGGREGATION_LIMIT_EXCEEDED` | 422 | [Агрегация](./entity-api.md#агрегация-post-потолок-5000-записей) отказалась отвечать: выборка шире 5000 записей, оценённая стоимость вызова превысила безопасный бюджет, страница записей не догрузилась — либо (для дел без сужающего фильтра) Битрикс24 не ответил за отведённое на вызов время. `message` говорит, какой именно случай. Заголовка `Retry-After` нет: отказ не временный | | `METHOD_NOT_YET_AVAILABLE` | 422 | Метод выходит в обновлении Битрикс24 и на этот портал ещё не приехал. Ответ содержит поле `error.release` с идентификатором обновления, например `imopenlines 26.700.0`. Это признак раскатки, а не ошибка вызова — [подробнее](#method_not_yet_available-422) | | `BITRIX_UNAVAILABLE` | 502 | Битрикс24 вернул 5xx или не ответил вовремя | | `BIND_FAILED` | 502 | Битрикс24 отклонил регистрацию события (`event.bind`) — например, портал не на коммерческом тарифе. См. [Подписки на события портала](./infra/event-subscriptions.md) | | `WINDOWED_SEARCH_FAILED` | — | Больше не возвращается: при полном отказе авто-окон `/search` возвращается реальный код Битрикс24 — `UNKNOWN_FILTER_FIELD` / `INVALID_PARAMS` / `BITRIX_ACCESS_DENIED` / `RATE_LIMITED` / `BITRIX_UNAVAILABLE` / `BITRIX_TIMEOUT` (503), как для узкого диапазона | | `QUEUE_OVERFLOW` | 429 | Очередь портала переполнена: слишком много одновременных вызовов Битрикс24. Отклоняется мгновенно, `Retry-After` в заголовке | | `QUEUE_TIMEOUT` | 429 | Очередь портала перегружена: больше 30 секунд ожидания на стороне Вайбкод. Запрос не был отправлен в Битрикс24 — безопасно повторить | | `BITRIX_TIMEOUT` | 503 | Битрикс24 принял запрос, но не ответил за 15 секунд — исход неизвестен. Для write: сначала перечитайте сущность, изменение могло примениться | | `POOL_EXHAUSTED` | 503 | Сервис временно перегружен — исчерпан пул соединений с базой данных. В ответе `retryAfter` и заголовок `Retry-After`, повторите через несколько секунд | | `DB_TRANSIENT` | 503 | Транзакция в базе данных закрылась или истекла до того, как операция завершилась, — платформа откатила её целиком. Отказ временный: в ответе `retryAfter` и заголовок `Retry-After`, повторите через несколько секунд. Изменение не применилось ни частично, ни полностью | | `SERVICE_UNAVAILABLE` | 503 | Граница платформы не смогла передать запрос бэкенду (например, в момент редеплоя) — либо не дождалась ответа. В ответе `retryAfter` и заголовок `Retry-After`. Если запрос мог быть выполнен (истёк таймаут ожидания ответа), для не-идемпотентных операций перед повтором сверьте состояние сущности | | `INTERNAL_ERROR` | 500 | Непредвиденная ошибка backend Вайбкод | | `NETWORK_DEVKEY_REQUIRED` | 503 | Ключ разработчика для автора приложения ещё не выдан — [привязка места встраивания](./apps/placements/bind.md) временно недоступна | ## Подробное описание ### `MISSING_API_KEY` (401) Запрос не содержит заголовка `X-Api-Key`. ```json { "success": false, "error": { "code": "MISSING_API_KEY", "message": "API key required. Pass via X-Api-Key header." } } ``` **Причины:** - Не передан заголовок `X-Api-Key` или `Authorization`. - Заголовок передан с пустым значением. **Решение:** - Добавить заголовок `X-Api-Key: vibe_api_...` или `X-Api-Key: vibe_app_...`. - Проверить, что переменная окружения с ключом установлена корректно (для CLI-утилит и SDK). --- ### `INVALID_API_KEY` (401) Переданный ключ не существует или его формат не распознан. ```json { "success": false, "error": { "code": "INVALID_API_KEY", "message": "Invalid API key" } } ``` **Причины:** - Опечатка или лишние пробелы в ключе. - Ключ удалён владельцем или администратором. - Ключ от другого окружения (staging/production). - Префикс не из числа поддерживаемых: `vibe_api_`, `vibe_app_`, `vibe_live_`, `vibe_mgmt_`. **Решение:** - Сверить ключ в личном кабинете на странице `/keys`. - Создать новый ключ, если старый удалён. --- ### `TOKEN_MISSING` (401) У ключа нет кредов Битрикс24, поэтому вызов к порталу выполнить нечем. Причина зависит от типа ключа, и это два разных сценария. **Личный ключ (`vibe_api_*`)** ходит в портал по вебхуку. Если вебхука на ключе нет, ответ на вызовах сущностей (`/v1/{сущность}` и `POST /v1/batch`) несёт машиночитаемую причину в `error.details`. На остальных маршрутах приходит тот же код без `details`: ```json { "success": false, "error": { "code": "TOKEN_MISSING", "message": "This personal API key (vibe_api_*) has no Bitrix24 webhook credentials, ...", "details": { "reason": "B24_MARKET_SUBSCRIPTION_REQUIRED", "paywallCode": "B24_MARKET_SUBSCRIPTION_REQUIRED" } } } ``` Значения `details.reason`: | Причина | Что означает | Что делать | |---|---|---| | `B24_MARKET_SUBSCRIPTION_REQUIRED` | На портале нет активной подписки на Битрикс24 Маркет | Активировать демо Маркета или оформить подписку, затем переподключить ключ | | `B24_MARKET_TRIAL_USED` | Демо Маркета уже использовано, платной подписки нет | Оформить подписку на Маркет, затем переподключить ключ | | `INT_TARIFF_REQUIRED` | У портала нет платного тарифа Битрикс24 (регионы с тарифной моделью доступа) | Подключить платный тариф, затем переподключить ключ | | `VIBE_SCOPES_ONLY` | Ключ не запрашивал ни одного скоупа Битрикс24 — вебхук ему не выдаётся by design | Создать ключ с нужными скоупами Битрикс24 | | `WEBHOOK_NOT_CONFIGURED` | Доступ Битрикс24 в порядке либо неизвестен, а вебхука на ключе нет | Переподключить ключ. При `details.hint` — повторить проверку через `GET /v1/me?refresh=tariff` | **Переподключение** — `POST /api/keys/:id/reconnect`: выдаёт ключу вебхук, не меняя саму строку ключа (интеграции перенастраивать не нужно), и снимает авто-блокировку со связанных ботов. Не применимо к ключам приложения, системным ключам и ключам без скоупов Битрикс24 — для них остаётся создание нового ключа. `paywallCode` приходит только для тарифных причин. Вместе с ним может прийти `upgradeUrl` — ссылка на страницу подключения на портале. У `INT_TARIFF_REQUIRED` её нет. **Ключ приложения (`vibe_app_*`)** держит токены портала в пользовательской сессии, а не на ключе. Вызов только с `X-Api-Key`, без `Authorization: Bearer <токен сессии>`, законно отвечает `TOKEN_MISSING` — `details` в этой ветке не приходит, а `message` описывает пропущенный шаг OAuth. Полный поток — [Ключи и авторизация](./keys-auth.md). **Как посмотреть состояние ключа заранее:** `GET /v1/me` для личного ключа отдаёт блок `b24Credentials` (`ready`, а при `ready: false` — та же `reason` и действия), а `GET /v1/keys` — признак `b24Ready` на каждом ключе. Ответ `/v1/me` кэшируется на 30 секунд, поэтому сразу после починки на портале читайте его как `GET /v1/me?refresh=tariff` — иначе до полуминуты будет отдаваться прежнее состояние. У `GET /v1/keys` кэша нет. --- ### `SCOPE_DENIED` (403) У ключа нет нужного скоупа для запрошенной операции. ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` **Причины:** - Для CRM-сущностей нужен скоуп `crm`, для задач — `task`, для бот-платформы — `imbot`, для AI Router — `vibe:ai`, для инфраструктуры — `vibe:infra`. - Скоуп ключа сужен на этапе создания. **Решение:** - Открыть страницу ключа в личном кабинете и выпустить новый ключ с расширенным набором скоупов. - Полный список скоупов и их назначение — на странице [Ключи и авторизация](./keys-auth.md). --- ### `BITRIX_ACCESS_DENIED` (403) Битрикс24 ответил `ACCESS_DENIED`: у пользователя или приложения нет прав на сущность или операцию. ```json { "success": false, "error": { "code": "BITRIX_ACCESS_DENIED", "message": "ACCESS_DENIED" } } ``` **Причины:** - У пользователя нет прав на сущность в CRM (например, чужая сделка с ограничением видимости). - Набор скоупов на портале уже, чем набор скоупов ключа. Скоупы Битрикс24 закрепляются за ключом в момент выпуска, поэтому скоуп, добавленный к уже выпущенному ключу, `GET /v1/me` покажет, а к данным портала ключ обратится с прежним набором. - Запрашиваемый модуль выключен на портале (отсутствует CRM, бот-платформа и тому подобное). **Решение зависит от типа ключа.** Когда отказ вызван набором скоупов, в `error.hint` приходит подсказка с конкретным случаем. Подсказка приходит не всегда: голому `ACCESS_DENIED` без пояснений от Битрикс24 её может не быть. - **API-ключ (`vibe_api_`).** Набор скоупов, с которым ключ обращается к порталу, хранится на портале отдельно от набора у самого ключа. [Перевыпустить ключ](./keys-auth.md#перевыпуск), переподключить его или создать новый с отмеченным скоупом — правка разрешений приложения на портале в этом случае ничего не меняет. - **Ключ авторизации (`vibe_app_`).** Создать приложение заново с нужным скоупом и пройти авторизацию заново. Перевыпуск ключа здесь скоуп не выдаёт. - **Методы чатов и ботов.** Для них того же отказа недостаточно объяснить скоупом: владелец ключа должен быть администратором портала. Выпустить ключ под учётной записью администратора — расширение скоупов тут не поможет. - Если дело в правах сотрудника, а не в скоупах ключа — проверить права пользователя в карточке сущности Битрикс24. Полное описание того, как скоупы закрепляются за ключом и что делать, если после перевыпуска отказ повторяется, — [Ключи и авторизация](./keys-auth.md). --- ### `WRITE_BLOCKED_READONLY_KEY` (403) У ключа задан режим «только чтение» (`accessMode: "READONLY"`), а запрос выполняет запись. Полное описание режима, переключения и политики портала — [Режим доступа](./keys-auth/access-mode.md). ```json { "success": false, "error": { "code": "WRITE_BLOCKED_READONLY_KEY", "message": "Key is in read-only mode. Switch to read+write in /keys to enable writes.", "details": { "method": "crm.item.add", "keyName": "MCP key", "currentMode": "READONLY", "switchUrl": "/keys" } } } ``` **Поля `details`:** | Поле | Когда возвращается | Описание | |------|-------------------|----------| | `method` | Только при проксировании в Битрикс24 | Имя метода Битрикс24, который был бы вызван при успешной записи (например, `crm.item.add`). Для менеджмент-ключей не возвращается — блокировка идёт по HTTP-методу запроса | | `keyName` | Всегда | Название ключа из личного кабинета. Если у ключа нет названия — возвращается `"unnamed"` | | `currentMode` | Всегда | Действующий режим ключа — всегда `"READONLY"` для этой ошибки | | `switchUrl` | Всегда | Путь до страницы личного кабинета, где режим переключается, — `"/keys"` | **Причины:** - **API-ключ или ключ авторизации (`vibe_api_`, `vibe_app_`)** в режиме `READONLY` выполнил вызов, который проксируется в Битрикс24 как операция записи: создание, обновление, удаление, действие над сущностью. - **Менеджмент-ключ (`vibe_live_`)** в режиме `READONLY` выполнил запрос с HTTP-методом `POST`, `PATCH`, `PUT` или `DELETE` — например, попытка создать ключ через `POST /v1/keys` или удалить запись обратной связи. **Решение:** - Владельцу ключа — открыть [Ключи API](/keys), в карточке нужного ключа в блоке **Режим доступа** выбрать «Чтение и запись» и сохранить. Режим применяется к следующему запросу, перевыпуск не нужен. - Если в карточке выбор переключателя недоступен — администратор портала ограничил режим. Запросить у администратора снятие ограничения для этого ключа. - При работе через AI-агента — действующий режим возвращает `GET /v1/me` в поле `data.accessMode`. Если запись нужна постоянно, выпустить отдельный ключ с режимом «чтение и запись». --- ### `VALIDATION_ERROR` (400) Тело или query-параметры не прошли проверку схемы. Для большинства V1-эндпоинтов обработка реализована через Zod, поэтому сообщение содержит конкретные поля с проблемами. ```json { "success": false, "error": { "code": "VALIDATION_ERROR", "message": "fields.title: Required; fields.stageId: Expected string, received number" } } ``` **Причины:** - Отсутствуют обязательные поля. - Тип значения не соответствует схеме (строка вместо числа, неверный формат даты). - Отсутствует заголовок `Content-Type: application/json`. Тело, которое не разбирается как JSON, отклоняется отдельными кодами — `INVALID_JSON_BODY`, `FST_ERR_CTP_INVALID_JSON_BODY` или `fst_err_ctp_invalid_json_body` на маршрутах AI Router. Какой из них придёт, зависит от маршрута — см. таблицу выше. **Решение:** - Сверить body со схемой эндпоинта в [справочнике сущностей](./entity-api.md) или на странице конкретного эндпоинта. - Числа передавать без кавычек, даты — в формате ISO 8601 (`2026-04-29T10:00:00`). - Добавить заголовок `Content-Type: application/json`. --- ### `INVALID_PARAMS` (400) Битрикс24 или route-handler нашёл некорректное значение параметра. Ошибки Битрикс24 формата `INVALID_PARAMS: ...` приходят под этим же кодом. ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "Path parameter :id must be a positive integer" } } ``` **Причины:** - Некорректное значение path-параметра (например, не число там, где ожидается число). - Битрикс24 отверг параметр запроса (например, неподходящее значение enum-поля). **Решение:** - Проверить страницу эндпоинта: какие значения допустимы для каждого параметра. - Для `filter` использовать список полей из `GET /v1//fields`. --- ### `MISSING_REQUIRED_FILTER` (400) Не передан обязательный фильтр на list-эндпоинте, который требует контекста. ```json { "success": false, "error": { "code": "MISSING_REQUIRED_FILTER", "message": "filter[entityType] and filter[entityId] are required for /v1/timelines" } } ``` **Причины:** - Список тайм-лайн-записей требует пары родительских идентификаторов `entityType` + `entityId`. - Список товаров и разделов каталога требует `iblockId`, а список значений списочного свойства — `propertyId`. - [Агрегация дел](./entities/activities/aggregate.md) требует сужающего фильтра: пара `ownerTypeId` + `ownerId`, либо `responsibleId`, либо граница по дате на `createdAt` / `updatedAt` / `deadline`. Здесь требование не «все перечисленные», а «любое одно» — Битрикс24 не успевает посчитать все дела аккаунта за отведённое на вызов время. Требование включается платформой отдельно на каждый аккаунт. Проверить состояние — `data.aggregateFilterRequirement.enforcement` в ответе `GET /v1/activities/fields`. Проверка выполняется до обращения к Битрикс24 и действует на `GET /v1/{entity}`, `POST /v1/{entity}/search` и `POST /v1/{entity}/aggregate`. **Решение:** - Добавить обязательные параметры фильтра, перечисленные в `message` или на странице эндпоинта. --- ### `BATCH_LIMIT_EXCEEDED` (400) Запрос превышает лимит элементов в массивной операции. На уровне `/v1/batch` лимит проверяется через `INVALID_REQUEST` со ссылкой на `Array must contain at most 50 element(s)`. На доменных bulk-эндпоинтах (например, `chats`, `task-comments`) — отдельный код `BATCH_LIMIT_EXCEEDED`. ```json { "success": false, "error": { "code": "BATCH_LIMIT_EXCEEDED", "message": "Maximum 50 dialogs per bulk request (Bitrix24 batch limit)." } } ``` **Причины:** - В массиве больше 50 элементов. **Решение:** - Разделить операцию на несколько запросов по 50 элементов. - Использовать [batch-запросы](./batch.md) для последовательных вызовов с одного ключа. --- ### `ENTITY_NOT_FOUND` (404) Запись CRM-сущности с указанным `id` не существует или была удалена. ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` **Причины:** - Запись с таким `id` действительно не существует. - Запись была удалена параллельным процессом. - Перепутана сущность: запрос идёт на `/v1/deals/:id`, а ID — от лида. **Решение:** - Проверить наличие записи через list-эндпоинт сущности. - Восстановить из корзины Битрикс24, если запись была удалена недавно (через интерфейс портала). --- ### `RATE_LIMITED` (429) Битрикс24 ограничил частоту запросов либо сработал внутренний лимит Вайбкод. ```json { "success": false, "error": { "code": "RATE_LIMITED", "message": "QUERY_LIMIT_EXCEEDED", "hint": "Wait 1-2 seconds and retry. Use POST /v1/batch to combine up to 50 calls in 1 request.", "retryAfter": 2 } } ``` **Заголовки ответа:** ``` Retry-After: 2 ``` **Причины:** - Сложилось слишком много одновременных запросов от одного ключа: общий лимит платформы считается по API-ключу. Исключение — [`POST /v1/search`](./search/run.md), [`POST /v1/research`](./search/research.md) и [`POST /v1/batch`](./batch.md): там лимит считается на портал, и все его ключи делят один счётчик. - Превышен лимит запросов в секунду на стороне Битрикс24. Он считается на портал. **Решение:** - Дождаться времени из `error.retryAfter` или заголовка `Retry-After`. - Реализовать повторные попытки с экспоненциальной задержкой. - Объединять до 50 вызовов через [`POST /v1/batch`](./batch.md). - Кэшировать редко изменяемые справочные данные — поля, статусы, валюты. --- ### `ERROR_LOOP_DETECTED` (429) Вайбкод фиксирует серию одинаковых ошибок на одном ключе для одного метода Битрикс24 — и временно блокирует запрос на стороне Вайбкод, чтобы не накручивать счётчики Битрикс24. Каждый N-й запрос пробрасывается дальше: если backend восстановился, блокировка снимается автоматически. ```json { "success": false, "error": { "code": "ERROR_LOOP_DETECTED", "message": "Vibe-side block (not a Bitrix24 limit). 12 failures on crm.deal.list in the last hour.", "hint": "Every 50th request will probe for recovery — keep retrying with backoff. If you suspect a platform-side issue (e.g. 5xx during an outage), platform admin can clear the block via POST /api/platform/analytics/circuit-breaker//clear.", "retryAfter": 60 } } ``` **Причины:** - В коде клиента баг: запрос с одинаковыми параметрами повторяется и стабильно даёт ошибку. - Платформенная авария на стороне Битрикс24 в момент серии запросов. **Решение:** - Прочитать `message` — там указан конкретный метод с серией ошибок. - Найти источник запроса в коде, исправить параметры или логику. - При платформенной аварии — повторять с задержкой: каждый N-й запрос платформа пропускает для проверки восстановления, и блокировка снимается сама. Если она держится дольше самой аварии, обратитесь в поддержку. - Маршрут, названный в поле `hint` ответа, — служебный эндпоинт платформы. Своим ключом его не вызвать, и вмешательство не требуется: он адресован поддержке. --- ### `BILLING_EXHAUSTED` (402) Платёжный аккаунт ушёл в красную зону: баланс отрицательный, грейс-период исчерпан. Запросы на создание и пробуждение инфраструктуры блокируются до пополнения. ```json { "success": false, "error": { "code": "BILLING_EXHAUSTED", "message": "Account is frozen due to negative balance.", "userMessage": "Платёжный аккаунт заморожен из-за отрицательного баланса. Пополните счёт, чтобы продолжить работу с серверами и агентами.", "hint": "Top up the account at /billing/topup, then call POST /v1/portals/:id/refresh-tariff." } } ``` **Причины:** - На балансе нет средств для оплаты часовой стоимости серверов и агентов. **Решение:** - Пополнить баланс на странице `/billing/topup`. - После пополнения вызвать `POST /v1/portals/:id/refresh-tariff` для обновления статуса. --- ### `COMMERCIAL_PLAN_REQUIRED` (402) Создание серверов и агентов недоступно на бесплатном тарифе Битрикс24 после окончания пробного периода. ```json { "success": false, "error": { "code": "COMMERCIAL_PLAN_REQUIRED", "message": "Commercial Bitrix24 plan required for infrastructure operations.", "userMessage": "Создание инфраструктуры доступно на коммерческих тарифах Битрикс24. Пробный период уже использован.", "hint": "Upgrade plan at https://www.bitrix24.ru/prices/, then call POST /v1/portals/:id/refresh-tariff." } } ``` **Решение:** - Обновить тариф Битрикс24 до коммерческого. - После обновления вызвать `POST /v1/portals/:id/refresh-tariff` либо `GET /v1/me?refresh=tariff`. --- ### `TRIAL_EXPIRED` (402) 14-дневный пробный период завершился, тариф остался бесплатным. ```json { "success": false, "error": { "code": "TRIAL_EXPIRED", "message": "Trial period has ended.", "userMessage": "Пробный период (14 дней) завершён. Перейдите на коммерческий тариф Битрикс24, чтобы продолжить пользоваться серверами и агентами." } } ``` **Решение:** - Перейти на коммерческий тариф Битрикс24. - Обновить статус через `POST /v1/portals/:id/refresh-tariff`. --- ### Отказы по подписке и тарифу (403) Три кода одного класса: доступ к операции закрыт условиями подписки или тарифа аккаунта, а не правами ключа. Приходят на [установке приложения](./apps/create.md) и на [привязке места встраивания](./apps/placements/bind.md) — в том числе на коробочном аккаунте, где ключ выдаёт модуль-коннектор. | Код | Когда приходит | `error.details.upgradeUrl` | |-----|----------------|----------------------------| | `B24_MARKET_SUBSCRIPTION_REQUIRED` | На аккаунте нет активной подписки BitrixGPT + Маркетплейс | передаётся | | `B24_MARKET_TRIAL_USED` | Пробный период подписки уже использован — нужна платная | передаётся | | `INT_TARIFF_REQUIRED` | Аккаунт получает доступ по тарифу Битрикс24, а не по подписке: нужен коммерческий тариф. Приходит вместо двух кодов выше, а также когда модель доступа аккаунта определить не удалось | не передаётся | ```json { "success": false, "error": { "code": "INT_TARIFF_REQUIRED", "message": "Paid Bitrix24 plan required (international region)", "userMessage": "Для доступа нужен платный тариф Битрикс24." } } ``` **Решение:** - Отказ окончательный — повторять запрос бессмысленно. Пока условие доступа не изменилось на аккаунте, тот же вызов будет отклоняться. - Если пришёл `error.details.upgradeUrl` — это готовый адрес страницы оформления на самом аккаунте. Ведите пользователя по нему, а не собирайте адрес сами. - Если `upgradeUrl` не пришёл, на установке приложения и привязке места встраивания оформлять нечего: у аккаунта тарифная модель доступа, и нужен коммерческий тариф Битрикс24. - Различайте эти коды в клиенте по `error.code`, а не по тексту: у трёх отказов разные действия пользователя. --- ### `BITRIX_ERROR` (422) Битрикс24 вернул бизнес-ошибку, которая не подпадает под более узкие категории (`ACCESS_DENIED`, `NOT_FOUND`, `INVALID_PARAMS`, `RATE_LIMITED`). ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "The requested period exceeds the maximum of 1 year", "b24Code": "PERIOD_TOO_LARGE" } } ``` **Причины:** - Битрикс24 отверг операцию по бизнес-причине: несовместимое состояние, неподдерживаемое значение, бизнес-правило. - Запрос работает на портале, где соответствующий модуль отключён. **Решение:** - Прочитать `message` — там оригинальный текст ошибки от Битрикс24. - При наличии `hint` — использовать его как первый шаг диагностики. - Для программной обработки читать поле `error.b24Code` — машиночитаемый код причины от Битрикс24, например `BOT_TYPE_NOT_ALLOWED` или `PERIOD_TOO_LARGE`. Ветвиться в коде по нему, а не по тексту `message`. - Поле `error.b24Code` приходит не всегда: когда Битрикс24 не прислал отдельный код, его в ответе нет. --- ### `METHOD_NOT_YET_AVAILABLE` (422) Метод выходит в обновлении Битрикс24, которое на этот портал ещё не приехало. Это признак раскатки, а не ошибка вызова: тот же запрос начнёт работать сам, как только обновление дойдёт до портала. На отдельных методах после этого добавляется своя проверка прав — она описана на странице метода. ```json { "success": false, "error": { "code": "METHOD_NOT_YET_AVAILABLE", "message": "Method \"imopenlines.v2.Stat.get\" is rolling out in update imopenlines 26.700.0 and is not yet available on this portal — this is not a call error.", "release": "imopenlines 26.700.0" } } ``` **Решение:** - Ветвиться по `error.code`, а не по тексту `message`. - Поле `error.release` — идентификатор обновления целиком: имя модуля и номер версии одной строкой. Сравнивать его на равенство как строку, разбирать как номер версии нельзя. - Частые повторы ничего не меняют: состояние переключается приездом обновления на портал, а не повтором вызова. Заголовка `Retry-After` и поля `retryAfter` в этом отказе нет, потому что срока платформа не знает. Пока обновление не пришло, показывайте пользователю ожидание названной версии, а не ошибку интеграции. --- ### `BITRIX_UNAVAILABLE` (502) Битрикс24 вернул 5xx или не ответил в отведённое время. ```json { "success": false, "error": { "code": "BITRIX_UNAVAILABLE", "message": "Bitrix24 returned 503 Service Unavailable" } } ``` **Причины:** - Технические работы или перегрузка на стороне Битрикс24. - Сетевые проблемы между Вайбкод и порталом. **Решение:** - Повторить запрос через несколько минут, реализовав повторные попытки с экспоненциальной задержкой. - **Для записывающих операций (POST/PATCH) — сначала проверьте, не применился ли исходный запрос.** Медленный портал может обработать запись уже ПОСЛЕ того, как API вернул таймаут — слепой повтор создаст дубль (задачи, эпика, комментария). Перед ретраем сделайте `GET` по списку/записи (например, поиск по только что отправленному названию) и повторяйте только если записи нет. - Проверить статус портала по адресу `/bitrix/admin/site_checker.php` (для администратора портала). --- ### `QUEUE_OVERFLOW` (429) Очередь запросов к Битрикс24 для конкретного портала переполнена: слишком много вызовов уже в ожидании (по умолчанию — более 100). Ответ возвращается мгновенно, за миллисекунды, с HTTP-заголовком `Retry-After: N` (секунды). ```json { "success": false, "error": { "code": "QUEUE_OVERFLOW", "message": "Portal queue overloaded — 100 Bitrix24 calls already pending", "userMessage": "Слишком много одновременных запросов к Bitrix24 — повторите через несколько секунд.", "hint": "Honor the Retry-After header. Use exponential backoff with jitter for repeated failures.", "retryAfter": 10 } } ``` **Решение:** - Очередь портала переполнена — повторите запрос через `Retry-After` секунд, используя backoff с джиттером (случайной добавкой к паузе), чтобы повторы от разных клиентов не пришли одной волной. - Уменьшить параллелизм на стороне клиента. - Объединить вызовы через `POST /v1/batch`. --- ### `QUEUE_TIMEOUT` (429) Очередь запросов к Битрикс24 для конкретного портала перегружена: больше 30 секунд ожидания. ```json { "success": false, "error": { "code": "QUEUE_TIMEOUT", "message": "Portal queue saturated — too many concurrent Bitrix24 calls", "userMessage": "Запросы к Битрикс24 в очереди дольше 30 секунд. Вероятно, на портале много одновременных операций.", "hint": "If this is a /search request with a wide date range, try adding \"autoWindow\": false OR narrow the date range to <14 days. See /v1/guide for optimization tips.", "retryAfter": 10 } } ``` Запрос НЕ был отправлен в Битрикс24 — безопасно повторить. **Решение:** - Повторить через `retryAfter` секунд, используя backoff с джиттером. - Уменьшить параллелизм. - Для `/search`-эндпоинтов — сузить диапазон дат либо передать `autoWindow: false`. - Объединить вызовы через `POST /v1/batch`. - Проверить таймаут на своей стороне: ожидание в очереди входит во время ответа, поэтому клиенту нужен запас — [Клиентский таймаут](./optimization.md#клиентский-таймаут). --- ### `TIMEOUT_QUARANTINE` (429) Метод несколько раз подряд не ответил вашему порталу Битрикс24 за отведённое вызову время, поэтому Вайбкод поставил пару «портал + метод» на паузу и больше не отправляет к ней запросы. > **В процессе раскатки.** Механизм включается на порталах постепенно. Пока он не включён на вашем, этот код не приходит: вызовы уходят в Битрикс24 как раньше и упираются в таймаут `BITRIX_TIMEOUT`. ```json { "success": false, "error": { "code": "TIMEOUT_QUARANTINE", "message": "Vibe-side block (not a Bitrix24 limit). crm.item.list timed out 5 times in a row on this portal, so calls to it are paused.", "hint": "Портал не отвечал на этот метод за отведённое вызову время, поэтому каждый следующий вызов только добавлял бы нагрузку. Дождитесь срока из Retry-After и НЕ сокращайте интервал повторов: агрессивный повтор занимает слот пробы восстановления и держит метод закрытым для всего портала дольше. Раз в 5 мин один вызов пропускается как проба, и первый успешный ответ снимает паузу немедленно. Облегчите запрос — меньше полей, меньше страница, более узкий фильтр: пару снимает с паузы именно лёгкий вызов.", "retryAfter": 288, "scope": "portal" } } ``` **Заголовки ответа:** ``` Retry-After: 288 ``` **Причины:** - Метод стабильно не отвечает порталу за отведённое вызову время — обычно из-за тяжёлого запроса: широкий диапазон дат, много полей в `select`, большая страница, фильтр по неиндексированному полю. - Пауза считается на пару «портал + метод» и не зависит от того, каким ключом сделан вызов: `scope: "portal"` означает, что её видят ВСЕ ключи портала, включая чужие интеграции. Контраст — [`OPERATION_TIME_LIMIT`](#operation_time_limit-429) со `scope: "apiKey"`: тот отказ про ваш ключ, этот — про весь портал. - Это отказ на стороне Вайбкод, а не лимит Битрикс24: запрос до портала не дошёл, поэтому ничего не изменилось — повтор безопасен даже для методов записи. - Код приходит и внутри `200`-ответа — на подвызовах [`POST /v1/batch`](./batch.md), которые Вайбкод исполняет отдельными запросами (`data.errors[]`), и на элементах батча одной сущности (`data[i].error`). У `200`-конверта нет заголовка `Retry-After` для отдельного подвызова, поэтому срок приходит полем `retryAfter`, а `scope` и `hint` — те же, что в одиночном `429`. **Решение:** - Дождаться срока из `retryAfter` (или заголовка `Retry-After`) и **не сокращать интервал повторов**: пока пауза действует, один вызов раз в 5 минут пропускается как проба восстановления, и агрессивный повтор занимает этот слот собой — метод остаётся закрытым для всего портала дольше, чем если бы вы просто подождали. - Добавлять к паузе случайную добавку (джиттер), чтобы повторы разных клиентов не пришли одной волной. - Облегчить сам вызов: меньше полей в `select`, меньше страница, более узкий фильтр или более узкий интервал дат. Пауза снимается первым успешным ответом, поэтому её снимает именно лёгкий вызов — тяжёлый снова упрётся в таймаут и продлит окно. - Не искать эндпоинт для снятия паузы — его нет, и вмешательство не требуется. - Сам конверт [`POST /v1/batch`](./batch.md) под паузу не попадает: он объединяет разные методы, и его собственная задержка не говорит о том, какие из них перестали отвечать. --- ### `OPERATION_TIME_LIMIT` (429) Битрикс24 приостановил ЭТОТ метод примерно на 5 минут, потому что метод исчерпал бюджет рабочего времени на портале. Отказ приходит и когда его прислал сам портал, и когда Вайбкод отбивает вызов на входе, зная, что пауза ещё действует. ```json { "success": false, "error": { "code": "OPERATION_TIME_LIMIT", "message": "Bitrix24 operation-time limiter banned crm.item.list on this portal, retry in 245s", "userMessage": "Битрикс24 приостановил этот запрос на несколько минут: метод исчерпал лимит рабочего времени на портале. Дождитесь срока из Retry-After — остальные методы работают.", "hint": "Bitrix24 banned THIS method on this portal for ~5 minutes because it exhausted the portal's operating-time budget. Honor Retry-After — the same call cannot succeed sooner and retrying earlier only adds load. Other methods on the portal are unaffected; spread heavy reads over time or narrow them (fewer fields, smaller pages, POST /v1/batch).", "retryAfter": 245, "scope": "apiKey" } } ``` **Заголовки ответа:** ``` Retry-After: 245 ``` **Причины:** - Метод израсходовал бюджет рабочего времени, который Битрикс24 считает на скользящем окне. - Пауза адресная: `scope: "apiKey"` означает, что Битрикс24 приостановил связку «ваш ключ + этот метод». Другие методы работают, и другие ключи портала тот же метод вызывать могут. Контраст — [`TIMEOUT_QUARANTINE`](#timeout_quarantine-429) со `scope: "portal"`: там пауза общая для всего портала. - Запрос не был выполнен — повтор безопасен, в том числе для методов записи. - Код приходит и внутри `200`-ответа — на подвызовах [`POST /v1/batch`](./batch.md), которые Вайбкод исполняет отдельными запросами (`data.errors[]`), и на элементах батча одной сущности (`data[i].error`). У `200`-конверта нет заголовка `Retry-After` для отдельного подвызова, поэтому срок приходит полем `retryAfter`, а `scope` и `hint` — те же, что в одиночном `429`. Поля `userMessage` в конверте нет. **Решение:** - Дождаться срока из `retryAfter` (или заголовка `Retry-After`): раньше этого срока тот же вызов не пройдёт, а повторы только добавляют нагрузку. - Разнести тяжёлые чтения по времени, а не запускать их пачкой. - Облегчить вызовы: меньше полей в `select`, меньше страница, объединение через [`POST /v1/batch`](./batch.md). --- ### `BITRIX_TIMEOUT` (503) Битрикс24 принял запрос, но не ответил за 15 секунд — исход неизвестен: запрос МОГ примениться на стороне портала. ```json { "success": false, "error": { "code": "BITRIX_TIMEOUT", "message": "Bitrix24 accepted the request but did not respond within 15s", "hint": "For WRITE operations, verify whether the change was applied (re-read the entity) before retrying. Reads are safe to retry.", "retryAfter": 10 } } ``` **Решение:** - Для чтения (GET/`/search`) — повторить безопасно, после более длинного backoff, чем при `429`. - **Для записывающих операций (POST/PATCH) — сначала перечитайте сущность.** Изменение могло уже примениться на стороне Битрикс24, несмотря на то, что ответ не пришёл. Слепой повтор создаст дубль (задачи, эпика, комментария). Проверьте наличие записи (например, поиск по только что отправленному названию) и повторяйте запись только если её нет. --- ### `INTERNAL_ERROR` (500) Непредвиденная ошибка на стороне API Вайбкод. ```json { "success": false, "error": { "code": "INTERNAL_ERROR", "message": "Internal server error" } } ``` **Решение:** - Повторить запрос. - Если ошибка воспроизводится стабильно — отправить тикет через `POST /v1/feedback` с указанием времени запроса. Заголовок `X-Request-Id` из ответа ускоряет диагностику. ## Повторы и backoff Сводка по кодам, которые сигнализируют о временной проблеме и подразумевают повтор: | Код | HTTP | Стратегия повтора | |-----|------|--------------------| | `RATE_LIMITED`, `QUEUE_OVERFLOW`, `QUEUE_TIMEOUT` | 429 | Повтор через `Retry-After` + backoff с джиттером (случайной добавкой к паузе) | | `LARGE_BODY_BACKEND_BUSY` | 429 | Повтор через `Retry-After` + джиттер. Запрос не выполнялся и состояние не менял — повтор безопасен и для записи | | [`OPERATION_TIME_LIMIT`](#operation_time_limit-429) | 429 | Повтор строго через `Retry-After`: раньше этого срока тот же вызов не пройдёт. `scope: "apiKey"` — пауза только на вызывающем ключе | | [`TIMEOUT_QUARANTINE`](#timeout_quarantine-429) | 429 | Повтор через `Retry-After` + джиттер, и **не сокращая интервал**: агрессивный повтор занимает слот пробы восстановления и держит метод закрытым для всего портала дольше. `scope: "portal"` — пауза общая для всех ключей портала | | `BITRIX_TIMEOUT` | 503 | Более длинный backoff, чем при 429. Для write-операций — сначала verify-before-retry: перечитайте сущность, изменение могло уже примениться | | `BITRIX_UNAVAILABLE` | 502 | Повтор не поможет без изменения запроса — это 5xx самого Битрикс24 или сетевая проблема между Вайбкод и порталом, а не временная перегрузка очереди | ## Обработка ошибок в коде ### JavaScript ```javascript async function vibeRequest(url, options = {}) { const response = await fetch(url, { ...options, headers: { 'X-Api-Key': process.env.VIBE_API_KEY, 'Content-Type': 'application/json', ...options.headers, }, }); const data = await response.json(); if (!data.success) { const { code, message, retryAfter } = data.error; switch (code) { case 'RATE_LIMITED': case 'QUEUE_TIMEOUT': { const wait = retryAfter ?? Number(response.headers.get('Retry-After') ?? 1); await new Promise(r => setTimeout(r, wait * 1000)); return vibeRequest(url, options); } case 'BITRIX_UNAVAILABLE': await new Promise(r => setTimeout(r, 5000)); return vibeRequest(url, options); case 'MISSING_API_KEY': case 'INVALID_API_KEY': throw new Error('Проверьте API-ключ'); default: throw new Error(`${code}: ${message}`); } } return data; } ``` ### Python ```python import os import time import requests def vibe_request(url, method="GET", json_data=None): headers = { "X-Api-Key": os.environ["VIBE_API_KEY"], "Content-Type": "application/json", } response = requests.request(method, url, headers=headers, json=json_data) data = response.json() if not data.get("success"): err = data.get("error", {}) code = err.get("code") message = err.get("message") retry_after = err.get("retryAfter") or int(response.headers.get("Retry-After", 1)) if code in ("RATE_LIMITED", "QUEUE_TIMEOUT"): time.sleep(retry_after) return vibe_request(url, method, json_data) if code == "BITRIX_UNAVAILABLE": time.sleep(5) return vibe_request(url, method, json_data) raise Exception(f"{code}: {message}") return data ``` ### PHP ```php function vibeRequest(string $url, string $method = 'GET', ?array $data = null): array { $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => $method, CURLOPT_HTTPHEADER => [ 'X-Api-Key: ' . getenv('VIBE_API_KEY'), 'Content-Type: application/json', ], ]); if ($data !== null) { curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); } $body = json_decode(curl_exec($ch), true); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($body === null) { throw new Exception("HTTP error: $httpCode"); } if (empty($body['success'])) { $errCode = $body['error']['code'] ?? 'UNKNOWN'; $errMsg = $body['error']['message'] ?? 'Unknown error'; $retryAfter = $body['error']['retryAfter'] ?? 1; if (in_array($errCode, ['RATE_LIMITED', 'QUEUE_TIMEOUT'], true)) { sleep((int) $retryAfter); return vibeRequest($url, $method, $data); } if ($errCode === 'BITRIX_UNAVAILABLE') { sleep(5); return vibeRequest($url, $method, $data); } throw new Exception("$errCode: $errMsg"); } return $body; } ``` ## Смотрите также - [Быстрый старт](./quickstart.md) - [Ключи и авторизация](./keys-auth.md) - [Оптимизация и batch](./optimization.md) - [Batch-запросы](./batch.md) - [CLI и cURL](./cli.md) - [MCP для AI](./mcp.md) --- # CLI и cURL Страница для тех, кто работает с API Вайбкод из терминала: скрипты для оболочки, разовые проверки утилитой `curl`, серверные интеграции на PHP без SDK. Полные справочники по операциям — на профильных страницах: [Entity API](./entity-api.md), [Фильтрация](./filtering.md), [Batch API](./batch.md), [Коды ошибок](./errors.md). Базовый URL — `https://vibecode.bitrix24.tech`. Авторизация — через заголовок `X-Api-Key`. Ответы — JSON в формате `{ success, data, meta }` при успехе и `{ success: false, error }` при ошибке. ## На странице - [Окружение](#окружение) — переменные `VIBE_API_KEY` / `VIBE_URL`, сохранение в `~/.zshrc` для использования между сессиями - [Авторизация в curl](#авторизация-в-curl) — личный ключ и ключ авторизации - [Минимальный цикл проверки](#минимальный-цикл-проверки) — создание → удаление с проверкой HTTP 204 - [Полезные приёмы curl](#полезные-приёмы-curl) — `jq`, `-s` против `-sS`, `--data-binary @file`, `read -s`, `X-RateLimit-*` - [OpenAPI-спецификация](#openapi-спецификация) — `/v1/openapi.json`, срез по скоупу и сторонняя утилита `openapi-to-cli` - [PHP](#php) — шаблон `vibeRequest` без внешних зависимостей - [Обработка ошибок](#обработка-ошибок) — формат `{ success: false, error }` ## Окружение Сохраните ключ и базовый URL в переменные окружения — это убирает повторы в каждой команде и не оставляет ключ в истории команд оболочки. ```bash export VIBE_API_KEY="vibe_api_xxx..." export VIBE_URL="https://vibecode.bitrix24.tech" ``` Проверка — должен вернуться JSON с порталом и скоупами: ```bash curl -s -H "X-Api-Key: $VIBE_API_KEY" "$VIBE_URL/v1/me" | head -c 200 ``` Чтобы переменные сохранились между сессиями, добавьте строки `export ...` в `~/.zshrc` (для оболочки `zsh`) или `~/.bashrc` (для `bash`) и перезапустите терминал. Для ключа авторизации (`vibe_app_...`) дополнительно понадобится токен сессии: ```bash export VIBE_APP_KEY="vibe_app_xxx..." export VIBE_SESSION_TOKEN="vibe_session_xxx..." ``` ## Авторизация в curl Личный ключ — один заголовок: ```bash curl -H "X-Api-Key: $VIBE_API_KEY" "$VIBE_URL/v1/deals" ``` Ключ авторизации — два заголовка, `X-Api-Key` для приложения и `Authorization: Bearer` для сессии конкретного пользователя: ```bash curl -H "X-Api-Key: $VIBE_APP_KEY" \ -H "Authorization: Bearer $VIBE_SESSION_TOKEN" \ "$VIBE_URL/v1/deals" ``` Подробнее о типах ключей и получении токена сессии — [Ключи и авторизация](./keys-auth.md). ## Минимальный цикл проверки Один сценарий, чтобы убедиться, что ключ работает и API отвечает: создать сделку → удалить. Формат вызова у остальных сущностей такой же, а набор операций и поля у каждой свои (см. [Обзор API](./entity-api.md) и [справочник сущностей](./entities-index.md)). ```bash # 1. Создать сделку — вернёт объект с присвоенным id curl -X POST "$VIBE_URL/v1/deals" \ -H "X-Api-Key: $VIBE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "CLI test", "stageId": "NEW", "categoryId": 0 }' # 2. Удалить созданную сделку — успех = HTTP 204 с пустым телом curl -i -X DELETE "$VIBE_URL/v1/deals/" \ -H "X-Api-Key: $VIBE_API_KEY" ``` Признак успеха `DELETE` — код ответа, не тело ответа. Чтобы увидеть только код: ```bash curl -s -o /dev/null -w "%{http_code}\n" -X DELETE \ -H "X-Api-Key: $VIBE_API_KEY" \ "$VIBE_URL/v1/deals/" ``` Полные примеры запросов с фильтрами, сортировкой, выбором полей и автопагинацией — на странице нужной сущности, например [Сделки](./entities/deals.md). Синтаксис фильтров (MongoDB-style, префиксы, операторы как ключи) — [Фильтрация и поиск](./filtering.md). ## Полезные приёмы curl ### Читаемый JSON в терминале `curl` выдаёт ответ одной строкой. Для просмотра подключите `jq` или `python3 -m json.tool`: ```bash curl -s -H "X-Api-Key: $VIBE_API_KEY" "$VIBE_URL/v1/deals?limit=5" | jq curl -s -H "X-Api-Key: $VIBE_API_KEY" "$VIBE_URL/v1/deals?limit=5" | python3 -m json.tool ``` ### `-s` против `-sS` в скриптах Флаг `-s` (тихий режим) подавляет индикатор прогресса вместе с сообщениями о сетевых ошибках — например, `Could not resolve host`. В скриптах это скрывает реальные сбои. Флаг `-sS` подавляет только индикатор прогресса, а текст ошибки выводится в `stderr`: ```bash # Тихо, но при сетевой ошибке скрипт молча получит пустой ответ curl -s "$VIBE_URL/v1/deals" -H "X-Api-Key: $VIBE_API_KEY" # Тихо для нормальной работы, ошибки сети видны curl -sS "$VIBE_URL/v1/deals" -H "X-Api-Key: $VIBE_API_KEY" ``` В скриптах для оболочки используйте `-sS`: ошибки сети попадут в `stderr` и не потеряются при отладке. ### Большое тело запроса через `--data-binary @file.json` При длинном теле (batch на 50 операций, импорт OpenAPI, развёрнутый фильтр) флаг `-d` не справляется с экранированием кавычек оболочки и переносами строк. Сохраните тело в файл и передайте его через `@`: ```bash cat > body.json <<'EOF' { "calls": [ { "id": "newDeals", "entity": "deals", "action": "list", "params": { "filter": { "stageId": "NEW" }, "limit": 100 } }, { "id": "user", "entity": "users", "action": "get", "entityId": 1 } ] } EOF curl -X POST "$VIBE_URL/v1/batch" \ -H "X-Api-Key: $VIBE_API_KEY" \ -H "Content-Type: application/json" \ --data-binary @body.json ``` `--data-binary` сохраняет переносы и кавычки как есть, в отличие от `-d`, который вырезает `\n`. Ответ группирует результаты по `id` каждого вызова — `results` содержит данные, `meta` — статистику пагинации, `summary` — итог по всему пакету: ```json { "success": true, "data": { "results": { "newDeals": [ { "id": 7720, "title": "Поставка серверов", "stageId": "NEW" } ], "user": { "id": 1, "name": "Иван Петров" } }, "totals": { "newDeals": 311 }, "meta": { "newDeals": { "total": 311, "returned": 100, "hasMore": true } }, "errors": [], "summary": { "total": 2, "succeeded": 2, "failed": 0 } } } ``` Полные правила batch (лимит 50 вызовов, стоимость в единицах rate-limit, поведение `action: "list"` с `limit > 50`) — [Batch API](./batch.md). ### Экспорт ключа без сохранения в истории оболочки Команда `export VIBE_API_KEY="vibe_api_..."` сохранится в `~/.zsh_history` или `~/.bash_history` — оттуда ключ может попасть на демонстрацию экрана или в резервную копию системы. Альтернатива — `read -s`: оболочка прочитает ключ без отображения на экране, в истории останется только команда `read`, без значения. ```bash read -s VIBE_API_KEY && export VIBE_API_KEY # курсор не двигается, вставляете ключ, Enter ``` Тот же приём подходит для `VIBE_APP_KEY` и `VIBE_SESSION_TOKEN`. ### Заголовки и код ответа ```bash # -i — заголовки + тело curl -i -H "X-Api-Key: $VIBE_API_KEY" "$VIBE_URL/v1/me" # -w — только выбранные поля статистики (код, время) curl -s -o /dev/null -w "HTTP %{http_code}, %{time_total}s\n" \ -H "X-Api-Key: $VIBE_API_KEY" "$VIBE_URL/v1/deals" ``` ### Лимиты запросов В заголовках ответа приходят `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` — текущий остаток лимита запросов для ключа: ```bash curl -s -D - -o /dev/null -H "X-Api-Key: $VIBE_API_KEY" "$VIBE_URL/v1/me" | grep -i ratelimit ``` ### Сохранение ответа в файл ```bash curl -s -H "X-Api-Key: $VIBE_API_KEY" "$VIBE_URL/v1/openapi.json" -o openapi.json ``` ## OpenAPI-спецификация Полный машинно-читаемый каталог эндпоинтов — `/v1/openapi.json` в формате OpenAPI 3.1: ```bash curl -s "$VIBE_URL/v1/openapi.json" -o openapi.json ``` Файл импортируется в Postman, Insomnia, Swagger UI и любые инструменты, поддерживающие OpenAPI 3.1. На основе спецификации можно генерировать клиентские библиотеки (`openapi-generator`, `oazapfts` и аналоги). Инструменту, который читает только 3.0, спецификация не подойдёт: нулевые значения в ней описаны как объединение типов (`["number","null"]`) — форма, появившаяся в 3.1. ### Срез по скоупу Параметр `?scope=<скоуп>` отдаёт спецификацию, урезанную до сущностей одного скоупа, — служебные и мета-эндпоинты остаются в любом срезе. Файл получается в разы меньше полного. Применяйте срез, когда инструмент или модель работают с одним разделом: ```bash curl -s "$VIBE_URL/v1/openapi.json?scope=crm" -o openapi-crm.json ``` Принимается ровно один известный скоуп из списка [Скоупы](/docs/scopes). Неизвестное значение и пустая строка возвращают полную спецификацию, а не ошибку. Перечисление через запятую тоже даёт полную спецификацию — кроме случая, когда все перечисленные значения сводятся к одному скоупу (`task,tasks`), тогда вернётся срез. ### Утилита `openapi-to-cli` > Сторонний инструмент, не часть API Вайбкод. Платформа не следит за его работоспособностью. За обновлениями, ошибками и совместимостью со спецификацией обращайтесь в [репозиторий автора](https://github.com/EvilFreelancer/openapi-to-cli). [`openapi-to-cli`](https://github.com/EvilFreelancer/openapi-to-cli) — CLI-утилита, которая собирает команды на основе любой OpenAPI-спецификации. Подключается к API Вайбкод без кодогенерации: указываете URL спецификации и заголовок авторизации. ```bash npm install -g openapi-to-cli ocli profile add vibecode \ --spec https://vibecode.bitrix24.tech/v1/openapi.json \ --base-url https://vibecode.bitrix24.tech \ --header "X-Api-Key: $VIBE_API_KEY" # Поиск эндпоинта по слову ocli vibecode search "deals" # Вызов ocli vibecode exec GET /v1/deals ocli vibecode exec POST /v1/deals \ --body '{ "title": "Новая сделка", "stageId": "NEW", "categoryId": 0 }' ``` Утилита сторонняя, поддерживается своим автором — за обновлениями и ошибками обращайтесь в её репозиторий. После изменений в API Вайбкод обновлённая спецификация подхватывается `ocli` при следующем запуске. ## PHP Минимальный шаблон для скриптов и серверных интеграций — без внешних зависимостей, только встроенный `curl`. Тот же шаблон подходит для всех эндпоинтов: `vibeRequest($url, $method, $data)`. ```php true, CURLOPT_CUSTOMREQUEST => $method, CURLOPT_HTTPHEADER => [ 'X-Api-Key: ' . $VIBE_API_KEY, 'Content-Type: application/json', ], ]); if ($data !== null) { curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE)); } $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); // DELETE возвращает 204 с пустым телом if ($httpCode === 204) { return ['success' => true]; } $body = json_decode($response, true); if ($body === null) { throw new RuntimeException("HTTP $httpCode: некорректный JSON в ответе"); } if (empty($body['success'])) { $code = $body['error']['code'] ?? 'UNKNOWN'; $msg = $body['error']['message'] ?? 'Неизвестная ошибка'; throw new RuntimeException("$code: $msg (HTTP $httpCode)"); } return $body; } ``` ### Примеры использования ```php // Список $result = vibeRequest("$VIBE_URL/v1/deals?limit=20"); foreach ($result['data'] as $deal) { echo $deal['id'] . ': ' . $deal['title'] . PHP_EOL; } // Создание $result = vibeRequest("$VIBE_URL/v1/deals", 'POST', [ 'title' => 'Поставка серверов', 'stageId' => 'NEW', 'categoryId' => 0, 'amount' => 1500000, 'currency' => 'RUB', ]); $dealId = $result['data']['id']; // Поиск с фильтром $result = vibeRequest("$VIBE_URL/v1/deals/search", 'POST', [ 'filter' => [ 'stageId' => ['$ne' => 'LOST'], 'amount' => ['$gte' => 100000], ], 'sort' => ['createdAt' => 'desc'], 'limit' => 50, ]); // Удаление — внутри vibeRequest 204 превращается в ['success' => true] vibeRequest("$VIBE_URL/v1/deals/$dealId", 'DELETE'); ``` Полные форматы тел запроса и поля ответа — на страницах конкретных сущностей, например [Сделки](./entities/deals.md). ## Обработка ошибок При неуспехе тело ответа имеет вид `{ success: false, error: { code, message } }` и соответствующий HTTP-статус. Пример — запрос без ключа: ```bash curl -i "$VIBE_URL/v1/deals" ``` ``` HTTP/2 401 content-type: application/json; charset=utf-8 { "success": false, "error": { "code": "MISSING_API_KEY", "message": "API key required. Pass via X-Api-Key header." } } ``` Полный справочник кодов и рекомендуемых действий — [Коды ошибок](./errors.md). ## Смотрите также - [Быстрый старт](./quickstart.md) — первый запрос за 2 минуты - [Ключи и авторизация](./keys-auth.md) — типы ключей, скоупы, лимиты, токены сессии - [Entity API](./entity-api.md) — CRUD, пагинация, выбор полей для всех сущностей - [Фильтрация и поиск](./filtering.md) — три синтаксиса фильтров с примерами - [Batch API](./batch.md) — объединение запросов, ускорение в 50 раз - [Оптимизация](./optimization.md) — паттерны для дашбордов и массовых операций - [Коды ошибок](./errors.md) — справочник по ошибкам - [MCP для AI](./mcp.md) — интеграция с AI-инструментами --- # Пакетные вызовы Один HTTP-запрос объединяет до 50 операций над разными сущностями. Каждый вызов идентифицируется собственным `id` и обрабатывается независимо: ошибка одного вызова не отменяет остальные. `POST /v1/batch` **Скоуп:** проверяется индивидуально по сущности (`crm`, `task`, `im`, `disk` и др.) | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` (APP-ключ) ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:---:|---------| | `calls` | array | ★ | Массив вызовов (от 1 до 50). Каждый элемент — объект, формат описан в таблице ниже. | ## Поля одного вызова | Поле | Тип | Обяз. | Описание | |------|-----|:---:|---------| | `id` | string | нет | Идентификатор вызова в ответе. Если не передан — присваивается порядковый индекс (`"0"`, `"1"`, ...). Длина до 64 символов. | | `entity` | string | ★ | Имя сущности во множественном числе: `deals`, `contacts`, `companies`, `tasks`, `users`, `files`, `folders` и другие. Полный список сущностей, доступных вашему ключу, возвращает `GET /v1/me` — см. [Ключи и авторизация](/docs/keys-auth). | | `action` | string | ★ | Операция: `list`, `get`, `create`, `update`, `delete`, `fields`, `search`. | | `entityId` | number / string | для `get` / `update` / `delete` | Идентификатор записи. | | `params` | object | нет | Параметры операции в едином entity-формате (имена полей в `camelCase`, фильтры в [синтаксисе фильтрации](/docs/filtering)). | Параметры внутри `params` совпадают с параметрами одиночного эндпоинта Entity API: - `list` и `search` — `filter`, `select`, `order`, `limit`. Отдельно `withTotal`: он действует только у `list` и только при нулевом `offset` (см. ниже). Переданный `select` применяется и к ответу: в записях остаются только перечисленные поля плюс `id`. Незнакомые имена перечисляются в `meta` этого вызова как предупреждения `UNKNOWN_SELECT_FIELD`. Значение `*` (и `UF_*`, в любом регистре) означает «вернуть все поля» — отбор не применяется - `get` — поле `include`, если сущность его поддерживает - `create` и `update` — поля сущности (имена в `camelCase`) - `delete` и `fields` — параметры не нужны - смарт-процессы (`entity: "items"`) — внутри `params` обязательно `entityTypeId` **Количество записей в списочном вызове.** `withTotal: false` в `params` означает «количество не нужно»: `data.totals.` и `meta..total` в ответе не приходят. Границы применимости стоит знать: параметр действует на вызовах `action: "list"` — и при `limit` не больше 50 с нулевым `offset`, и при `limit` больше 50. У `action: "search"` и у пакета одной сущности `POST /v1/{entity}/batch` он инертен — подсчёт заказывается как раньше. **Важно:** Подсчёт у Битрикс24 параметр отменяет только при `limit` не больше 50. При `limit` больше 50 подсчёт нужен платформе, чтобы спланировать обход подзапроса, поэтому там параметр убирает число, а не нагрузку. Правило присутствия `total` то же, что у одиночных эндпоинтов: на короткой странице точное количество приходит и без заказа, а у вызова с отключённым подсчётом его не будет при `offset` больше нуля — см. [Листание и количество записей](./entity-api.md#листание-и-количество-записей). Границей листания в любом случае остаётся `meta..hasMore`. **Отмена подсчёта со стороны Битрикс24 — `params.start: -1`.** Помимо `withTotal` у подкоманды есть второй, более низкоуровневый способ отказаться от счёта: значение `-1` в `params.start` — это прямая инструкция Битрикс24 «коллекцию не считать». Тогда счёта нет и в ответе портала, поэтому платформа его не публикует: ключа `total` не будет ни в `meta.`, ни в `data.totals.`. Числа взяться неоткуда, и `withTotal: true` его не вернёт — подсчёт отменил сам клиент. Исключение — [события календаря](./entities/calendar-events.md): их набор платформа получает целиком одним ответом и считает количество сама, поэтому `total` придёт и в этом режиме. Границу выборки в этом режиме определяет `meta..hasMore`, и считается она по полноте страницы, которую вернул Битрикс24: заполнена до его размера страницы — 50 записей — → `true`, короче → `false`. У `action: "list"` клиентский `limit` до Битрикс24 не доезжает, поэтому потолком остаются те же 50. Свой `limit` уходит на портал только у `action: "search"`, и там полная страница ровно на лимите (`{"action":"search","params":{"limit":10,"start":-1}}` при десяти записях) — это `hasMore: true`, а не «всё найдено». Значение читается так же, как его читает Битрикс24 — дробное усекается, строка разбирается по числовому префиксу, — поэтому `-1`, `"-1"`, `-1.5` и `"-1abc"` означают одно и то же. Положительное смещение (`start: 100`) остаётся обычным счётным курсором, `total` по нему приходит как раньше. Значение, которое числом не является вовсе (`"abc"`, пустая строка, `null`, объект, массив, `true`), читается как непереданное: страница будет та же, что и без `start`, но подкоманда попадает под общий выбор платформы и может прийти без `total`. **Важно:** `start: -1` — не курсор, а отказ от счёта: он всегда отдаёт начало коллекции, и повторный вызов с тем же значением вернёт ту же страницу. Чтобы двигаться дальше, переходите на положительное смещение (`start: 100`) — по нему `total` приходит. Проверяйте наличие ключа (`meta..total !== undefined`), а признаком непрочитанного остатка считайте `hasMore` — так код одинаково работает в обоих режимах. Идентификатор записи для `get` / `update` / `delete` передаётся в поле `entityId` на уровне вызова, **не** в `params.id`. Вызов `{ "entity": "users", "action": "get", "params": { "id": 1 } }` без `entityId` отклоняется как `MISSING_ENTITY_ID`, и вся пачка возвращает `400` с ошибкой валидации. Правильно: `{ "entity": "users", "action": "get", "entityId": 1 }`. Поле `params` у `get` служит только для `include`. Так же строятся `update` и `delete` — идентификатор в `entityId`, изменяемые поля для `update` в `params`: `{ "entity": "deals", "action": "update", "entityId": 575, "params": { "title": "Новое название" } }` и `{ "entity": "contacts", "action": "delete", "entityId": 42 }`. Успех `update` и `delete` определяется по `data.summary.succeeded` и отсутствию `id` в `data.errors`. ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/batch \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "calls": [ { "id": "deals", "entity": "deals", "action": "list", "params": { "filter": { "stageId": "NEW" }, "select": ["id", "title", "amount"], "limit": 50, "withTotal": true } }, { "id": "contacts", "entity": "contacts", "action": "list", "params": { "select": ["id", "name", "lastName"], "limit": 20, "withTotal": true } }, { "id": "user1", "entity": "users", "action": "get", "entityId": 1 } ] }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/batch \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "calls": [ { "id": "deals", "entity": "deals", "action": "list", "params": { "filter": { "stageId": "NEW" }, "select": ["id", "title", "amount"], "limit": 50, "withTotal": true } }, { "id": "contacts", "entity": "contacts", "action": "list", "params": { "select": ["id", "name", "lastName"], "limit": 20, "withTotal": true } }, { "id": "user1", "entity": "users", "action": "get", "entityId": 1 } ] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/batch', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ calls: [ { id: 'deals', entity: 'deals', action: 'list', params: { filter: { stageId: 'NEW' }, select: ['id', 'title', 'amount'], limit: 50, withTotal: true } }, { id: 'contacts', entity: 'contacts', action: 'list', params: { select: ['id', 'name', 'lastName'], limit: 20, withTotal: true } }, { id: 'user1', entity: 'users', action: 'get', entityId: 1 } ] }) }) const { data } = await res.json() console.log('Сделки:', data.results.deals) console.log('Контакты:', data.results.contacts) console.log('Сводка:', data.summary) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/batch', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify({ calls: [ { id: 'deals', entity: 'deals', action: 'list', params: { filter: { stageId: 'NEW' }, select: ['id', 'title', 'amount'], limit: 50, withTotal: true } }, { id: 'contacts', entity: 'contacts', action: 'list', params: { select: ['id', 'name', 'lastName'], limit: 20, withTotal: true } }, { id: 'user1', entity: 'users', action: 'get', entityId: 1 } ] }) }) const { data } = await res.json() console.log('Сделки:', data.results.deals) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | `true`, если запрос принят. Частичные ошибки внутри `data.errors` не переводят его в `false`. | | `data.results` | object | Результаты по `id` каждого вызова. Значение — то, что вернул бы соответствующий эндпоинт Entity API: массив записей для `list` / `search`, объект для `get` / `create`, нормализованная запись для `update`, объект `{ id, deleted: true }` для `delete`, схема полей для `fields`. | | `data.totals` | object | Общее количество записей под фильтр для `list` / `search`-вызовов. Ключи — `id` соответствующих вызовов. У `list`-вызова присутствие подчиняется тому же правилу, что `meta.total` одиночного списка: не заказал количество — ключа нет. У `search`-вызова количество заказывается всегда. Плюс своя ветка: отрицательный `params.start` отменяет подсчёт на стороне Битрикс24, и тогда числа нет даже при `withTotal: true`. Оба случая разобраны в абзацах «Количество записей в списочном вызове» и «Отмена подсчёта со стороны Битрикс24» выше. Вызова, завершившегося ошибкой, — тоже нет. | | `data.errors` | object | Ошибки по `id` неудачных вызовов. Каждое значение — `{ "code": "...", "message": "..." }`. | | `data.summary.total` | number | Общее количество вызовов в запросе. | | `data.summary.succeeded` | number | Количество успешных вызовов. | | `data.summary.failed` | number | Количество вызовов с ошибкой. | | `data.meta` | object | Дополнительные сведения по `id` вызовов с `action: "list"` или `action: "search"`: `total` (может отсутствовать — см. выше), `returned`, `hasMore`, `truncated`, а при потере страницы выборки — `pageErrorSample`. | | `data.meta..warnings` | array | Предупреждения по этому вызову. Появляется, только когда они есть. Приходят те же коды, что у одиночного эндпоинта, и в той же форме — `code`, `field`, `message`. Разбирайте массив по `code`, не по позиции. | ## Пример ответа ```json { "success": true, "data": { "results": { "deals": [ { "id": 575, "title": "Тест валюты", "amount": 0 }, { "id": 741, "title": "Поставка оборудования", "amount": 250000 } ], "contacts": [ { "id": 1, "name": "Иван", "lastName": "Петров" } ], "user1": [ { "ID": "1", "NAME": "Мария", "ACTIVE": true } ] }, "totals": { "deals": 1798, "contacts": 305 }, "errors": {}, "summary": { "total": 3, "succeeded": 3, "failed": 0 }, "meta": { "deals": { "total": 1798, "returned": 2, "hasMore": true, "truncated": false }, "contacts": { "total": 305, "returned": 1, "hasMore": true, "truncated": false } } } } ``` ## Частичные ошибки Если часть вызовов не прошла проверку или вернула ошибку на стороне Битрикс24, успешные результаты остаются в `data.results`, неудачные — в `data.errors` под тем же `id`: ```json { "success": true, "data": { "results": { "deals": [ { "id": 575, "title": "Тест валюты" } ] }, "totals": { "deals": 1798 }, "errors": { "unknown": { "code": "UNKNOWN_ENTITY", "message": "Unknown entity \"foobar\". Check GET /v1/guide for available entities." } }, "summary": { "total": 2, "succeeded": 1, "failed": 1 }, "meta": { "deals": { "total": 1798, "returned": 1, "hasMore": true, "truncated": false } } } } ``` **Пауза по лимиту приходит по отдельному вызову.** Когда метод приостановлен на несколько минут, отказ достаётся не всему пакету, а конкретному вызову — в `data.errors.` здесь и в `data[i].error` у пакета одной сущности `POST /v1/{entity}/batch`. Кодов два: [`OPERATION_TIME_LIMIT`](/docs/errors#operation_time_limit-429) — приостановлена связка «ваш ключ и этот метод», [`TIMEOUT_QUARANTINE`](/docs/errors#timeout_quarantine-429) — пауза действует на весь портал. Конверт при этом отвечает `200`, поэтому заголовка `Retry-After` для отдельного вызова у него нет. Если вызов отбила платформа, зная о действующей паузе, рядом с кодом приходят `retryAfter` в секундах, `scope` и `hint` — дождитесь срока и повторите только этот вызов. Так отбиваются вызовы, которые платформа выполняет отдельными запросами: здесь это `search` и `list`, чьё окно не умещается в одну страницу Битрикс24, а в пакете одной сущности — любой читающий вызов, то есть `list`, `get` и `fields`. Если же паузу применил сам Битрикс24 к вызову внутри общего пакетного запроса, придут только `code` и `message`: срок повтора в этом случае не приходит, поэтому повторяйте не раньше чем через пять минут. ## Пример ответа при ошибке Если все вызовы не прошли валидацию, возвращается `400 INVALID_REQUEST` с разбивкой по `id` в `data.errors`: ```json { "success": false, "error": { "code": "INVALID_REQUEST", "message": "All calls in the batch failed validation" }, "data": { "errors": { "x": { "code": "MISSING_ENTITY_ID", "message": "Action \"get\" requires entityId." } } } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_REQUEST` | Тело запроса не соответствует схеме или все вызовы провалили валидацию. | | 400 | `UNKNOWN_ENTITY` | В одном из вызовов передано неизвестное имя сущности. | | 400 | `ACTION_NOT_SUPPORTED` | Сущность не поддерживает указанное действие (например, `delete` для справочной сущности без удаления). | | 400 | `MISSING_ENTITY_ID` | Действия `get`, `update`, `delete` требуют `entityId`. | | 400 | `EMPTY_CREATE_BODY` | Вызов `create` без единого поля тела. Возвращается для конкретного вызова в `data.errors`. | | 400 | `EMPTY_UPDATE_BODY` | Вызов `update` без единого поля тела. Возвращается для конкретного вызова в `data.errors`. | | 400 | `BIZPROC_CALLBACK_BATCH_UNSUPPORTED` | Вызов `create` или `update` для `bizproc-activities` либо `bizproc-robots`, где `handler` ведёт на субдомен Black Hole. Такой обработчик регистрируется одиночным запросом. Возвращается для конкретного вызова в `data.errors`. | | 400 | `MISSING_REQUIRED_PARAMS` | В `list`-вызове `calendar-events` не переданы обязательные `type` и `ownerId` в `params`. | | 400 | `UNSUPPORTED_FILTER` | В `params.filter` вызова переданы поля, которые метод сущности не принимает как фильтр — например, `calendar-events`. | | 400 | `MISSING_DYNAMIC_PARAM` | Для смарт-процессов (`entity: "items"`) не передан `entityTypeId` внутри `params`. | | 400 | `INVALID_DYNAMIC_PARAM` | `entityTypeId` для смарт-процессов задан некорректно (не положительное целое). | | 400 | `USE_DEDICATED_ENTITY` | Для переданного `entityTypeId` существует выделенная сущность — использовать её, а не `items`. | | 400 | `ENTITY_CUSTOM_ROUTES` | Сущность работает только через специализированные маршруты (например, `task-comments` — через `/v1/tasks/:taskId/comments`). | | 400 | `INVALID_CALL` | Объект вызова не содержит обязательных полей `entity` и `action`. | | 401 | `TOKEN_MISSING` | У ключа нет настроенных OAuth-токенов или для OAuth-приложения не передан `Authorization: Bearer ...`. | | 401 | `TOKEN_REFRESH_FAILED` | Не удалось обновить OAuth-токен портала. | | 403 | `MANAGEMENT_KEY_NO_ENTITY_ACCESS` | Запрос пришёл с management-ключа — пакетные вызовы доступны только APP-ключам. | | 403 | `SCOPE_NOT_ALLOWED` | Все вызовы запросили скоупы, которых нет у ключа. Если хотя бы один вызов проходит — этот код возвращается внутри `data.errors` для конкретных вызовов, а сам запрос успешен. | | 422 | `BITRIX_ERROR` | Битрикс24 отклонил вызов. Тело ответа содержит `bitrixError.error` и `bitrixError.error_description`. | | 429 | `RATE_LIMITED` | Превышен лимит 30 запросов в минуту на портал — общий для всех его API-ключей. Ответ содержит заголовок `Retry-After`. | | 429 | `QUEUE_OVERFLOW` | На портале накопилось слишком много одновременных вызовов Битрикс24 (по умолчанию более 100 в ожидании). Ответ возвращается мгновенно с HTTP-заголовком `Retry-After: N` (секунды) — клиент должен дождаться его и повторить с экспоненциальным backoff + jitter. Тело: `error.code = QUEUE_OVERFLOW`, `error.retryAfter` дублирует заголовок. | | 429 | `QUEUE_TIMEOUT` | Запрос ожидал в очереди портала более 30 секунд. Запрос не был отправлен в Битрикс24 — безопасно повторить (`Retry-After`). Ответ содержит `userMessage` и `hint`. | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 ответил с ошибкой 5xx. | | 503 | `BITRIX_TIMEOUT` | Битрикс24 принял запрос, но не ответил за 15 секунд — исход неизвестен. Для write-вызовов внутри batch: сначала перечитайте сущность, изменение могло примениться. | | 500 | `INTERNAL_ERROR` | Внутренняя ошибка прокси. | Полный список общих ошибок API — [Коды ошибок](/docs/errors). Отказы `OPERATION_TIME_LIMIT` и `TIMEOUT_QUARANTINE` приходят по отдельному вызову внутри успешного `200` — они описаны в разделе [Частичные ошибки](#частичные-ошибки). ## Известные особенности **`search` и `list` с `limit > 50` обходят нативный пакетный вызов Битрикс24.** Эти вызовы выполняются как отдельные последовательные запросы со страничной выборкой до 5000 записей — каждый потребляет свою квоту rate-limit Битрикс24 независимо. Остальные вызовы — `list` с `limit ≤ 50`, `get`, `create`, `update`, `delete`, `fields` — объединяются в один пакетный вызов на стороне Битрикс24 и стоят одну единицу rate-limit суммарно. **Стоимость `list` в единицах rate-limit Битрикс24.** Каждые 50 записей = 1 единица. При `limit > 50` авто-пагинатор делает несколько вызовов: | `limit` | Единиц Битрикс24 | |---------|-----------------| | 1–50 | 1 (нативный batch) | | 51–2 550 | 2 | | 2 551–5 000 | 3 | **Если действие в одном вызове провалилось, остальные продолжают выполняться.** Ошибки попадают в `data.errors` под тем же `id`, успешные результаты — в `data.results`. Поле `success` остаётся `true`, проверять нужно `data.summary.failed` или присутствие нужного `id` в `data.results`. **`users.get` возвращает массив, а не объект.** Это особенность Entity API: ответ `get` для пользователей — `[ { ID, NAME, ... } ]`. Первый элемент — искомая запись. **Потеря страницы выборки при сбое подзапроса.** Если во время авто-пагинации `list` / `search`-вызова один из подзапросов страницы упал, результат обрезается до непрерывного префикса, а в `data.meta[].pageErrorSample` приходит `{ code, message }` первого сбоя. Поле `hasMore` при этом остаётся `true` — оставшиеся записи можно дозапросить. В `code` приходит либо код ошибки Битрикс24, либо код самого Вайбкод. Кодов Вайбкод сегодня три, и все означают одно: обход прервал не Битрикс24, а сам Вайбкод, и вернул непрерывное начало выборки. `KEYSET_DISCONTINUITY` — обнаружен разрыв в последовательности страниц, продолжать значило бы отдать дубли. `PAGE2_COUNT_FAILED` — не удался подсчёт записей: тайм-аут, лимит запросов или ошибка портала. `LAZY_COUNT_NO_PROGRESS` — метод вернул те же записи вместо следующих. Реакция во всех трёх случаях та же — дозапросить остаток. У двух последних кодов есть следствие для меты: `meta..total` и `data.totals.` в таком ответе отсутствуют — количество не сосчитано, и число отданных строк его не заменяет. Границей остаётся `hasMore`. **`calendar-events` в пакетном вызове.** Обязательные `type` и `ownerId` передаются в `params` вызова. Фильтр для этой сущности не поддерживается — оставшиеся поля в `params.filter` возвращают `UNSUPPORTED_FILTER`, отсутствие `type` или `ownerId` — `MISSING_REQUIRED_PARAMS`. **Выделенные сущности недоступны в пакетном вызове.** Чаты, сообщения, лента, база знаний, звонки и рабочий день обслуживаются выделенными маршрутами — вызов с `entity: "chats"`, `"messages"`, `"posts"`, `"note"`, `"calls"` или `"workday"` возвращает ошибку с указателем на нужный маршрут. Пакетный вызов поддерживает только сущности из [справочника](/docs/entity-api). Для чтения сообщений многих диалогов одним запросом используйте `POST /v1/chats/messages/bulk` — до 50 диалогов за вызов. **Обработчик действия или робота на субдомене Black Hole регистрируется одиночным запросом.** Вызов `create` или `update` для `bizproc-activities` и `bizproc-robots`, где `handler` ведёт на такой субдомен, пакетный вызов отклоняет: `BIZPROC_CALLBACK_BATCH_UNSUPPORTED` приходит в `data.errors` под `id` этого вызова. Обработчик на своём домене проходит пакетным вызовом. Форма отказа на `POST /v1/{entity}/batch`, поведение на аккаунте без надёжной доставки и что даёт одиночная регистрация — [Доставка вызовов действий и роботов](/docs/infra/bizproc-callbacks). **Пакетные операции по одной сущности.** Специализированный эндпоинт `POST /v1/{entity}/batch` работает с одной сущностью. Набор действий у каждой сущности свой: полный список — в `operations.batch` ответа `GET /v1/guide` (`data.batch` в `GET /v1/{entity}/fields` перечисляет только действия ЗАПИСИ). Действие, которого у сущности нет, отвечает `400 ACTION_NOT_SUPPORTED` — в том числе чтение, выключенное у сущности через `disabledOperations`. Для `delete` передаётся массив `ids`, для `create` и `update` — `items`, для чтений `list` / `get` / `fields` — массив `calls`. Записи идут внутренними пакетами по 50 штук, до 500 за запрос, ответ — массив результатов с пометкой `success` для каждого элемента. Для смарт-процессов путь несёт сегмент типа: `POST /v1/items/{entityTypeId}/batch`. В `list`-вызове поле `filter` проходит через транслятор фильтров — работают псевдонимы полей и операторы `$gt`, `$contains`, `$in`. Некорректный фильтр отклоняет ТОЛЬКО свой подвызов: ответ `200`, код отказа в `data[i].error.code`, остальные подвызовы выполняются. Проверяйте наличие `error` у каждого элемента `data` — как и в глобальном `POST /v1/batch`. ## Смотрите также - [Лимиты и оптимизация](/docs/optimization) - [Синтаксис фильтрации](/docs/filtering) - [Entity API](/docs/entity-api) - [Ключи и авторизация](/docs/keys-auth) - [Коды ошибок](/docs/errors) --- # Лимиты и оптимизация Вайбкод сам объединяет вызовы и пагинирует выборки на стороне сервера. Эта статья описывает встроенные механизмы и подсказывает, какой эндпоинт выбирать под задачу. **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` [Авто-пагинация](#авто-пагинация-в-list) | [Листание и количество](#листание-и-количество-записей) | [Пакетные вызовы](#пакетные-вызовы-по-нескольким-сущностям) | [Поиск по датам](#поиск-с-разбиением-по-датам) | [Агрегация](#агрегация-вместо-выборки-записей) | [Очередь портала](#очередь-портала) | [Клиентский таймаут](#клиентский-таймаут) | [Кэширование](#кэширование) | [Сводные лимиты](#сводные-лимиты) ## Авто-пагинация в `list` Параметр `limit` в `GET /v1/{entity}` принимает значения до 5000. Если `limit > 50`, Вайбкод сам разбивает выборку на внутренние страницы по 50 записей и собирает их в один ответ: ``` GET /v1/deals?limit=500&filter[stageId]=NEW ``` Возвращается до 500 записей плюс мета-поле `meta.hasMore` (и `meta.total`, если количество заказывалось — см. ниже). Если под фильтр попадает больше 5000 записей, в выборку попадают первые 5000, а `meta.hasMore` приходит `true` — для остатка нужно либо сузить фильтр, либо использовать `POST /v1/{entity}/search`. ## Листание и количество записей Это две разные задачи, и решаются они разными полями. Смешивать их — самая дорогая ошибка на списках. **Листание идёт по `meta.hasMore`.** Признак выводится из полноты страницы: пришла полная — возможно, есть ещё, пришла неполная — коллекция кончилась. Коллекция ровно кратна `limit` — последний шаг вернёт пустой список, это штатный признак конца. Поле описывает состояние отдельного ответа, а не обещает неизменяемый снимок коллекции. Если ответ метода содержит `meta.nextAfterId`, для больших обходов используйте сортировку строго по `id` по возрастанию, отключите точный подсчёт через `withTotal=false` и запросите через `select` только нужные поля вместе с `id`. Поле `meta.nextAfterId` несёт идентификатор последней отданной записи. Передайте его обратно как `filter[>id]`, и следующая страница начнётся за ним. Такой обход не зависит от смещения и не дорожает к концу коллекции: ``` GET /v1/deals?order[id]=asc&limit=50&withTotal=false&select=id,title GET /v1/deals?order[id]=asc&limit=50&withTotal=false&select=id,title&filter[>id]= ``` Курсор доступен у сделок, лидов, контактов, компаний, предложений и элементов смарт-процессов. У остальных сущностей `meta.nextAfterId` в ответе нет: страницы там берутся через `offset`, а размер выборки сокращается фильтром. Готовый цикл обхода на JavaScript — [Постраничный вывод](./filtering.md#постраничный-вывод). На внутреннем уровне этот режим следует рекомендованной схеме Битрикс24: `start=-1`, `order=ID ASC`, фильтр `ID` больше последнего полученного идентификатора. Клиент не передаёт `start` в запросе к API Вайбкод. Вайбкод применяет его только к методам, для которых подтверждена совместная работа фильтра по `id` и `start=-1`. Для остальных методов сервис сохраняет корректность вызова и может не применить режим без подсчёта. Такой обход предполагает, что записи не удаляются, а права доступа не меняются до его завершения. Если любое из условий нарушено, часть записей может быть пропущена. API Вайбкод не обещает полный обход как инвариант клиента. **Количество берётся из доступной операции агрегации.** Подсчёт коллекции стоит Битрикс24 несоразмерно дорого — заметно дороже, чем отдать страницу. Если нужна точная цифра, сначала прочитайте `operations.search.paginationStability.counting` сущности в `GET /v1/guide`. Когда указание содержит путь агрегации, спросите число одним вызовом [агрегации](#агрегация-вместо-выборки-записей) с функцией `count`. Когда указание есть, но пути нет, дешёвого точного подсчёта нет: читайте `meta.total`, только когда поле пришло, а обход ограничивайте по `meta.hasMore`. Если весь блок `counting` отсутствует вместе с общей операцией поиска, не угадывайте путь агрегации — перейдите по указателю на документацию сущности или домена из того же руководства и используйте только явно описанную операцию счёта. Не нужна цифра — отключите подсчёт параметром `withTotal=false`. У `POST /v1/{entity}/search` это одноимённое поле тела. В поддерживаемом режиме `meta.total` в ответе не придёт, а отдельный `COUNT` не выполняется. **Важно:** как приём оптимизации `withTotal=false` работает только при `limit` не больше 50 — там подсчёт действительно не заказывается. При `limit` больше 50 подсчёт нужен платформе, чтобы спланировать обход, поэтому параметр убирает число, а не нагрузку, и вдобавок отбрасывает точное количество, которое короткая первая страница отдала бы бесплатно. Если `withTotal` не передан, значение берётся из настройки `totalDefault` на API-ключе, а при её отсутствии — из платформенного умолчания. Действующее сейчас значение показывает блок `totalDefault` в [GET /v1/me](./keys-auth/me.md). Отключённый подсчёт не всегда означает отсутствие цифры: на вызове с `offset = 0`, где страница пришла короче запрошенного `limit`, точное количество известно из самой страницы и приходит бесплатно. Явный `withTotal=false` в запросе убирает и его — полная таблица присутствия поля в разделе [Листание и количество записей](./entity-api.md#листание-и-количество-записей). Обратное тоже верно: присутствие `meta.total` не означает, что за него заплатили подсчётом. На многостраничном вызове (`limit` больше 50) платформа выполняет подсчёт, только когда без него не обойтись, — форма ответа при этом не меняется, `meta.total` приходит как приходил. Отдельного действия от вас это не требует. **Не эмулируйте счётчик обходом.** Пролистать пять тысяч записей, чтобы узнать, что их 4863, — это сто вызовов вместо одного, и для учётной записи Битрикс24 это худшая из возможных нагрузок. Если операция агрегации доступна, один `aggregate` с `count` даёт ту же цифру за один вызов. `meta.total` — информативное поле. Оно может отставать от текущего состояния коллекции до минуты, поэтому число отданных строк иногда оказывается больше него. Полнота выдачи от `meta.total` не зависит. ## Пакетные вызовы по нескольким сущностям `POST /v1/batch` объединяет до 50 операций над разными сущностями в один HTTP-запрос. Каждый вызов идентифицируется собственным `id`, ошибка одного не отменяет остальные. Подходит для дашбордов и страниц-сводок, где одной загрузкой нужны данные из разных мест: ```json { "calls": [ { "id": "deals", "entity": "deals", "action": "list", "params": { "filter": { "stageId": "NEW" }, "limit": 50 } }, { "id": "tasks", "entity": "tasks", "action": "list", "params": { "filter": { "responsibleId": 1 }, "limit": 20 } }, { "id": "user", "entity": "users", "action": "get", "entityId": 1 } ] } ``` Полная спецификация — [Пакетные вызовы](/docs/batch). ## Пакетные операции по одной сущности `POST /v1/{entity}/batch` массово создаёт, обновляет или удаляет до 500 записей одной сущности. Внутри Вайбкод разбивает запрос на пакеты по 50 элементов: ```bash curl -X POST https://vibecode.bitrix24.tech/v1/deals/batch \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "action": "update", "items": [ { "id": 575, "stageId": "WON" }, { "id": 741, "stageId": "WON" } ] }' ``` Действия: `create`, `update`, `delete`, `list`, `get`, `fields`. Для `delete` передаётся массив `ids`, для `create` и `update` — `items`, для `list` / `get` / `fields` — `calls`. ## Массовое сканирование с дозагрузкой связанных данных Когда нужно прочитать тысячи записей одной сущности и подтянуть к ним связанные данные из других сущностей, поток выглядит так: 1. Выгрузить корневой список одним вызовом — Вайбкод сам пагинирует на сервере: ``` GET /v1/deals?limit=5000&select=id,title,companyId,assignedById ``` 2. Собрать `id` связанных сущностей и догрузить пакетами по 50 через `POST /v1/batch`: ```json { "calls": [ { "id": "company-15", "entity": "companies", "action": "get", "entityId": 15 }, { "id": "company-22", "entity": "companies", "action": "get", "entityId": 22 }, { "id": "user-1", "entity": "users", "action": "get", "entityId": 1 } ] } ``` Один HTTP-запрос — до 50 связанных записей. Цикл повторяется для следующего пакета `id`. В таком сценарии корневая выгрузка занимает один сетевой запрос: Вайбкод сам поднимает страницы по 50. Ассоциации догружаются в темпе один HTTP-запрос на 50 элементов вместо запроса на каждый элемент. ## Поиск с разбиением по датам `POST /v1/{entity}/search` рассчитан на крупные выборки. Если в фильтре есть условие по дате с диапазоном больше 14 дней, Вайбкод автоматически делит запрос на окна по 7 дней и обрабатывает их параллельно: ```json { "filter": { "createdAt": { "$gte": "2026-01-01", "$lte": "2026-04-30" } }, "select": ["id", "title", "stageId"], "limit": 5000 } ``` При частичном отказе окон, когда часть окон вернула данные и ответ приходит с HTTP 200, в `meta` появляются поля: | Поле | Описание | |------|---------| | `meta.autoWindowed` | `true`, когда запрос был разбит на окна по датам. | | `meta.windowCount` | Количество окон, на которые был разбит запрос. | | `meta.windowErrors` | Количество окон, по которым Битрикс24 вернул ошибку. Остальные окна возвращают свои данные. | | `meta.windowErrorSample` | Объект `{ code, message }` — код и текст первого сбойного окна, чтобы видеть причину потери данных. | | `meta.batchWaves` | Количество волн параллельной отправки окон. Приходит, когда сработала пакетная отправка окон. | | `meta.hasMore` | Есть ли записи за пределами `limit`. При выборке больше 5000 записей часть остаётся за границей — сузьте фильтр или диапазон дат. | Если упали **все** окна, этого мета-блока нет — возвращается реальный код ошибки Битрикс24, как для узкого диапазона: `UNKNOWN_FILTER_FIELD`, `INVALID_PARAMS`, `BITRIX_ACCESS_DENIED`, `RATE_LIMITED`, `BITRIX_UNAVAILABLE` или `BITRIX_TIMEOUT` (503). Отдельный код `WINDOWED_SEARCH_FAILED` больше не возвращается. Разбиение отключается флагом `"autoWindow": false` в теле запроса — применяйте его при таймаутах сети или нестабильной выдаче. Полный список параметров `search` — в документации каждой сущности. ### Неполная выдача Выдача бывает неполной и тогда, когда ни одно окно не упало. Ответ в этом случае несёт массив `meta.warnings` с записью `{ "code": "WINDOW_TRUNCATED", "field": "...", "message": "..." }`. Причин две, и называет сработавшую текст `message`: либо одно окно держало больше записей, чем возвращает одно чтение окна, либо чтения окон в сумме упёрлись в предельные 5000 записей, и оставшиеся окна не отправлялись. Код у обеих причин один — ветвиться по нему можно, не разбирая текст. Предупреждение приходит на сущностях, чей список Битрикс24 отдаёт постранично. Поле `field` называет поле диапазона исходным именем Битрикс24, а не тем, которое вы отправили: у сущностей с собственными именами полей это разные строки. Сопоставление имён — в справочнике полей сущности, например [`GET /v1/deals/fields`](./entities/deals/fields.md). Сравнивать `field` с ключами своего фильтра напрямую нельзя. Ниже — блок `meta` поиска по сделкам за два года. Массив `data` в таком ответе заполнен и содержит набранные записи: ```json { "total": 5000, "hasMore": false, "autoWindowed": true, "windowCount": 105, "batchWaves": 2, "durationMs": 41230, "warnings": [ { "code": "WINDOW_TRUNCATED", "field": "createdTime", "message": "This result is incomplete: the range filter on \"createdTime\" reached the 5000-row ceiling of a windowed search, so the remaining time windows were never requested. Narrow the date range or add filters — paging is not available on a windowed search." } ] } ``` Проверяйте `meta.warnings` до того, как считать выдачу полной. Ни `meta.hasMore`, ни `meta.total` для этого не годятся: в примере выше оба говорят, что выдача закончилась, — они описывают набранное, а не то, что осталось за границей. Пагинация тоже не спасает: при активном разбиении по датам смещение больше нуля отклоняется кодом `400 UNSTABLE_OFFSET_PAGINATION`, поэтому дочитать остаток следующей страницей не получится. Сузьте диапазон дат или добавьте фильтров, чтобы поиск перестал упираться в потолок. Поиск по узкому диапазону, который на окна не разбивается, этим предупреждением не затронут. ## Агрегация вместо выборки записей Когда нужны суммы, минимумы, максимумы или средние, сначала убедитесь, что `GET /v1/guide` показывает для сущности `operations.aggregate`. После этого `POST /v1/{entity}/aggregate` возвращает результат без отдельной выгрузки записей: ```json { "aggregate": [ { "field": "amount", "function": "sum" }, { "field": "amount", "function": "avg" } ], "filter": { "stageId": "WON" }, "groupBy": "assignedById" } ``` Ответ содержит `data.count`, `data.aggregates` и массив `data.groups` с разбивкой по полю группировки. Массив `data.groups` присутствует только при заданном `groupBy` — без него ответ ограничен одним объектом сводных значений. Для функции `count` результат возвращается одним вызовом независимо от размера выборки. Функции `sum` / `avg` / `min` / `max` подгружают записи постранично до 5000 штук — при большем объёме приходит `meta.truncated: true`. Для функции `count` действует отдельный [канон листания и количества записей](#листание-и-количество-записей). Используйте её только по пути, явно указанному в `operations.search.paginationStability.counting`. Наличие `operations.aggregate` для других функций не доказывает доступность точного счёта, и наоборот. Пример ниже применим только к явно указанному пути. Не обходите коллекцию ради подсчёта: ```json { "aggregate": [ { "field": "*", "function": "count" } ], "filter": { "stageId": "NEW" } } ``` ## Очередь портала У каждого портала Битрикс24 своя очередь к API Вайбкод: одновременно выполняется ограниченное число запросов, остальные ждут места. Если запрос провисел в очереди дольше 30 секунд, возвращается `429 QUEUE_TIMEOUT` с подсказкой `userMessage` и `hint`. Что снижает нагрузку на очередь: - Объединять разнородные обращения через `POST /v1/batch` — один HTTP-запрос вместо нескольких. - Для массового CRUD по одной сущности — `POST /v1/{entity}/batch`, до 500 записей за запрос. - Для широких выборок — `GET /v1/{entity}?limit=...` с пагинацией на стороне сервера или `POST /v1/{entity}/search` с разбивкой по датам. - Когда нужны агрегаты, а не записи, и `GET /v1/guide` показывает `operations.aggregate` — `POST /v1/{entity}/aggregate`. Точный счёт использует только путь из `operations.search.paginationStability.counting`. **Повтор при перегрузке очереди.** Под нагрузкой очередь возвращает два разных кода, и оба означают «повтори позже»: - `429 QUEUE_OVERFLOW` — очередь переполнена, запрос отклонён сразу, за миллисекунды. В заголовке `Retry-After` — рекомендованная пауза в секундах. - `429 QUEUE_TIMEOUT` — запрос ждал места дольше 30 секунд. Запрос не был отправлен в Битрикс24 — безопасно повторить. В теле `error.retryAfter` — рекомендованная пауза. Виджеты аналитики, которые шлют пачку `/search` подряд, должны делать повтор с экспоненциальной задержкой и случайным разбросом по времени, учитывая `Retry-After`, а не повторять мгновенно в цикле — это усугубляет перегрузку. Снизьте параллелизм: выполняйте запросы последовательно или объедините их в `POST /v1/batch`. ```javascript async function callWithBackoff(url, options, maxRetries = 4) { for (let attempt = 0; ; attempt++) { const res = await fetch(url, options) if (res.status !== 429) return res if (attempt >= maxRetries) return res // Оба кода (QUEUE_OVERFLOW, QUEUE_TIMEOUT) отдают паузу в заголовке Retry-After; // error.retryAfter в теле дублирует то же значение const headerWait = Number(res.headers.get('Retry-After')) const bodyWait = Number((await res.clone().json())?.error?.retryAfter) || 0 const baseSec = headerWait || bodyWait || Math.min(2 ** attempt, 30) const jitterMs = Math.floor(Math.random() * 1000) await new Promise(r => setTimeout(r, baseSec * 1000 + jitterMs)) } } ``` **Паузы по отдельному методу.** Кроме очереди запрос отбивают ещё две паузы. Обе отвечают `429` с заголовком `Retry-After` и снимаются автоматически, поэтому цикл повтора выше подходит и для них. Поле `error.scope` говорит, на кого пауза распространяется: - `429 OPERATION_TIME_LIMIT`, `scope: "apiKey"` — Битрикс24 приостановил этот метод для вашего ключа примерно на 5 минут: метод исчерпал бюджет рабочего времени на портале. Остальные методы и другие ключи портала работают. - `429 TIMEOUT_QUARANTINE`, `scope: "portal"` — метод несколько раз подряд не ответил порталу за отведённое вызову время, и пара «портал + метод» поставлена на паузу на стороне Вайбкод. Пауза действует для всех ключей портала. Не сокращайте интервал повторов: раз в 5 минут один вызов пропускается как проба восстановления, и частый повтор занимает этот слот собой — метод остаётся закрытым дольше. Механизм в процессе раскатки: пока он не включён на портале, этот код не приходит. Эти паузы измеряются минутами, а не секундами, как отказы очереди. Ждать их в пользовательском запросе не стоит — переносите повтор в фоновую задачу. Описание обоих кодов — [Ошибки](/docs/errors). ## Клиентский таймаут Ответ приходит не мгновенно: запрос сначала ждёт места в очереди портала, потом выполняется в Битрикс24. Обе фазы ограничены сверху, как и удержание соединения платформой, а таймаут на стороне клиента должен превышать сумму первых двух. | Фаза | Предел | Что приходит по истечении | |------|--------|---------------------------| | Ожидание места в очереди портала | 30 секунд | `429 QUEUE_TIMEOUT` — в Битрикс24 запрос не ушёл, повтор безопасен | | Один вызов в Битрикс24 | 15 секунд | `503 BITRIX_TIMEOUT` | | Удержание соединения платформой | 660 секунд | соединение закрывается | Отсюда рабочее значение: таймаут ожидания ответа — от 60 секунд, а не 30. Ожидание в очереди запрос проходит один раз, за себя целиком, а не за каждую страницу. Дальше запрос с `limit > 50` читает записи несколькими последовательными вызовами по 50 штук, каждый со своим пределом в 15 секунд, поэтому широкая выборка отвечает дольше одной страницы. Что помогает вместо одного длинного запроса: - Читать страницами по 50 записей и идти [курсором](#листание-и-количество-записей). Каждый вызов короткий, а прерванный обход продолжается с последнего `meta.nextAfterId`, не начиная сначала. - Задавать таймауты раздельно — на установление соединения и на ожидание данных. В Python: `requests.get(url, headers=headers, timeout=(10, 60))` — 10 секунд на соединение, 60 на ожидание данных от сервера. - Для выборок по широкому диапазону дат — [`POST /v1/{entity}/search`](#поиск-с-разбиением-по-датам): диапазон разбивается на окна, которые выполняются параллельными волнами. ## Загрузка сообщений из нескольких диалогов `POST /v1/chats/messages/bulk` возвращает сообщения не более чем из 50 диалогов в одном ответе и принимает курсоры `lastId` / `firstId` и `limit` для каждого диалога: ```json { "dialogs": [ { "dialogId": "chat253", "limit": 20 }, { "dialogId": "chat741", "lastId": 9357, "limit": 50 } ] } ``` Скоуп: `im`. Формат ответа — `{ results, errors, summary }`, аналогично `/v1/batch`. ## Кэширование Часть ответов отдаётся из кэша, чтобы повторные чтения не нагружали Битрикс24 и очередь портала. Кэш прозрачен — тело ответа совпадает с некэшированным, а заголовок `X-Cache` показывает, откуда пришёл ответ. ### Кэш ответов `/v1/users`, `/v1/statuses` и `/v1/{entity}/fields` Ответы `GET /v1/users`, `GET /v1/statuses` и `GET /v1/{entity}/fields` кэшируются на стороне сервера. Пользователи — 60 секунд. Справочники CRM и схемы полей — 5 минут. Это ускоряет дашборды, которые запрашивают эти эндпоинты при каждой загрузке. Кэш `GET /v1/users` привязан к личному ключу `vibe_api_...`. Кэш `GET /v1/statuses` привязан к порталу: личные ключи одного портала используют одну запись, потому что стадии и справочники CRM общие для портала. Кэш `GET /v1/{entity}/fields` привязан к порталу, ключу авторизации, сущности, параметрам пути, параметрам запроса и языку ответа. Полные ответы сохраняются на 5 минут. Ответы с предупреждением `fields_partial` не сохраняются, чтобы следующий запрос мог получить полную схему полей. Для ключа авторизации OAuth-приложения `vibe_app_...` кэш не используется — у разных пользователей разный доступ к данным портала. Запись через API сбрасывает соответствующий кэш сразу. `POST /v1/users`, `PATCH /v1/users/:id` и аналогичные операции сбрасывают кэш пользователей и справочников. `POST` / `PATCH` / `DELETE` на `/v1/userfields/:entity` и `/v1/items/:entityTypeId/userfields` сбрасывают кэш `GET /v1/{entity}/fields` для этой сущности или смарт-процесса. Правка напрямую в интерфейсе Битрикс24 кэшу не видна, поэтому такие изменения могут отображаться с задержкой до конца времени жизни кэша: до 60 секунд для пользователей и до 5 минут для справочников и схем полей. Чтобы получить заведомо свежие данные в обход кэша, добавьте заголовок `Cache-Control: no-cache`. Для `GET /v1/{entity}/fields` также работает параметр `refresh=true`: ```bash curl -H "X-Api-Key: YOUR_API_KEY" \ -H "Cache-Control: no-cache" \ https://vibecode.bitrix24.tech/v1/users ``` Заголовок `X-Cache` в ответе показывает, как был обработан запрос: | Значение | Что означает | |----------|--------------| | `HIT` | Ответ отдан из кэша | | `MISS` | Ответ получен из Битрикс24 и сохранён в кэш | | `COALESCED` | Запрос присоединился к уже выполняющемуся обращению за теми же данными | | `BYPASS` | Кэш не использовался — ключ авторизации OAuth-приложения, заголовок `Cache-Control: no-cache` или `refresh=true` для `/fields`. Причина указывается в заголовке `X-Cache-Bypass-Reason` | ### HTTP-кэш служебных эндпоинтов `GET /v1/openapi.json` и `GET /v1/guide` возвращают объёмные документы, которые клиенту незачем перекачивать при каждом запуске. Оба ответа несут стандартные заголовки HTTP-кэша: - `/v1/openapi.json` — `Cache-Control: public, max-age=300`. Спецификация одинакова для всех клиентов, поэтому её может хранить любой кэш. - `/v1/guide` — `Cache-Control: private, max-age=300`. Состав ответа зависит от скоупов ключа, поэтому общий кэш хранить его не должен. - `ETag` — отпечаток содержимого, меняется только при изменении документа или набора скоупов ключа. Сохраните `ETag` из первого ответа и передавайте его в заголовке `If-None-Match` при повторных запросах. Если содержимое не изменилось, эндпоинт отвечает `304 Not Modified` с пустым телом вместо повторной передачи всего документа: ```bash # Первый вызов — полное тело и ETag (openapi.json не требует авторизации) curl -i https://vibecode.bitrix24.tech/v1/openapi.json # ... ETag: "a1b2c3d4e5f6a7b8" # Повторный вызов — 304 Not Modified, тело не передаётся curl -i -H 'If-None-Match: "a1b2c3d4e5f6a7b8"' \ https://vibecode.bitrix24.tech/v1/openapi.json ``` Заголовок `max-age=300` также разрешает клиенту и промежуточному кэшу повторно использовать ответ в течение 5 минут, не обращаясь к серверу. ## Сводные лимиты | Сценарий | Ограничение | |----------|-------------| | `GET /v1/{entity}` — `limit` | до 5000 записей, при `limit > 50` — авто-пагинация на стороне Вайбкод | | `POST /v1/batch` — число вызовов | до 50 в одном запросе | | `POST /v1/{entity}/batch` — массовый CRUD | до 500 записей в одном запросе | | `POST /v1/{entity}/batch` — чтение `list` / `get` / `fields` | до 50 вызовов в массиве `calls` | | `POST /v1/{entity}/search` — `limit` | до 5000 записей, при диапазоне дат > 14 дней — окна по 7 дней | | `POST /v1/chats/messages/bulk` — диалогов | до 50 в одном запросе | | Очередь портала | ограниченное число одновременных запросов, ожидание до 30 секунд | | Кэш ответов `/v1/users` / `/v1/statuses` / `/v1/{entity}/fields` | 60 секунд / 5 минут / 5 минут, обход — заголовок `Cache-Control: no-cache`, для `/fields` также `refresh=true` | ## Смотрите также - [Batch](/docs/batch) - [Синтаксис фильтрации](/docs/filtering) - [Entity API](/docs/entity-api) - [Коды ошибок](/docs/errors) - [Быстрый старт](/docs/quickstart) --- # Бот-платформа Создавайте чат-ботов Битрикс24: регистрируйте бота, получайте сообщения и команды пользователей, отвечайте текстом, кнопками и вложениями, управляйте групповыми чатами и участниками. Не нужны вебхуки и публичный сервер — бот опрашивает события и отвечает обычными HTTP-запросами. **Скоуп:** `imbot` | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` [Какой ключ выбрать](#какой-ключ-выбрать) | [Владение ботом](#владение-ботом) | [Быстрый старт](#быстрый-старт) | [Echo-бот (пример)](#полный-пример-echo-бот) | [Коды ошибок](#коды-ошибок) | [Справочник эндпоинтов](#справочник-эндпоинтов) ## Разделы документации - [Управление ботами](/docs/bots/management) — регистрация, обновление, удаление - [События](/docs/bots/events) — опрос входящих сообщений и команд - [Сообщения](/docs/bots/messages) — отправка, редактирование, удаление, форматирование - [Чаты](/docs/bots/chats) — создание чатов, управление участниками и менеджерами - [Команды](/docs/bots/commands) — slash-команды бота - [Интерфейс](/docs/bots/ui) — реакции, индикатор набора, поле ввода - [Файлы](/docs/bots/files) — загрузка и скачивание - [Диагностика проблем](/docs/bots/troubleshooting) — что делать, если бот не получает события или возвращает ошибки - [Восстановление доступа к боту](/docs/bots/ownership-recovery) — бота нет в списке, а его код занят ## Оформление сообщений Справочники по оформлению текста при отправке и редактировании сообщений: - [Форматирование текста (BB-коды)](/docs/bots/messages/formatting) - [Клавиатура](/docs/bots/messages/keyboard) - [Вложения (ATTACH-блоки)](/docs/bots/messages/attach) --- ## Какой ключ выбрать Бот-платформа работает с двумя типами ключей. Выбор определяется тем, от чьего имени бот будет обращаться к Битрикс24. | Сценарий | Ключ | Заголовки запроса | |---------|------|-------------------| | Бот для своего портала: собственный сервер, фоновый процесс, личный скрипт | Личный API-ключ `vibe_api_…` | `X-Api-Key: vibe_api_…` | | Бот внутри OAuth-приложения, опубликованного в каталоге Вайбкод и установленного на портал | Ключ авторизации `vibe_app_…` | `X-Api-Key: vibe_app_…` + `Authorization: Bearer ` | **Личный ключ `vibe_api_…`.** Создаётся в личном кабинете Вайбкод и привязан к одному порталу Битрикс24. Все запросы идут от лица владельца ключа, дополнительный токен сессии не требуется. Подходит для одноразовых ботов, которые не публикуются как приложение. **Ключ авторизации `vibe_app_…`.** Привязан к OAuth-приложению из каталога. Каждый запрос отправляется от лица того пользователя, который установил приложение на свой портал и прошёл OAuth-авторизацию — поэтому обязателен заголовок `Authorization: Bearer `. Без Bearer бот-эндпоинты вернут `401 TOKEN_MISSING`. Подходит для ботов, которые работают от лица разных пользователей того портала, где приложение зарегистрировано. Подробное описание типов ключей, форматов и получения `session_token` — [Ключи и авторизация](/docs/keys-auth). --- ## Владение ботом Бот привязан к тому API-ключу, которым зарегистрирован. Все операции с ботом — получение событий, отправка сообщений, обновление — выполняются тем же ключом. Запрос с другого ключа возвращает `403 BOT_ACCESS_DENIED`. Это важно при деплое: если приложение развёрнуто с одним ключом, а бот создан другим, обращения к бот-эндпоинтам этим ключом не пройдут. Регистрируйте бота и работайте с ним одним и тем же ключом. Передать бота на другой ключ можно через [`POST /v1/bots/:botId/transfer`](/docs/bots/management/transfer) — например, когда исходный ключ отозван после пересоздания приложения. `botId` и история чатов при этом сохраняются. Из-за этой же привязки бот, зарегистрированный другим ключом, не приходит в `GET /v1/bots`, хотя его `code` остаётся занятым на портале. Порядок восстановления по шагам — [Восстановление доступа к боту](/docs/bots/ownership-recovery). --- ## Быстрый старт ### 1. Зарегистрируйте бота ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots \ -H "X-Api-Key: $VIBE_KEY" \ -H "Content-Type: application/json" \ -d '{ "code": "my_helper_bot", "name": "Помощник", "type": "bot", "eventMode": "fetch" }' ``` Ответ: ```json { "success": true, "data": { "botId": 42, "bot": { "id": 42, "code": "my_helper_bot", "type": "bot", "eventMode": "fetch" }, "users": [ { "id": 42, "name": "Помощник", "workPosition": "Чат-бот", "active": true, "bot": true } ] } } ``` > ID бота берите из `data.botId` — `botToken` платформа хранит сама и в ответ не возвращает. Имя бота приходит в массиве `data.users`, а не в объекте `data.bot`. ### 2. Получайте события (длинный опрос) ```bash curl -H "X-Api-Key: $VIBE_KEY" \ "https://vibecode.bitrix24.tech/v1/bots/42/events" ``` Ответ содержит `nextOffset` — передайте его как `offset` в следующем запросе: ```json { "success": true, "data": { "events": [ { "eventId": 35, "type": "ONIMBOTV2MESSAGEADD", "date": "2026-04-13T10:05:00+03:00", "data": { "dialogId": "12", "bot": { "id": 42, "code": "my_helper_bot", "type": "bot" }, "message": { "id": 1501, "chatId": 87, "authorId": 1, "date": "2026-04-13T10:05:00+03:00", "text": "Привет, бот!" }, "chat": { "id": 87, "dialogId": "12", "type": "private" }, "user": { "id": 1, "name": "Иван Петров", "firstName": "Иван", "lastName": "Петров" } } } ], "nextOffset": 36, "hasMore": false, "storedOffset": 35, "persisted": true } } ``` Следующий запрос: ```bash curl -H "X-Api-Key: $VIBE_KEY" \ "https://vibecode.bitrix24.tech/v1/bots/42/events?offset=36" ``` ### 3. Отправьте ответ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/messages \ -H "X-Api-Key: $VIBE_KEY" \ -H "Content-Type: application/json" \ -d '{ "dialogId": "12", "fields": { "message": "Привет! Чем могу помочь?" } }' ``` Ответ: ```json { "success": true, "data": { "id": 1502, "uuidMap": [] } } ``` --- ## Полный пример: Echo-бот ```javascript const VIBE_KEY = process.env.VIBE_KEY const BASE = 'https://vibecode.bitrix24.tech/v1' // ── 1. Регистрация бота ───────────────────────────────────────── const regRes = await fetch(`${BASE}/bots`, { method: 'POST', headers: { 'X-Api-Key': VIBE_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ code: 'echo_bot', name: 'Echo Bot', type: 'bot', color: 'AQUA', eventMode: 'fetch', workPosition: 'Повторяет ваши сообщения' }) }) const { data } = await regRes.json() const BOT_ID = data.botId console.log(`Bot registered with ID: ${BOT_ID}`) // ── 2. Регистрация slash-команд ───────────────────────────────── await fetch(`${BASE}/bots/${BOT_ID}/commands`, { method: 'POST', headers: { 'X-Api-Key': VIBE_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ command: 'ping', title: { ru: 'Проверить, жив ли бот', en: 'Check whether the bot is alive' } }) }) await fetch(`${BASE}/bots/${BOT_ID}/commands`, { method: 'POST', headers: { 'X-Api-Key': VIBE_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ command: 'help', title: { ru: 'Показать список команд', en: 'Show the command list' } }) }) // ── 3. Цикл опроса событий (polling) ─────────────────────────── let offset = undefined async function poll() { 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': VIBE_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 // ── Обработка сообщений ──────────────────────────────────── if (event.type === 'ONIMBOTV2MESSAGEADD') { const dialogId = data.chat.dialogId const text = data.message?.text || '' const userName = data.user?.firstName || 'друг' // Пропускаем системные сообщения и свои собственные if (data.message?.isSystem) return if (data.message?.authorId === BOT_ID) return // Показываем "думает..." await fetch(`${BASE}/bots/${BOT_ID}/typing`, { method: 'POST', headers: { 'X-Api-Key': VIBE_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ dialogId, statusMessageCode: 'IMBOT_AGENT_ACTION_THINKING' }) }) // Ставим реакцию на сообщение await fetch(`${BASE}/bots/${BOT_ID}/messages/${data.message.id}/reactions`, { method: 'POST', headers: { 'X-Api-Key': VIBE_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ reaction: 'like' }) }) // Отправляем эхо-ответ с клавиатурой await fetch(`${BASE}/bots/${BOT_ID}/messages`, { method: 'POST', headers: { 'X-Api-Key': VIBE_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ dialogId, fields: { message: `${userName}, вы написали: [I]${text}[/I]`, keyboard: [ { TEXT: 'Повторить', BG_COLOR_TOKEN: 'primary', ACTION: 'SEND', ACTION_VALUE: text || 'ping', BLOCK: 'Y' }, { TEXT: 'Помощь', BG_COLOR_TOKEN: 'secondary', ACTION: 'SEND', ACTION_VALUE: '/help', DISPLAY: 'LINE' } ] } }) }) } // ── Обработка команд ─────────────────────────────────────── if (event.type === 'ONIMBOTV2COMMANDADD') { const dialogId = data.chat.dialogId const command = data.command if (command.command === 'ping') { await fetch(`${BASE}/bots/${BOT_ID}/commands/${command.id}/answer`, { method: 'POST', headers: { 'X-Api-Key': VIBE_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ dialogId, messageId: data.message.id, fields: { message: '[B]Pong![/B] Бот работает нормально.' } }) }) } if (command.command === 'help') { await fetch(`${BASE}/bots/${BOT_ID}/commands/${command.id}/answer`, { method: 'POST', headers: { 'X-Api-Key': VIBE_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ dialogId, messageId: data.message.id, fields: { message: '[B]Echo Bot — Команды[/B]\n\n/ping — проверить, жив ли бот\n/help — показать этот список\n\nПросто напишите мне — я повторю ваше сообщение.' } }) }) } } // ── Обработка реакций ────────────────────────────────────── if (event.type === 'ONIMBOTV2REACTIONCHANGE') { const dialogId = data.chat.dialogId const userName = data.user?.firstName || 'Кто-то' if (data.action === 'add') { await fetch(`${BASE}/bots/${BOT_ID}/messages`, { method: 'POST', headers: { 'X-Api-Key': VIBE_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ dialogId, fields: { message: `${userName} поставил реакцию: ${data.reaction}`, system: true } }) }) } } // ── Вход в чат ───────────────────────────────────────────── if (event.type === 'ONIMBOTV2JOINCHAT') { await fetch(`${BASE}/bots/${BOT_ID}/messages`, { method: 'POST', headers: { 'X-Api-Key': VIBE_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ dialogId: data.chat.dialogId, fields: { message: 'Привет! Я Echo Bot. Напишите мне что-нибудь, и я повторю.\n\nКоманды:\n[SEND=/ping]Ping[/SEND] | [SEND=/help]Помощь[/SEND]' } }) }) } } poll() ``` --- ## Полный пример: Standup-бот (личный опрос → отчёт в группу) Сценарий: утром бот пишет каждому сотруднику **в личные сообщения**, собирает ответы и публикует сводку в **групповой чат**. Здесь важны два разных `dialogId` (см. [Отправить сообщение](/docs/bots/messages/send)): - **личное сообщение** — `dialogId` равен числовому ID пользователя (`"42"`) - **групповой чат** — `dialogId` имеет вид `chatXXX`. ### Где взять `dialogId` группового чата - Создать чат: `POST /v1/bots/:botId/chats` (`Chat.add`) — в ответе `data.chat.dialogId` = `chatXXX`. См. [Создать чат](/docs/bots/chats/create). - Или взять из входящего события: каждое сообщение-событие из `GET /v1/bots/:botId/events` несёт `dialogId` (для группового чата это `chatXXX`). См. [События](/docs/bots/events). ### Где взять ID участников `GET /v1/bots/:botId/chats/:dialogId/users` возвращает список участников чата, либо берите сотрудников из `GET /v1/users` (скоуп `user`). Числовой ID каждого пользователя и есть его личный `dialogId`. ### Шаги ```javascript const BASE = 'https://vibecode.bitrix24.tech/v1' const headers = { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' } // 1. Утром: личный вопрос каждому участнику (dialogId = числовой userId) async function askTeam(botId, userIds) { for (const userId of userIds) { await fetch(`${BASE}/bots/${botId}/messages`, { method: 'POST', headers, body: JSON.stringify({ dialogId: String(userId), fields: { message: 'Доброе утро! Что сделал вчера, что планируешь сегодня, что мешает в работе?' }, }), }) } } // 2. В течение дня: собираем ответы через polling. // Поля события вложены в ev.data (см. «События»): chat.dialogId, message.text, user.id. // В личном диалоге ev.data.chat.dialogId равен числовому ID отправителя — тот же // путь, что использует echo-бот выше. const answers = {} async function collect(botId, expectedUserIds) { const res = await fetch(`${BASE}/bots/${botId}/events`, { headers }) const { data } = await res.json() for (const ev of data.events ?? []) { if (ev.type !== 'ONIMBOTV2MESSAGEADD') continue const fromUser = String(ev.data.user.id) // Личный диалог: dialogId берём из ev.data.chat.dialogId if (ev.data.chat.dialogId === fromUser && expectedUserIds.includes(fromUser)) { answers[fromUser] = ev.data.message.text } } } // 3. Публикуем сводку в групповой чат (dialogId = chatXXX) async function publishReport(botId, groupDialogId, userIds) { const lines = userIds.map(id => `[b]${id}[/b]: ${answers[String(id)] ?? '— нет ответа'}`) await fetch(`${BASE}/bots/${botId}/messages`, { method: 'POST', headers, body: JSON.stringify({ dialogId: groupDialogId, // 'chat123' fields: { message: `[b]Standup за сегодня[/b]\n${lines.join('\n')}` }, }), }) } ``` **Расписание — на стороне вашего сервера.** Платформа не планирует запуски за вас: бот живёт на вашем Black Hole-сервере, поэтому утренний опрос и публикацию отчёта вызывайте по собственному расписанию (`crontab`, `node-cron` и т. п.). Опрос событий держите запущенным постоянно — см. [Echo-бот](#полный-пример-echo-бот) выше. --- ## Windows / PowerShell и UTF-8 При отправке запросов к API ботов из Windows PowerShell кириллица в `name` бота или в теле сообщения может превратиться в знаки вопроса (`?`). Это не проблема отображения на стороне сервера — кириллические байты теряются ещё до отправки HTTP-запроса, на стороне клиента. **Причина:** по умолчанию PowerShell перекодирует строку из параметра `-Body` у `Invoke-WebRequest` / `Invoke-RestMethod` в системную кодировку `windows-1251`, и кириллица теряется ещё до того, как HTTP-клиент соберёт запрос. Заголовок `Content-Type: charset=utf-8` здесь не помогает — к моменту его применения исходные байты уже потеряны при перекодировании на стороне клиента. **Решение:** передавайте тело запроса массивом байтов UTF-8. ```powershell # 1. Кодировка вывода консоли — на кодирование тела запроса не влияет [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 # 2. Собрать JSON и преобразовать его в массив UTF-8 байтов $body = @{ code = 'my_bot' name = 'Мой бот' color = 'AZURE' } | ConvertTo-Json -Compress $bytes = [System.Text.Encoding]::UTF8.GetBytes($body) # 3. Передать в -Body массив байтов (не строку!) и явно указать кодировку в Content-Type Invoke-WebRequest ` -Uri 'https://vibecode.bitrix24.tech/v1/bots' ` -Method POST ` -Headers @{ 'X-Api-Key' = $env:VIBE_KEY 'Content-Type' = 'application/json; charset=utf-8' } ` -Body $bytes ``` **Распространённые ошибки:** - Сохранять `.ps1` файл **с UTF-8 BOM** — старые версии PowerShell могут не разобрать сам скрипт. - Передавать **строку** в `-Body` (`-Body $body`) вместо массива байтов (`-Body $bytes`) — строка повторно перекодируется через системную кодировку. - Полагаться только на `Content-Type: application/json; charset=utf-8` без `UTF8.GetBytes` — этот заголовок не восстанавливает байты, потерянные при перекодировании на стороне клиента, а лишь объявляет серверу заявленную кодировку тела. **Node.js и Python работают по умолчанию** — `fetch` с JSON в теле запроса и библиотека `requests` сами кодируют тело в UTF-8, дополнительных шагов не требуется. Проблема специфична для PowerShell. --- ## Коды ошибок ### Ошибки бот-платформы | Код | HTTP | Описание | |-----|------|---------| | `SCOPE_DENIED` | 403 | API-ключ не имеет скоупа `imbot` | | `TOKEN_MISSING` | 401 | API-ключ не имеет настроенных токенов | | `CODE_REQUIRED` | 400 | Не передан параметр `code` при регистрации | | `NAME_REQUIRED` | 400 | Не передан параметр `name` при регистрации | | `INVALID_BOT_ID` | 400 | `botId` должен быть числом | | `BOT_NOT_FOUND` | 404 | Бот с таким ID не найден — зарегистрируйте через `POST /v1/bots` | | `BOT_ACCESS_DENIED` | 403 | Бот принадлежит другому API-ключу. Вернуть управление — [Восстановление доступа к боту](/docs/bots/ownership-recovery) | | `BOT_ALREADY_EXISTS` | 409 | Бот с таким `code` уже зарегистрирован. Ответ содержит `data.botId` существующего бота — тот же путь к полю, что в успешном 201. Если этого бота нет в `GET /v1/bots` — [Восстановление доступа к боту](/docs/bots/ownership-recovery) | | `REGISTRATION_FAILED` | 502 | Битрикс24 не вернул ID бота при регистрации | ### Системные ошибки | Код | HTTP | Описание | |-----|------|---------| | `MISSING_API_KEY` | 401 | Отсутствует заголовок `X-Api-Key` | | `INVALID_API_KEY` | 401 | Неверный API-ключ | | `KEY_REVOKED` | 403 | API-ключ отозван | | `RATE_LIMITED` | 429 | Превышен лимит запросов | | `BITRIX_ERROR` | 422 | Ошибка в ответе Битрикс24 API | | `BITRIX_UNAVAILABLE` | 502 | Портал Битрикс24 недоступен | | `INTERNAL_ERROR` | 500 | Внутренняя ошибка сервера | Полный список общих ошибок API — [Ошибки](/docs/errors). --- ## Справочник эндпоинтов Эта таблица — перечень возможностей бота на Вайбкод. Общий список REST-методов портала Битрикс24 для такой проверки не подходит: он неполон относительно Bot API v2, и проверка по нему сообщает об отсутствии возможности, которая работает. Разбор ситуации — [Методы Bot API v2 не видны в списке REST-методов портала](/docs/bots/troubleshooting#методы-bot-api-v2-не-видны-в-списке-rest-методов-портала). Все 37 эндпоинтов бот-платформы: | Метод | Путь | Битрикс24 метод | Описание | |-------|------|---------------|---------| | POST | [/v1/bots](/docs/bots/management/create) | imbot.v2.Bot.register | Регистрация бота | | GET | [/v1/bots](/docs/bots/management/list) | — | Список ботов | | GET | [/v1/bots/:botId](/docs/bots/management/get) | imbot.v2.Bot.get | Данные бота | | PATCH | [/v1/bots/:botId](/docs/bots/management/update) | imbot.v2.Bot.update | Обновление бота | | DELETE | [/v1/bots/:botId](/docs/bots/management/delete) | imbot.v2.Bot.unregister | Удаление бота | | POST | [/v1/bots/:botId/reauth](/docs/bots/management/reauth) | — | Повторная авторизация бота | | POST | [/v1/bots/:botId/resubscribe](/docs/bots/management/resubscribe) | imbot.v2.Bot.update | Перепривязка подписки на события | | POST | [/v1/bots/:botId/transfer](/docs/bots/management/transfer) | — | Перенос владения ботом на другой ключ | | GET | [/v1/bots/revision](/docs/bots/management/revision) | imbot.v2.Revision.get | Ревизия бот-платформы | | GET | [/v1/bots/:botId/events](/docs/bots/events/polling) | imbot.v2.Event.get | Получение событий | | POST | [/v1/bots/:botId/messages](/docs/bots/messages/send) | imbot.v2.Chat.Message.send | Отправка сообщения | | PATCH | [/v1/bots/:botId/messages/:messageId](/docs/bots/messages/update) | imbot.v2.Chat.Message.update | Обновление сообщения | | DELETE | [/v1/bots/:botId/messages/:messageId](/docs/bots/messages/delete) | imbot.v2.Chat.Message.delete | Удаление сообщения | | POST | [/v1/bots/:botId/chats/:dialogId/read](/docs/bots/messages/read) | imbot.v2.Chat.Message.read | Прочитать сообщения | | GET | [/v1/bots/:botId/messages/:messageId](/docs/bots/messages/get) | imbot.v2.Chat.Message.get | Получить сообщение | | GET | [/v1/bots/:botId/messages/:messageId/context](/docs/bots/messages/context) | imbot.v2.Chat.Message.getContext | Контекст сообщения | | POST | [/v1/bots/:botId/messages/:messageId/reactions](/docs/bots/ui/reaction-add) | imbot.v2.Chat.Message.Reaction.add | Добавить реакцию | | DELETE | [/v1/bots/:botId/messages/:messageId/reactions](/docs/bots/ui/reaction-delete) | imbot.v2.Chat.Message.Reaction.delete | Удалить реакцию | | POST | [/v1/bots/:botId/typing](/docs/bots/ui/typing) | imbot.v2.Chat.InputAction.notify | Индикатор набора | | POST | [/v1/bots/:botId/text-field](/docs/bots/ui/text-field) | imbot.v2.Chat.TextField.enabled | Управление полем ввода | | POST | [/v1/bots/:botId/chats](/docs/bots/chats/create) | imbot.v2.Chat.add | Создание чата | | GET | [/v1/bots/:botId/chats/:dialogId](/docs/bots/chats/get) | imbot.v2.Chat.get | Информация о чате | | PATCH | [/v1/bots/:botId/chats/:dialogId](/docs/bots/chats/update) | imbot.v2.Chat.update | Обновление чата | | POST | [/v1/bots/:botId/chats/:dialogId/leave](/docs/bots/chats/leave) | imbot.v2.Chat.leave | Покинуть чат | | POST | [/v1/bots/:botId/chats/:dialogId/owner](/docs/bots/chats/set-owner) | imbot.v2.Chat.setOwner | Назначить владельца | | POST | [/v1/bots/:botId/chats/:dialogId/users](/docs/bots/chats/user-add) | imbot.v2.Chat.User.add | Добавить участников | | DELETE | [/v1/bots/:botId/chats/:dialogId/users](/docs/bots/chats/user-delete) | imbot.v2.Chat.User.delete | Удалить участника | | GET | [/v1/bots/:botId/chats/:dialogId/users](/docs/bots/chats/user-list) | imbot.v2.Chat.User.list | Список участников | | POST | [/v1/bots/:botId/chats/:dialogId/managers](/docs/bots/chats/manager-add) | imbot.v2.Chat.Manager.add | Добавить менеджеров | | DELETE | [/v1/bots/:botId/chats/:dialogId/managers](/docs/bots/chats/manager-delete) | imbot.v2.Chat.Manager.delete | Удалить менеджеров | | POST | [/v1/bots/:botId/commands](/docs/bots/commands/register) | imbot.v2.Command.register | Регистрация команды | | GET | [/v1/bots/:botId/commands](/docs/bots/commands/list) | imbot.v2.Command.list | Список команд | | PATCH | [/v1/bots/:botId/commands/:commandId](/docs/bots/commands/update) | imbot.v2.Command.update | Обновление команды | | DELETE | [/v1/bots/:botId/commands/:commandId](/docs/bots/commands/delete) | imbot.v2.Command.unregister | Удаление команды | | POST | [/v1/bots/:botId/commands/:commandId/answer](/docs/bots/commands/answer) | imbot.v2.Command.answer | Ответ на команду | | POST | [/v1/bots/:botId/files](/docs/bots/files/upload) | imbot.v2.File.upload | Загрузка файла | | GET | [/v1/bots/:botId/files/:fileId](/docs/bots/files/download) | imbot.v2.File.download | Скачивание файла | --- # Инфраструктура Создание и управление виртуальными серверами для деплоя приложений Битрикс24. Каждый сервер невидим из интернета по умолчанию (режим Black Hole) — доступ к приложению только через HTTPS-субдомен `app-{id}.vibecode.bitrix24.tech`. Управление сервером и деплой — через REST API без SSH. **Скоуп:** `vibe:infra` (добавляется автоматически в каждый API-ключ) · **Базовый URL:** `https://vibecode.bitrix24.tech/v1` · **Авторизация:** заголовок `X-Api-Key` ## Разделы документации - [Провайдеры и каталоги](/docs/infra/providers) — список провайдеров, тарифов, регионов и образов ОС (4 эндпоинта). - [Серверы](/docs/infra/servers) — создание, список, детали, правка имени и описания, удаление (5 эндпоинтов). - [Жизненный цикл](/docs/infra/lifecycle) — старт, стоп, сон, пробуждение, ремонт туннеля, статус провижининга (9 эндпоинтов). - [Пробуждение по расписанию](/docs/infra/wake-schedules) — окна автоматического пробуждения спящего сервера по cron-расписанию (4 эндпоинта). - [Доступ и режимы](/docs/infra/access) — политика доступа, список пользователей/отделов, SSH-данные, режим BLACKHOLE↔OPEN (7 эндпоинтов). - [Deploy API](/docs/infra/deploy) — выполнение команд, загрузка файлов, деплой приложения, логи, порт, метрики, лок, рантаймы (8 эндпоинтов). - [Токены доступа](/docs/infra/access-tokens) — краткосрочные токены для e2e-проверки и распространяемых ссылок (4 эндпоинта, раздел включается на стороне платформы). - [Что приходит в приложение](/docs/infra/app-runtime) — Gateway подставляет `X-Vibe-Authorization: Bearer`, чтение данных пользователя через `/v1/me`, скелеты обработчика на Node/Python/Go. - [Подписки на события портала](/docs/infra/event-subscriptions) — доставка событий Битрикс24 (`ONTASKADD` и подобных) в приложение через туннель, без опроса (3 эндпоинта). - [Доставка вызовов действий и роботов](/docs/infra/bizproc-callbacks) — обработчик действия или робота на субдомене Black Hole: очередь вызовов, пробуждение спящего сервера, регистрация одиночным запросом. - [Galaxy-приложение](/docs/infra/galaxy) — режим размещения «контейнер в общей галактике»: как отличить от обычного сервера (`kind`), жизненный цикл со сборкой при загрузке кода, стоимость за галактику. - [Восстановление доступа к серверу](/docs/infra/server-access-recovery) — сервер работает, но новый ключ его не видит: пустой список, `404 NOT_FOUND`, смена управляющего ключа. ## Что важно знать сразу 1. **Порт приложения — всегда 3000.** Black Hole туннель проксирует ровно этот порт, менять его не нужно. Сервер — изолированное окружение: `:3000` внутри виртуальной машины никак не связан с портами вашей локальной машины. 2. **Deploy API — только для BLACKHOLE.** Все `/deploy`, `/exec`, `/upload`, `/logs` требуют серверов в режиме `BLACKHOLE` со статусом `CONNECTED` для агента туннеля. Для OPEN-серверов они вернут ошибку. 3. **`/deploy` и `/exec` отдают JSON по умолчанию.** Это безопасно для AI-агентов и MCP-клиентов — никаких дополнительных параметров запроса не нужно. Если вам действительно нужен потоковый ответ (вывод шагов деплоя в реальном времени в UI), передайте `?stream=true` — тогда вернётся SSE (Server-Sent Events). Раньше документация утверждала обратное (по умолчанию SSE, `?stream=false` для JSON) — это устарело и больше не соответствует поведению API. 4. **`accessPolicy` — это безопасность.** Смена политики с `OWNER_ONLY` на `PORTAL`/`AUTHENTICATED`/`PUBLIC` открывает приложение другим пользователям. **Никогда не меняйте `accessPolicy` без явного подтверждения пользователя.** 5. **Сервер — это чистая Ubuntu 24.04, рут-доступ включён.** Виртуальная машина создаётся из стандартного образа Ubuntu без предустановленного ПО (кроме агента туннеля). Агент работает от имени пользователя `root` — в `preStart`, `install` и командах `/exec` `sudo` не нужен. Исходящий интернет доступен без ограничений: `apt-get`, `curl`, `wget`, `pip` работают напрямую. Входящий трафик заблокирован кроме туннельного соединения. **Само приложение при этом запускается не от `root`, а под выделенной непривилегированной учётной записью** — это касается только процесса приложения, команды деплоя и `/exec` по-прежнему выполняются с правами администратора. Подробности и как отключить — [Деплой приложения](/docs/infra/deploy/deploy). 6. **Тариф Битрикс24 играет двойную роль.** Во-первых, REST API самого Битрикс24 доступен только на коммерческих тарифах портала — без этого не работают ни приложения, ни прокси `/v1/deals`, ни боты, ни любой другой вызов, который проксируется в Битрикс24. Во-вторых, поверх этого — создание серверов, деплой и пробуждение требуют активной подписки BitrixGPT + Маркетплейс на портале. AI Router работает независимо от тарифа Битрикс24 — он не проксирует в REST и доступен даже на бесплатных тарифах (BYOK бесплатно, платформенные модели тарифицируются с баланса Вайбкод). Подробности — в разделе «Тариф и доступ» ниже. 7. **Авторизация пользователя в приложении.** На каждом запросе Gateway проставляет шесть заголовков с префиксом `X-Vibe-`: `Request-Id` всегда плюс `User-Id`, `User-Name`, `User-Role`, `Portal-Id`, `Authorization` (`Bearer vibe_session_<…>`) для аутентифицированного запроса. Браузер `Authorization`-токен не видит и не хранит — он живёт только между Gateway и app-сервером. Для быстрого идентификатора пользователя достаточно заголовка `X-Vibe-User-Id`. Полный контекст (скоупы, `capabilities`, тариф, информация о приложении) — одним вызовом `GET /v1/me` с серверным кэшированием. ID пользователя в ответе `/v1/me` — `data.currentUser.bitrixUserId`, домен портала — `data.portal`. Полная таблица заголовков, BFF-паттерн и скелеты обработчика на Node/Python/Go — [Что приходит в приложение](/docs/infra/app-runtime). 8. **Создание серверов требует пользовательской сессии для ключей `vibe_app_`.** `POST /v1/infra/servers` проходит тарифную проверку, которой нужно знать, кто именно создаёт сервер. Для `vibe_api_` пользовательский контекст уже есть в самом ключе, для `vibe_app_` обязателен `Authorization: Bearer ` — без него ответ `401 UNAUTHENTICATED` с `error.hint`, указывающим на OAuth-флоу. Чтение и Deploy API на уже существующих серверах сессии не требуют — таблица «Авторизация эндпоинтов» ниже сводит все правила в одном месте. ## Быстрый старт Три вызова — создание сервера и запуск приложения. ### curl — личный ключ ```bash export VIBE_KEY="YOUR_API_KEY" # 1. Создать сервер (автоматически в режиме Black Hole) curl -X POST https://vibecode.bitrix24.tech/v1/infra/servers \ -H "X-Api-Key: $VIBE_KEY" \ -H "Content-Type: application/json" \ -d '{ "provider": "bitrix-cloud", "name": "my-app", "plan": "bc-small", "region": "ru-central1-b", "image": "fd83esfomhq25p2ono90" }' # 2. Отдельная виртуальная машина — дождаться готовности: # status=running И blackholeStatus=CONNECTED. # Galaxy-приложение (kind=GALAXY_APP в ответе шага 1) этого состояния # не достигает — переходите к шагу 3 сразу, см. примечание ниже. curl -H "X-Api-Key: $VIBE_KEY" \ https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID # 3. Задеплоить приложение (JSON — режим по умолчанию). # Пример ниже — для отдельной виртуальной машины: код берётся # по внешнему адресу. Galaxy-приложение принимает только встроенный # архив — "source": { "content": "" }, см. примечание выше. # X-Skip-Source-Snapshot: деплой с внешнего URL при включённом # хранилище исходников, иначе 409 SNAPSHOT_REQUIRED (см. ниже). curl -X POST "https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/deploy" \ -H "X-Api-Key: $VIBE_KEY" \ -H "Content-Type: application/json" \ -H "X-Skip-Source-Snapshot: deploy from external URL" \ -d '{ "source": { "url": "https://github.com/user/app/archive/main.tar.gz" }, "runtime": "node20", "install": "cd /opt/app && npm install --production", "start": "cd /opt/app && node server.js", "port": 3000 }' ``` Приложение доступно по адресу `https://app-{id}.vibecode.bitrix24.tech` — поле `appUrl` в ответе `/deploy`. **Деплой с внешнего URL и хранилище исходников.** Когда на портале включено [хранилище исходников](/docs/source-storage), деплой с внешнего адреса — не из хранилища Вайбкод — возвращает `409 SNAPSHOT_REQUIRED`, чтобы история версий приложения не терялась. Заголовок `X-Skip-Source-Snapshot: <причина>` продолжает деплой без сохранения снимка. Чтобы снимок сохранился, сначала загрузите архив через `POST /v1/apps/:id/sources`, затем разверните его через `{ "source": { "versionId": "vN" } }`. Подробнее — [Хранилище исходников](/docs/source-storage). ### curl — OAuth-приложение ```bash # То же самое, только добавляется заголовок Authorization: Bearer с токеном сессии curl -X POST https://vibecode.bitrix24.tech/v1/infra/servers \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "provider": "bitrix-cloud", "name": "my-app", "plan": "bc-small", "region": "ru-central1-b", "image": "fd83esfomhq25p2ono90" }' ``` > **Galaxy-приложение — другой контракт.** Если портал размещает приложения в галактиках, тот же `POST /v1/infra/servers` создаёт galaxy-приложение — контейнер на общем хосте. В ответе создания у него `kind` равен `GALAXY_APP`, а `createdVia` — `galaxy`. Такое приложение до `blackholeStatus: "CONNECTED"` не доходит: контейнер собирается загрузкой кода, поэтому шаг 2 для него отпадает, а код загружают **сразу после создания**. Источник кода при этом — встроенный архив в base64, поле `source.content`; вариант `source.url` доступен там, где платформа включила для вас выкладку по ссылке (иначе `400 GALAXY_DEPLOY_CONTENT_ONLY`), а `source.versionId` на создании не принимается — сохранённую версию выкладывают вторым шагом, через `POST /v1/infra/servers/:id/deploy`. Поля `runtime` и `start` обязательны. Нужна именно отдельная виртуальная машина — передайте в теле создания поле `placement` равным `dedicated`. Полная модель, жизненный цикл, стоимость и отличия деплоя — [Galaxy-приложение](./infra/galaxy). ## Полный пример Реалистичный сценарий на JavaScript — создание сервера, ожидание готовности, деплой, получение URL приложения. ```javascript const VIBE_KEY = process.env.VIBE_KEY const BASE = 'https://vibecode.bitrix24.tech/v1' async function api(method, path, body = null, extraHeaders = {}) { const opts = { method, headers: { 'X-Api-Key': VIBE_KEY, ...extraHeaders } } if (body) { opts.headers['Content-Type'] = 'application/json' opts.body = JSON.stringify(body) } const res = await fetch(`${BASE}${path}`, opts) if (!res.ok) throw new Error(`${method} ${path} → ${res.status}`) return res.json() } // 1. Выбрать провайдера, тариф, регион, образ const { data: plans } = await api('GET', '/infra/providers/bitrix-cloud/plans') const { data: regions } = await api('GET', '/infra/providers/bitrix-cloud/regions') const { data: images } = await api('GET', '/infra/providers/bitrix-cloud/images') const plan = plans.find(p => p.id === 'bc-small') const region = regions.find(r => r.id === 'ru-central1-b') const image = images[0] // 2. Создать сервер (всегда в Black Hole) const { data: server } = await api('POST', '/infra/servers', { provider: 'bitrix-cloud', name: 'my-crm-bot', plan: plan.id, region: region.id, image: image.id, }) console.log(`Сервер создан: ${server.id}, субдомен: ${server.subdomain}`) // 3. Отдельная виртуальная машина: ждать running и CONNECTED. // Galaxy-приложение (kind === 'GALAXY_APP') этого состояния не достигает — // для него шаг пропускается, код загружается сразу. let info = server if (server.kind === 'STANDALONE') { while (info.status !== 'running' || info.blackholeStatus !== 'CONNECTED') { await new Promise(r => setTimeout(r, 10000)) // 10 секунд между опросами const res = await api('GET', `/infra/servers/${server.id}`) info = res.data console.log(`status=${info.status}, blackhole=${info.blackholeStatus}`) } } // 4. Задеплоить приложение (JSON — режим по умолчанию). // Источник кода ниже — внешний адрес, это вариант для отдельной // виртуальной машины. Для galaxy-приложения (kind === 'GALAXY_APP') // источник только встроенный: source: { content: '' }. // Заголовок X-Skip-Source-Snapshot нужен при деплое с внешнего URL, // когда включено хранилище исходников — иначе 409 SNAPSHOT_REQUIRED. const deploy = await api('POST', `/infra/servers/${server.id}/deploy`, { source: { url: 'https://github.com/user/app/archive/main.tar.gz' }, runtime: 'node20', install: 'cd /opt/app && npm install --production', preStart: 'cd /opt/app && npx prisma migrate deploy', start: 'cd /opt/app && node server.js', port: 3000, env: { NODE_ENV: 'production' }, }, { 'X-Skip-Source-Snapshot': 'deploy from external URL' }) console.log(`Приложение живёт: ${deploy.data.appUrl}`) // 5. (Опционально) Настроить авто-сон через 60 минут простоя await api('PATCH', `/infra/servers/${server.id}/sleep`, { sleepAfterMinutes: 60 }) ``` ## Справочник эндпоинтов Справочник эндпоинтов раздела. Ссылки ведут на страницы с параметрами, примерами и кодами ошибок. **Провайдеры и каталоги:** | Метод | Путь | Описание | |-------|------|----------| | GET | [`/v1/infra/providers`](/docs/infra/providers/list) | Список облачных провайдеров | | GET | [`/v1/infra/providers/:providerId/plans`](/docs/infra/providers/plans) | Тарифы провайдера | | GET | [`/v1/infra/providers/:providerId/regions`](/docs/infra/providers/regions) | Регионы провайдера | | GET | [`/v1/infra/providers/:providerId/images`](/docs/infra/providers/images) | Образы ОС | **Серверы:** | Метод | Путь | Описание | |-------|------|----------| | POST | [`/v1/infra/servers`](/docs/infra/servers/create) | Создать сервер (всегда Black Hole) | | GET | [`/v1/infra/servers`](/docs/infra/servers/list) | Список ваших серверов | | GET | [`/v1/infra/servers/:id`](/docs/infra/servers/get) | Детали сервера | | PATCH | [`/v1/infra/servers/:id`](/docs/infra/servers/update) | Обновить имя и описание | | DELETE | [`/v1/infra/servers/:id`](/docs/infra/servers/delete) | Удалить сервер | **Жизненный цикл:** | Метод | Путь | Описание | |-------|------|----------| | POST | [`/v1/infra/servers/:id/start`](/docs/infra/lifecycle/start) | Запустить остановленный/спящий сервер | | POST | [`/v1/infra/servers/:id/stop`](/docs/infra/lifecycle/stop) | Остановить работающий сервер | | POST | [`/v1/infra/servers/:id/reboot`](/docs/infra/lifecycle/reboot) | Перезагрузить сервер | | POST | [`/v1/infra/servers/:id/wake`](/docs/infra/lifecycle/wake) | Разбудить спящий сервер (асинхронно или блокирующе) | | POST | [`/v1/infra/servers/:id/sleep-now`](/docs/infra/lifecycle/sleep-now) | Немедленно усыпить BLACKHOLE-сервер | | PATCH | [`/v1/infra/servers/:id/sleep`](/docs/infra/lifecycle/sleep) | Настроить авто-засыпание | | POST | [`/v1/infra/servers/:id/refresh`](/docs/infra/lifecycle/refresh) | Запросить статус и IP у провайдера | | POST | [`/v1/infra/servers/:id/repair`](/docs/infra/lifecycle/repair) | Восстановить туннель через serial console | | GET | [`/v1/infra/servers/:id/repair-status`](/docs/infra/lifecycle/repair-status) | Прогресс восстановления туннеля | **Пробуждение по расписанию:** | Метод | Путь | Описание | |-------|------|----------| | GET | [`/v1/infra/servers/:id/wake-schedules`](/docs/infra/wake-schedules/list) | Список окон пробуждения и историю запусков | | POST | [`/v1/infra/servers/:id/wake-schedules`](/docs/infra/wake-schedules/create) | Создать окно пробуждения | | PATCH | [`/v1/infra/servers/:id/wake-schedules/:scheduleId`](/docs/infra/wake-schedules/update) | Обновить окно пробуждения | | DELETE | [`/v1/infra/servers/:id/wake-schedules/:scheduleId`](/docs/infra/wake-schedules/delete) | Удалить окно пробуждения | **Доступ и режимы:** | Метод | Путь | Описание | |-------|------|----------| | GET | [`/v1/infra/servers/:id/ssh`](/docs/infra/access/ssh) | SSH-данные (только для OPEN) | | PATCH | [`/v1/infra/servers/:id/mode`](/docs/infra/access/mode) | Переключить BLACKHOLE↔OPEN | | PATCH | [`/v1/infra/servers/:id/access-policy`](/docs/infra/access/access-policy) | Политика доступа к приложению | | GET | [`/v1/infra/servers/:id/access`](/docs/infra/access/access-list) | Список пользователей и отделов доступа | | POST | [`/v1/infra/servers/:id/access`](/docs/infra/access/access-add) | Добавить пользователя или отдел | | DELETE | [`/v1/infra/servers/:id/access/:accessId`](/docs/infra/access/access-delete) | Удалить запись доступа | | GET | [`/v1/infra/servers/:id/b24-users`](/docs/infra/access/b24-users) | Поиск пользователей портала Битрикс24 | **Deploy API:** | Метод | Путь | Описание | |-------|------|----------| | POST | [`/v1/infra/servers/:id/exec`](/docs/infra/deploy/exec) | Выполнить команду (SSE или JSON) | | POST | [`/v1/infra/servers/:id/upload`](/docs/infra/deploy/upload) | Загрузить файл (base64 или по URL) | | GET | [`/v1/infra/servers/:id/logs`](/docs/infra/deploy/logs) | Логи сервиса (утилита `journalctl`) | | POST | [`/v1/infra/servers/:id/deploy`](/docs/infra/deploy/deploy) | Полный деплой приложения | | GET | [`/v1/infra/operations/:operationId`](/docs/infra/deploy/operation-status) | Исход выкладки по идентификатору операции | | PATCH | [`/v1/infra/servers/:id/port`](/docs/infra/deploy/port) | Задать порт приложения | | GET | [`/v1/infra/servers/:id/metrics`](/docs/infra/deploy/metrics) | Метрики активности туннеля | | DELETE | [`/v1/infra/servers/:id/lock`](/docs/infra/deploy/lock) | Снять зависший лок операции | | GET | [`/v1/infra/runtimes`](/docs/infra/deploy/runtimes) | Список доступных рантаймов | **Токены доступа:** | Метод | Путь | Описание | |-------|------|----------| | POST | [`/v1/infra/servers/:id/access-tokens`](/docs/infra/access-tokens/create) | Выпустить токен доступа (`api-bearer` или `share-url`) | | POST | [`/v1/infra/servers/:id/access-tokens/:tokenId/refresh`](/docs/infra/access-tokens/refresh) | Выпустить свежий JWT для того же токена `api-bearer` | | GET | [`/v1/infra/servers/:id/access-tokens`](/docs/infra/access-tokens/list) | Список токенов сервера | | DELETE | [`/v1/infra/servers/:id/access-tokens/:tokenId`](/docs/infra/access-tokens/delete) | Отозвать токен | **Подписки на события портала:** | Метод | Путь | Описание | |-------|------|----------| | POST | [`/v1/infra/servers/:id/event-subscriptions`](/docs/infra/event-subscriptions) | Подписать сервер на событие портала (`event.bind` под OAuth-приложением) | | GET | [`/v1/infra/servers/:id/event-subscriptions`](/docs/infra/event-subscriptions) | Список подписок + недавние доставки | | DELETE | [`/v1/infra/servers/:id/event-subscriptions/:subId`](/docs/infra/event-subscriptions) | Снять подписку | ## Авторизация эндпоинтов Все инфра-эндпоинты требуют заголовок `X-Api-Key`. Для ключей `vibe_app_` (привязка к OAuth-приложению) часть POST-операций дополнительно требует `Authorization: Bearer ` — без него ответ `401 UNAUTHENTICATED` с `error.hint`. Для ключей `vibe_api_` пользовательский контекст уже есть в самом ключе, отдельная сессия не нужна. | Эндпоинт | `X-Api-Key` | `Authorization: Bearer` для `vibe_app_` | Когда требует Bearer | |----------|:-----------:|:--------------------------------------:|----------------------| | `GET /v1/infra/providers/*` | да | нет | — | | `GET /v1/infra/servers`, `GET /v1/infra/servers/:id` | да | нет | — | | `GET /v1/infra/servers/:id/logs`, `/metrics`, `/access`, `/b24-users`, `/ssh` | да | нет | — | | `GET /v1/infra/runtimes` | да | нет | — | | `POST /v1/infra/servers` (создать сервер) | да | **да** | Тарифная проверка: платформе нужно знать, кто именно создаёт сервер. | | `POST /v1/infra/servers/:id/deploy`, `/exec`, `/upload` | да | нет | Достаточно скоупа `vibe:infra` на ключе. | | `POST /v1/infra/servers/:id/start`, `/stop`, `/reboot`, `/wake`, `/sleep-now`, `/refresh`, `/repair`, `PATCH /sleep` | да | нет | — | | `GET /v1/infra/servers/:id/wake-schedules` | да | нет | — | | `POST /v1/infra/servers/:id/wake-schedules`, `PATCH .../wake-schedules/:scheduleId` | да | нет | Требует включённого пробуждения по расписанию на портале, иначе `403 WAKE_SCHEDULE_DISABLED`. Если на портале возможность включена, а сервер — приложение в галактике, приходит `403 WAKE_SCHEDULE_GALAXY_DISABLED`: для таких приложений её включают отдельно от обычных серверов. | | `DELETE /v1/infra/servers/:id/wake-schedules/:scheduleId` | да | нет | Удаление окна этими условиями не ограничено — окно можно снять и после того, как пробуждение по расписанию отключили на портале или для приложений галактики. | | `PATCH /v1/infra/servers/:id/mode`, `/access-policy`, `/port` | да | нет | — | | `POST /v1/infra/servers/:id/access`, `DELETE /v1/infra/servers/:id/access/:accessId` | да | нет | — | | `POST/GET /v1/infra/servers/:id/access-tokens`, `DELETE .../:tokenId`, `POST .../:tokenId/refresh` | да | нет | Раздел токенов доступа должен быть включён на платформе, иначе все четыре эндпоинта отвечают `503 FEATURE_DISABLED`. Проверка до вызова — `data.capabilities.servers.preview` в [`GET /v1/me`](/docs/keys-auth/me). | | `POST/GET/DELETE /v1/infra/servers/:id/event-subscriptions` | да | нет | Сервер должен быть привязан к OAuth-приложению с `application_token`, иначе `400 NOT_OAUTH_APP`. | | `PATCH /v1/infra/servers/:id` (имя и описание) | да | нет | — | | `DELETE /v1/infra/servers/:id` | да | нет | — | | `DELETE /v1/infra/servers/:id/lock` | да | нет | — | Быстрая проверка до вызова: `GET /v1/me` → `data.capabilities.servers.create.available`. Для `vibe_app_` без сессии возвращается `false` с `reason: "SESSION_REQUIRED"` и подсказкой в `userMessage` — модель сразу видит, что нужно пройти OAuth-флоу, а не ловить `401` на самом `POST /v1/infra/servers`. ## Лимиты | Лимит | Значение | |-------|----------| | Серверов на API-ключ | 100. В счёт идут только отдельные виртуальные машины, созданные этим ключом — приложения в галактике и сами машины-галактики в лимит не входят. Своё текущее значение и израсходованную часть смотрите в `GET /v1/me`: `data.infra.limits.max` и `data.infra.limits.used` | | Операций Deploy API в минуту на сервер | 10 | | Одновременных `exec`/`deploy` на сервер | 1 | | Таймаут `exec` | 1–600 секунд (по умолчанию 300) | | Размер base64-тела (`upload` inline, `source.content`) | 500 МБ | | Размер файла через `source.url` / `upload url` | 500 МБ | | Размер multipart-архива в `deploy` | 500 МБ | | Частота запросов `/ssh` | до 10 в минуту | Ограничение частоты запросов платформы — общее для всех V1-эндпоинтов, [см. раздел «Лимиты и оптимизация»](/docs/optimization). ## Статусы сервера | Статус | Описание | |--------|----------| | `provisioning` | Виртуальная машина создаётся у провайдера (1–3 минуты) | | `running` | Виртуальная машина запущена, IP назначен. Для туннеля нужен ещё `blackholeStatus: CONNECTED` | | `sleeping` | Остановлен по таймеру сна или вручную. Просыпается при вызове `/deploy`/`/start`/`/wake`, а обращение к HTTPS-субдомену будит его на [условиях автоматического пробуждения](/docs/infra/lifecycle/wake) | | `error` | Сервер не в рабочем состоянии: виртуальная машина удалена у провайдера, агент долго не подключается, внешний `externalId` отсутствует | | `deleted` | Сервер удалён (пометка на удаление). Нельзя восстановить | Поле `blackholeStatus` описывает состояние туннеля агента независимо от `status`: | Значение | Описание | |----------|----------| | `NONE` | Сразу после создания сервера, до первой попытки подключения агента | | `WAITING` | Агент готовится к подключению | | `CONNECTED` | Туннель активен, Deploy API доступен | | `DISCONNECTED` | Агент был подключён, сейчас нет связи — попробуйте [`/repair`](/docs/infra/lifecycle/repair) | Поле `kind` различает модель размещения: `STANDALONE` — отдельная виртуальная машина, `GALAXY_APP` — galaxy-приложение (контейнер в галактике), `GALAXY` — сама галактика (хост-носитель — её создаёт платформа, не пользователь). У galaxy-приложения `blackholeStatus` остаётся `NONE` до загрузки кода — оно не подключается само. Подробнее — [Galaxy-приложение](/docs/infra/galaxy). Поле `runtimeStatus` — устаревшее, оставлено для совместимости. Для серверов, созданных после 2026-04-25 (когда параметр `runtime` был убран из [`POST /v1/infra/servers`](/docs/infra/servers/create)), всегда возвращается `null`. Рантайм теперь ставится на этапе [`POST /:id/deploy`](/docs/infra/deploy/deploy), а сигналом готовности служит сам успех шага `runtime` в ответе деплоя. ## Тариф и доступ У инфраструктуры Вайбкод два уровня условий по доступу. **Уровень 1 — REST API Битрикс24.** Сам Битрикс24 открывает REST API только на коммерческих тарифах портала. Это не про Вайбкод: на бесплатных тарифах Битрикс24 попросту не отдаёт REST-ответы. Значит, без коммерческого тарифа Битрикс24 не работают: - Создание и публикация приложений (`POST /api/apps`) — регистрируется на портале через REST. - REST-прокси: `/v1/deals`, `/v1/contacts`, `/v1/batch`, `/v1/bots`, `/v1/tasks` и все остальные сущности. - Боты, чаты, задачи — всё, что проксирует в Битрикс24. **Уровень 2 — Вайбкод-инфраструктура.** Сверх первого условия, создание серверов, деплой и пробуждение требуют активной подписки BitrixGPT + Маркетплейс на портале: - `POST /v1/infra/servers` — создание сервера. - `POST /v1/infra/servers/:id/deploy` — деплой приложения. - `POST /v1/infra/servers/:id/wake` и автоматическое пробуждение при `preventWake=true`. - Создание агентов и управляемых ботов (они провижинят серверы под капотом). **Что работает на любом тарифе Битрикс24, включая бесплатный:** - AI Router — `POST /v1/chat/completions`, `POST /v1/audio/transcriptions`, `GET /v1/models`. Не проксирует в Битрикс24, напрямую ходит к провайдерам LLM. С BYOK-ключами — бесплатно, с платформенными моделями — тарифицируется с баланса Вайбкод. - Базовые эндпоинты платформы: `GET /v1/me`, `GET /v1/feedback`, `GET /v1/guide` — для самоориентации AI-агента. **Проверка до вызова:** `GET /v1/me` → поле `capabilities.servers.create.available`. Если `false` — поле `capabilities.servers.create.userMessage` содержит переведённое объяснение для пользователя. **Принудительное обновление после повышения тарифа:** `GET /v1/me?refresh=tariff` — пропускает кэш, по умолчанию часовой, и запрашивает тариф у Битрикс24 заново. **Доступ к серверам:** единственный признак — `capabilities.servers.create` в ответе `GET /v1/me` (см. выше). Если доступ закрыт, `POST /v1/infra/servers` вернёт `402` (или `403` для `REGION_NOT_SUPPORTED`) с кодом проверки доступа (см. «Коды ошибок» ниже). Доступ управляется подпиской BitrixGPT + Маркетплейс на портале. **Заголовки ответа** инфра-эндпоинтов: | Заголовок | Значение | |-----------|----------| | `X-Tariff-Checked-At` | ISO-timestamp последней сверки тарифа с Битрикс24, кэш до 1 часа | | `X-Tariff-Is-Commercial` | `"true"` или `"false"` | Коды ошибок проверки доступа перечислены в разделе «Коды ошибок» ниже. ## Windows / PowerShell и UTF-8 Кириллица в `displayName` и `description` сервера может превратиться в знаки вопроса (`?`), если запрос отправляется из Windows PowerShell без явной сериализации в UTF-8. Это не проблема отображения на стороне платформы — кириллические байты теряются ещё до отправки HTTP-запроса, на стороне клиента. **Причина.** По умолчанию PowerShell перекодирует строку из параметра `-Body` у `Invoke-WebRequest` и `Invoke-RestMethod` в системную кодировку `windows-1251`, и кириллица теряется ещё до сборки запроса. Заголовок `Content-Type: charset=utf-8` здесь не помогает — к моменту его применения исходные байты уже потеряны. **Решение.** Передавайте тело запроса массивом байтов UTF-8. ```powershell # 1. Кодировка вывода консоли — на кодирование тела запроса не влияет [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 # 2. Собрать JSON и преобразовать его в массив UTF-8 байтов $body = @{ displayName = 'Уведомления клиентов' description = 'Бот отправляет уведомления по сделкам' } | ConvertTo-Json -Compress $bytes = [System.Text.Encoding]::UTF8.GetBytes($body) # 3. Передать в -Body массив байтов, а не строку, и указать кодировку в Content-Type Invoke-WebRequest ` -Uri 'https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID' ` -Method PATCH ` -Headers @{ 'X-Api-Key' = 'YOUR_API_KEY' 'Content-Type' = 'application/json; charset=utf-8' } ` -Body $bytes ``` **Распространённые ошибки:** - Сохранять `.ps1` с UTF-8 BOM — старые версии PowerShell могут не разобрать сам скрипт. - Передавать в `-Body` строку `$body` вместо массива байтов `$bytes` — строка повторно перекодируется через системную кодировку. - Полагаться только на `Content-Type: application/json; charset=utf-8` без `UTF8.GetBytes` — этот заголовок не восстанавливает потерянные байты, а лишь объявляет серверу заявленную кодировку тела. Та же сериализация нужна везде, где вы передаёте отображаемое имя и описание: [создание сервера](/docs/infra/servers/create), [правка имени и описания](/docs/infra/servers/update) и [деплой приложения](/docs/infra/deploy/deploy) — оттуда эти значения попадают в карточку приложения в каталоге Битрикс24. **Node.js (`fetch`) и Python (`requests`)** кодируют тело в UTF-8 сами, дополнительных шагов не требуется. Проблема специфична для PowerShell. ## Коды ошибок ### Ошибки инфраструктуры | Код | HTTP | Описание | |-----|------|----------| | `NOT_FOUND` | 404 | Сервер не найден или принадлежит другому API-ключу | | `INVALID_REQUEST` | 400 | Ошибка валидации (неверное имя, тариф, регион, образ) | | `INFRA_NOT_PERMITTED` | 403 | Инфраструктура отключена на платформе или на портале | | `SERVER_CREATION_DISABLED` | 403 | Создание серверов запрещено политикой портала | | `MAX_SERVERS_REACHED` | 403 | Превышен лимит серверов на API-ключ | | `NO_CREDENTIALS` | 404 | Провайдер не сконфигурирован на платформе | | `SERVER_NOT_READY` | 409 | Сервер ещё создаётся, операция пока недоступна | | `CONFLICT` | 409 | Сервер в статусе, из которого нельзя выполнить действие (например `start` работающего) | | `PROVIDER_ERROR` | 502 | Облачный провайдер вернул ошибку | | `VM_MISSING` | 422 | У записи нет `externalId` — виртуальная машина не создана у провайдера или удалена извне. Удалите сервер через `DELETE` и создайте новый | | `PORT_RESTRICTED` | 400 | Порт 1–1023 (системные порты запрещены). Допустимы `0` (автоопределение) и `1024–65535` | | `BLACKHOLE_ONLY` | 400 | Эндпоинт работает только для BLACKHOLE-серверов (актуально для `/sleep-now`, `/sleep`, `/metrics`) | | `OPEN_MODE_NOT_ALLOWED` | 403 | Переключение в OPEN запрещено политикой портала `allowOpenMode` | | `SAME_MODE` | 400 | Сервер уже в запрошенном режиме | | `NOT_IMPLEMENTED` | 501 | Действие не поддерживается провайдером (например `/reboot` на некоторых плагинах) | | `REPAIR_BLOCKED` | 409 | Восстановление туннеля заблокировано (`preventWake=true` или сервер удалён) | ### Ошибки Deploy API | Код | HTTP | Описание | |-----|------|----------| | `SERVER_NOT_READY` | 409 | Сервер не готов к операции: не запущен, туннель не подключён, либо сервер числится подключённым, но у Gateway нет живого туннеля. В ответе — поле `hint` с причиной и следующим шагом. Платформа пытается восстановить туннель сама. Если это не удалось — разбудите сервер или вызовите [`/repair`](/docs/infra/lifecycle/repair) и повторите запрос | | `EXEC_BUSY` | 409 | На сервере уже выполняется другая операция. Используйте [`/lock`](/docs/infra/deploy/lock) для снятия зависшего лока | | `COMMAND_TOO_LONG` | 400 | Команда `/exec` длиннее 10 000 символов. Большие данные и скрипты передавайте через [`/upload`](/docs/infra/deploy/upload) | | `EXEC_TIMEOUT` | 200 | Превышен таймаут выполнения. Отказ приходит в теле ответа | | `EXEC_FAILED` | 200 | Ошибка выполнения команды на агенте. Отказ приходит в теле ответа | | `EXEC_NO_EXIT` | 200 | Поток `/exec` завершился, не прислав статус выхода: исход команды на сервере неизвестен. Отказ приходит в теле ответа, накопленный вывод — в `data`. Только на отдельной виртуальной машине (`kind: "STANDALONE"`) | | `UPLOAD_PATH_DENIED` | 403 | Запрещённый путь для загрузки | | `DEPLOY_FAILED` | 200 | Упал один из шагов деплоя — какой именно, указывает поле `error.step`. Отказ приходит в теле ответа | | `DEPLOY_TIMEOUT` | 200 | Шаг деплоя не уложился в отведённое ему время | | `DEPLOY_CONNECTION_TERMINATED` | 200 | Соединение с сервером оборвалось посреди деплоя. Деплой мог примениться частично — проверьте упавший шаг и повторите | | `DEPLOY_TUNNEL_STALE` | 200 | У Gateway нет живого туннеля для сервера. Вызовите [`/repair`](/docs/infra/lifecycle/repair) и повторите деплой | | `VALIDATION_ERROR` | 400 | Некорректное тело запроса Deploy API | У [`/exec`](/docs/infra/deploy/exec) и [`/deploy`](/docs/infra/deploy/deploy) на отдельной виртуальной машине (`kind: "STANDALONE"`) соединение удерживается на всё время работы, поэтому статус `200` уходит до её начала. Отказ во время выполнения приходит телом ответа — признаком служит `success: false`, а не HTTP-статус. Проверять надо `success`, иначе провалившаяся команда будет принята за успешную. У galaxy-приложения (`kind: "GALAXY_APP"`) та же ошибка приходит со статусом `502` — HTTP-статусы `200` в таблице выше относятся к отдельной виртуальной машине. В потоковом режиме (`?stream=true`) отказ приходит SSE-событием `error` с полями `code` и `message` — так отдаёт `/exec` и деплой при исключении или обрыве транспорта. У деплоя провал отдельного **шага** приходит иначе — событием `step` со `status: "error"` и именем шага. Поля `success` в потоке нет. ### Ошибки проверки доступа и биллинга | Код | HTTP | Описание | |-----|------|----------| | `MARKETPLACE_REQUIRED` | 402 | На портале нет активной подписки BitrixGPT + Маркетплейс — оформите её, чтобы открыть создание серверов, деплой и пробуждение | | `KZ_PAID_ONLY` | 402 | В Казахстане подписка BitrixGPT + Маркетплейс доступна только на платном тарифе (демо-доступа нет) | | `UZ_PAID_ONLY` | 402 | В Узбекистане подписка BitrixGPT + Маркетплейс доступна только на платном тарифе (демо-доступа нет) | | `REGION_NOT_SUPPORTED` | 403 | Подписка BitrixGPT + Маркетплейс пока недоступна в регионе портала | | `COMMERCIAL_PLAN_REQUIRED` | 402 | Бесплатный тариф Битрикс24 без активной подписки BitrixGPT + Маркетплейс | | `TRIAL_PORTAL_LIMIT` | 402 | Превышен лимит серверов на портал для демо-доступа RU/BY (1 сервер на портал) | | `PLAN_NOT_ALLOWED_ON_TRIAL` | 402 | Запрошенный план недоступен на демо-доступе RU/BY (разрешён только `bc-micro`) | | `ACCOUNT_FROZEN` | 402 | Баланс Вайбкод заморожен. Нужно пополнить | | `BILLING_EXHAUSTED` | 402 | Баланс Вайбкод исчерпан. Пробуждение и деплой заблокированы | | `SERVER_WAKE_BLOCKED` | 403 | Пробуждение заблокировано (не из-за биллинга: административный блок, безопасность) | ### Системные ошибки | Код | HTTP | Описание | |-----|------|----------| | `MISSING_API_KEY` | 401 | Не передан заголовок `X-Api-Key` | | `INVALID_API_KEY` | 401 | Неверный или просроченный API-ключ | | `SCOPE_DENIED` | 403 | У ключа нет скоупа `vibe:infra` | | `RATE_LIMITED` | 429 | Превышено ограничение частоты запросов. Ответ несёт заголовок `Retry-After` | | `INTERNAL_ERROR` | 500 | Внутренняя ошибка сервера | Полный справочник общих ошибок — [Ошибки](/docs/errors). ## Иконка приложения Иконка приложения (SVG) показывается в каталоге Битрикс24 и как фавикон во вкладке браузера. Формат, требования и порядок (фавикон-`` до деплоя, загрузка `POST /v1/infra/servers/:id/icon` после) — на отдельной странице [Иконка приложения](/docs/infra/app-icon). ## Рецепты - [Загрузка дампа БД на сервер](/docs/recipes/db-dump-restore) — залить дамп и восстановить базу в фоне через `exec`. - [Быстрый цикл выпуска](/docs/infra/deploy/fast-cycle) — сократить цикл правок без полного прогона всех шагов. ## Смотрите также - [Обзор API](/docs/entity-api) - [Лимиты и оптимизация](/docs/optimization) - [Ключи и авторизация (`/v1/me`)](/docs/keys-auth) - [Что приходит в приложение](/docs/infra/app-runtime) --- # Телефония Управление телефонией Битрикс24: регистрация внешних звонков в CRM, исходящие автоматические звонки и обратный звонок, прикрепление транскрипций, статистика звонков, управление линиями приложения. **Скоуп:** `telephony` | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` [Быстрый старт](#быстрый-старт) | [Полный пример](#полный-пример) | [Справочник эндпоинтов](#справочник-эндпоинтов) | [Коды ошибок](#коды-ошибок) ## Разделы документации - [Звонки в CRM](/docs/telephony/crm) — регистрация внешних звонков, завершение, карточка оператору, транскрипции - [Исходящие звонки](/docs/telephony/outbound) — обратный звонок и автоматические звонки с синтезом речи или аудиофайлом - [Линии](/docs/telephony/lines) — внешние линии приложения и список арендованных у Voximplant - [Аналитика и справочники](/docs/telephony/analytics) — статистика звонков и справочник голосов для синтеза речи --- ## Быстрый старт ### 1. Зарегистрируйте звонок ```bash curl -X POST https://vibecode.bitrix24.tech/v1/calls/register \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "userId": 1, "phoneNumber": "+79161234567", "type": 2, "crmCreate": true }' ``` Ответ (HTTP 201): ```json { "success": true, "data": { "CALL_ID": "externalCall.00b1e735843c558431be668e3687a58b.1777974304", "CRM_CREATED_LEAD": 1001069, "CRM_CREATED_ENTITIES": [{"ENTITY_TYPE": "LEAD", "ENTITY_ID": 1001069}], "CRM_ENTITY_TYPE": "LEAD", "CRM_ENTITY_ID": 1001069 } } ``` ### 2. Завершите звонок ```bash curl -X POST https://vibecode.bitrix24.tech/v1/calls/externalCall.00b1e735843c558431be668e3687a58b.1777974304/finish \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"userId": 1, "duration": 120, "statusCode": "200"}' ``` ### 3. Прикрепите транскрипцию ```bash curl -X POST https://vibecode.bitrix24.tech/v1/calls/externalCall.00b1e735843c558431be668e3687a58b.1777974304/transcription \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "messages": [ {"side": "User", "startTime": 0, "stopTime": 3, "message": "Здравствуйте, чем могу помочь?"}, {"side": "Client", "startTime": 4, "stopTime": 8, "message": "У меня вопрос по заказу"} ] }' ``` Ответ: ```json { "success": true, "data": { "TRANSCRIPT_ID": 3 } } ``` --- ## Полный пример JavaScript-скрипт обработки входящего звонка: регистрация в CRM с автосозданием лида → отображение карточки оператору → завершение → прикрепление транскрипции → проверка статистики. ```javascript const KEY = process.env.VIBE_API_KEY const BASE = 'https://vibecode.bitrix24.tech/v1' async function api(method, path, body) { const opts = { method, headers: { 'X-Api-Key': KEY } } if (body) { opts.headers['Content-Type'] = 'application/json' opts.body = JSON.stringify(body) } const res = await fetch(`${BASE}${path}`, opts) if (res.status === 204) return null return res.json() } // 1. Регистрируем внешний звонок и создаём лид, если номера ещё нет в CRM const reg = await api('POST', '/calls/register', { userId: 1, phoneNumber: '+79161234567', type: 2, crmCreate: true }) const callId = reg.data.CALL_ID console.log('Звонок зарегистрирован:', callId) console.log('Создан лид:', reg.data.CRM_CREATED_LEAD) // 2. Показываем карточку звонка оператору await api('POST', `/calls/${callId}/show`, { userId: 1 }) // 3. Завершаем звонок (длительность 245 секунд, успех) const fin = await api('POST', `/calls/${callId}/finish`, { userId: 1, duration: 245, statusCode: '200' }) console.log('CRM-активность:', fin.data.CRM_ACTIVITY_ID) // 4. Прикрепляем транскрипцию await api('POST', `/calls/${callId}/transcription`, { messages: [ { side: 'User', startTime: 0, stopTime: 4, message: 'Здравствуйте, компания Вайб!' }, { side: 'Client', startTime: 5, stopTime: 12, message: 'Здравствуйте, я хотел бы уточнить детали заказа 4521' }, { side: 'User', startTime: 13, stopTime: 25, message: 'Конечно, заказ отправлен, трек-номер RU123456789' } ] }) // 5. Смотрим статистику за сегодня const today = new Date().toISOString().slice(0, 10) + 'T00:00:00' const stats = await api('GET', `/calls/statistics?filter[>CALL_START_DATE]=${today}`) console.log(`Звонков сегодня: ${stats.total}`) ``` --- ## Справочник эндпоинтов | Метод | Путь | Bitrix24 метод | Описание | |-------|------|----------------|---------| | POST | [/v1/calls/register](/docs/telephony/crm/register) | telephony.externalcall.register | Зарегистрировать внешний звонок в CRM | | POST | [/v1/calls/:callId/finish](/docs/telephony/crm/finish) | telephony.externalcall.finish | Завершить звонок | | POST | [/v1/calls/:callId/show](/docs/telephony/crm/show) | telephony.externalcall.show | Показать карточку звонка оператору | | POST | [/v1/calls/:callId/hide](/docs/telephony/crm/hide) | telephony.externalcall.hide | Скрыть карточку звонка | | POST | [/v1/calls/:callId/transcription](/docs/telephony/crm/transcription) | telephony.call.attachTranscription | Прикрепить транскрипцию | | POST | [/v1/calls/callback](/docs/telephony/outbound/callback) | voximplant.callback.start | Обратный звонок (оператор → клиент) | | POST | [/v1/calls/auto-call](/docs/telephony/outbound/auto-call) | voximplant.infocall.startwithtext | Автозвонок с синтезом речи | | POST | [/v1/calls/auto-call-audio](/docs/telephony/outbound/auto-call-audio) | voximplant.infocall.startwithsound | Автозвонок с воспроизведением аудиофайла | | GET | [/v1/telephony-lines](/docs/telephony/lines/list) | telephony.externalLine.get | Список линий приложения | | POST | [/v1/telephony-lines](/docs/telephony/lines/create) | telephony.externalLine.add | Добавить линию приложения | | PATCH | [/v1/telephony-lines/:number](/docs/telephony/lines/update) | telephony.externalLine.update | Обновить линию | | DELETE | [/v1/telephony-lines/:number](/docs/telephony/lines/delete) | telephony.externalLine.delete | Удалить линию | | GET | [/v1/telephony-lines/fields](/docs/telephony/lines/fields) | — | Схема полей линии приложения | | GET | [/v1/voximplant-lines](/docs/telephony/lines/voximplant) | voximplant.line.get | Список линий Voximplant (арендованные и SIP) | | GET | [/v1/calls/statistics](/docs/telephony/analytics/statistics) | voximplant.statistic.get | Статистика звонков | | GET | [/v1/calls/voices](/docs/telephony/analytics/voices) | voximplant.tts.voices.get | Справочник голосов синтеза речи | --- ## Коды ошибок ### Ошибки телефонии | Код | HTTP | Описание | |-----|------|---------| | `MISSING_PARAMS` | 400 | Обязательный параметр не передан или не прошёл проверку. Точное сообщение называет требуемые параметры и их формат | | `INVALID_MESSAGE_SHAPE` | 400 | Только для `transcription`: некорректная структура одного из элементов массива `messages` | | `BITRIX_ERROR` | 422 | Битрикс24 вернул ошибку (сообщение из B24 в поле `error.message`) | | `BITRIX_UNAVAILABLE` | 502 | Битрикс24 недоступен | ### Системные ошибки | Код | HTTP | Описание | |-----|------|---------| | `MISSING_API_KEY` | 401 | Не передан заголовок `X-Api-Key` | | `INVALID_API_KEY` | 401 | Неверный API-ключ | | `KEY_INACTIVE` | 401 | API-ключ неактивен или отозван | | `TOKEN_MISSING` | 401 | Ключ не имеет настроенных токенов Битрикс24 | | `SCOPE_DENIED` | 403 | Ключу не хватает скоупа `telephony` | | `RATE_LIMITED` | 429 | Превышен лимит запросов | Полный список общих ошибок API — [Ошибки](/docs/errors). --- ## Смотрите также - [Лиды](/docs/entities/leads) - [Контакты](/docs/entities/contacts) - [Сделки](/docs/entities/deals) --- # Звонки Программный доступ к AI Follow-up завершённых звонков Битрикс24: транскрипция разговора, обзор встречи, договорённости, задачи и оценка эффективности. **Скоуп:** `call` | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` ## Что такое Follow-up Follow-up — это AI-разбор внутреннего звонка или совещания сотрудников: расшифровка разговора, тема встречи, договорённости, поставленные задачи, разбор участников и оценка эффективности. Битрикс24 формирует его сам после завершения звонка, методы раздела только читают готовый результат и ничего не создают. Follow-up формируется не по каждому звонку. Готовые блоки перечислены в поле `outcomes` ответа, несформированные приходят как `null`. **Это не расшифровка звонка клиенту.** Разговор с клиентом, залогированный делом CRM, расшифровывается отдельным механизмом — его текст возвращает [`GET /v1/activities/:activityId/transcript`](/docs/entities/activities/transcript). Если задача звучит как «получить текст разговора с клиентом по сделке или лиду» — вам туда, а не в этот раздел. ## Быстрый старт Список звонков с готовым Follow-up за январь: ```bash curl -X POST https://vibecode.bitrix24.tech/v1/calls/followups/list \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "startDate": { "from": "2026-01-01T00:00:00Z", "to": "2026-01-31T23:59:59Z" } }, "pagination": { "limit": 5 } }' ``` Ответ содержит массив звонков в `data.items` и курсор следующей страницы в `data.afterCursor`: ```json { "success": true, "data": { "items": [ { "callId": 12345, "callType": 1, "initiatorId": 7, "startDate": "2026-01-15T10:00:00+00:00", "endDate": "2026-01-15T10:42:00+00:00", "durationSeconds": 2520 } ], "hasMore": false, "afterCursor": null } } ``` ## Полный пример Разбор итогов встречи: находим звонок за период, читаем обзор и договорённости, забираем задачи. ```bash BASE='https://vibecode.bitrix24.tech/v1' # 1. Звонки с Follow-up за период → берём идентификатор первого CALL_ID=$(curl -s -X POST "$BASE/calls/followups/list" \ -H "X-Api-Key: YOUR_API_KEY" -H "Content-Type: application/json" \ -d '{"filter": {"startDate": {"from": "2026-01-01T00:00:00Z", "to": "2026-01-31T23:59:59Z"}}, "order": {"startDate": "desc"}, "pagination": {"limit": 1}}' | jq -r '.data.items[0].callId') # 2. Обзор встречи и договорённости curl -s "$BASE/calls/followups/$CALL_ID?select=overview&mentionFormat=none" \ -H "X-Api-Key: YOUR_API_KEY" | jq '.data.item.overview.topic, .data.item.overview.agreements' # 3. Задачи, поставленные на встрече curl -s "$BASE/calls/followups/$CALL_ID?select=overview.actionItems&mentionFormat=none" \ -H "X-Api-Key: YOUR_API_KEY" | jq '.data.item.overview.actionItems' ``` `mentionFormat=none` убирает разметку `@`-упоминаний: текст приходит без служебных тегов и готов к передаче в нейросеть или к сохранению в задачу. ## Справочник эндпоинтов | Метод | Путь | Bitrix24 метод | Описание | |-------|------|---------------|----------| | POST | [`/v1/calls/followups/list`](/docs/calls/followup/list) | call.followup.list | Список Follow-up за период с фильтром, сортировкой и курсорной навигацией | | GET | [`/v1/calls/followups/:callId`](/docs/calls/followup/get) | call.followup.get | Полные данные Follow-up по одному звонку | ## Коды ошибок ### Ошибки раздела | HTTP | Код | Когда | |------|-----|-------| | 400 | `MISSING_PARAMS` | В теле запроса нет объекта `filter` | | 400 | `INVALID_PARAMS` | `callId` в пути — не положительное целое число | | 400 | `INVALID_PARAMS` | Битрикс24 отклонил значение параметра. Ответ дополнительно содержит массив `error.validation` с именем поля | | 403 | `BITRIX_ACCESS_DENIED` | Битрикс24 отказал в доступе. Частый случай — набор скоупов, с которым ключ обращается к порталу, не содержит `call`. Полный разбор причин и что делать по типу ключа — [Ошибки](/docs/errors#bitrix_access_denied-403) | | 422 | `METHOD_NOT_YET_AVAILABLE` | Обновление `call 26.600.0` на портале ещё не выпущено. Ответ содержит поле `error.release` со значением `call 26.600.0` — [разбор кода](/docs/errors#method_not_yet_available-422) | | 422 | `BITRIX_ERROR` | Запрос отклонён: некорректный диапазон дат, недопустимое поле в `select`, некорректные `pagination` или `order`, нет доступа к данным звонка | ### Системные ошибки | HTTP | Код | Когда | Повтор | |------|-----|-------|--------| | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | нет | | 401 | `TOKEN_MISSING` | У ключа нет токенов портала. Ключ OAuth-приложения требует заголовок `Authorization: Bearer` | нет | | 403 | `SCOPE_DENIED` | У ключа нет скоупа `call` | нет | | 429 | `RATE_LIMITED` | Превышена частота запросов на стороне Битрикс24 | да, с задержкой | | 429 | `QUEUE_OVERFLOW`, `QUEUE_TIMEOUT` | Очередь запросов портала переполнена или запрос не дождался очереди. Заголовок `Retry-After` подсказывает задержку | да, после `Retry-After` | | 503 | `BITRIX_TIMEOUT` | Битрикс24 принял запрос, но не ответил за 15 секунд | да: методы раздела только читают данные, повтор безопасен | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | да, с задержкой | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Follow-up звонков](/docs/calls/followup) - [Телефония](/docs/telephony) - [Расшифровка звонка](/docs/entities/activities/transcript) - [Ошибки](/docs/errors) --- # CRM Автоматизация Запускайте CRM-триггеры и бизнес-процессы через API. Автоматизируйте воронку продаж, переводите сделки по стадиям, запускайте цепочки согласований программно. **Скоуп:** `crm` (триггеры), `bizproc` (бизнес-процессы) | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` ## Разделы документации - [Триггеры](/docs/automation/triggers) — активация CRM-триггеров для сущностей (2 эндпоинта). - [Бизнес-процессы](/docs/automation/workflows) — запуск, мониторинг и управление бизнес-процессами (5 эндпоинтов). ## Быстрый старт ### Активировать CRM-триггер ```bash curl -X POST https://vibecode.bitrix24.tech/v1/triggers/fire \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "entityType": "deal", "entityId": 100, "triggerId": "payment_received" }' ``` Ответ: ```json { "success": true, "data": true } ``` Полная документация параметров и кодов ошибок: [`POST /v1/triggers/fire`](/docs/automation/triggers/fire) ### Запустить бизнес-процесс ```bash curl -X POST https://vibecode.bitrix24.tech/v1/workflows/start \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "templateId": 15, "entityType": "deal", "entityId": 100, "parameters": { "approver": 1, "comment": "Согласование скидки 15%" } }' ``` Ответ: ```json { "success": true, "data": { "workflowId": "67a1b2c3d4e5f6" } } ``` Полная документация параметров и кодов ошибок: [`POST /v1/workflows/start`](/docs/automation/workflows/start) ## Полный пример Сценарий: сделка перешла в стадию «Оплачено» — активируем CRM-триггер, затем запускаем бизнес-процесс подготовки документов, отправляем событие для продолжения приостановленного процесса, завершаем ненужный экземпляр. ```javascript const VIBE_KEY = process.env.VIBE_KEY const BASE = 'https://vibecode.bitrix24.tech/v1' async function api(method, path, body = null) { const opts = { method, headers: { 'X-Api-Key': VIBE_KEY } } if (body) { opts.headers['Content-Type'] = 'application/json' opts.body = JSON.stringify(body) } const res = await fetch(`${BASE}${path}`, opts) return res.json() } const dealId = 100 // 1. Сделка оплачена — активируем CRM-триггер await api('POST', '/triggers/fire', { entityType: 'deal', entityId: dealId, triggerId: 'payment_received' }) console.log('Триггер "Оплата получена" активирован') // 2. Запускаем бизнес-процесс подготовки документов const { data: wf } = await api('POST', '/workflows/start', { templateId: 22, entityType: 'deal', entityId: dealId, parameters: { docType: 'act', sendToClient: true } }) console.log('Бизнес-процесс запущен:', wf.workflowId) // 3. Просматриваем запущенные экземпляры по шаблону const { data: instances, meta } = await api('GET', '/workflows?templateId=22') console.log(`Активных процессов по шаблону 22: ${meta.total}`) for (const instance of instances) { console.log(` ${instance.ID}: started=${instance.STARTED}`) } // 4. Отправляем событие в приостановленный процесс // eventToken приходит на handler зарегистрированной активити из B24-callback // (см. /docs/entities/bizproc-activities), здесь — иллюстративное значение await api('POST', '/workflows/event', { eventToken: '55c1dc1c3f0d75.67', returnValues: { approved: true }, logMessage: 'Автоматическое подтверждение — сумма в пределах лимита' }) console.log('Событие отправлено, процесс продолжен') // 5. Завершаем ненужный экземпляр await fetch(`${BASE}/workflows/${wf.workflowId}`, { method: 'DELETE', headers: { 'X-Api-Key': VIBE_KEY } }) console.log('Процесс завершён') ``` ## Справочник эндпоинтов | Метод | Путь | Bitrix24 метод | Скоуп | Описание | |-------|------|---------------|-------|---------| | POST | [`/v1/triggers/fire`](/docs/automation/triggers/fire) | crm.automation.trigger | crm | Активировать CRM-триггер | | GET | [`/v1/triggers`](/docs/automation/triggers/list) | crm.automation.trigger.list | crm | Список триггеров портала | | POST | [`/v1/workflows/start`](/docs/automation/workflows/start) | bizproc.workflow.start | bizproc | Запустить бизнес-процесс | | GET | [`/v1/workflows`](/docs/automation/workflows/list) | bizproc.workflow.instances | bizproc | Список запущенных процессов | | DELETE | [`/v1/workflows/:id`](/docs/automation/workflows/terminate) | bizproc.workflow.terminate / kill | bizproc | Завершить бизнес-процесс | | POST | [`/v1/workflows/event`](/docs/automation/workflows/event) | bizproc.event.send | bizproc | Отправить событие в процесс | | POST | [`/v1/workflows/activity-log`](/docs/automation/workflows/activity-log) | bizproc.activity.log | bizproc | Записать в журнал процесса | ## Коды ошибок ### Ошибки автоматизации | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_ENTITY_TYPE` | Неизвестный тип сущности в `entityType`. Поддерживаются: `deal`, `lead`, `contact`, `company`, `quote`, `invoice` | | 400 | `MISSING_PARAMS` | Не переданы обязательные параметры (указаны в поле `message` ответа) | | 400 | `INVALID_PARAMS` | Некорректное значение параметра (возвращается Битрикс24) | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов Битрикс24 | | 403 | `SCOPE_DENIED` | API-ключ не имеет нужного скоупа: `crm` для триггеров, `bizproc` для бизнес-процессов | | 403 | `BITRIX_ACCESS_DENIED` | Портал Битрикс24 отклонил операцию — недостаточно прав на стороне портала | | 404 | `ENTITY_NOT_FOUND` | Сущность или шаблон с указанным ID не найден | | 422 | `BITRIX_ERROR` | Ошибка Битрикс24 REST API (подробности в поле `message`) | | 429 | `RATE_LIMITED` | Превышен лимит запросов. Подождите 1–2 секунды и повторите | | 429 | `QUEUE_TIMEOUT` | Запрос к Битрикс24 ожидал в очереди дольше 30 секунд. Запрос не был отправлен в Битрикс24 — безопасно повторить (`Retry-After`) | | 500 | `INTERNAL_ERROR` | Внутренняя ошибка сервера | | 502 | `BITRIX_UNAVAILABLE` | Портал Битрикс24 недоступен | | 503 | `BITRIX_TIMEOUT` | Битрикс24 принял запрос, но не ответил за 15 секунд. Для write-операций — сначала перечитайте сущность, изменение могло примениться | Полный справочник общих ошибок — [Ошибки](/docs/errors). ## Смотрите также - [Сделки](/docs/entities/deals) - [Лиды](/docs/entities/leads) - [Шаблоны бизнес-процессов](/docs/entities/bizproc-templates) - [Действия бизнес-процессов](/docs/entities/bizproc-activities) - [Роботы](/docs/entities/bizproc-robots) - [Ошибки](/docs/errors) --- # Рабочий день Учёт рабочего времени сотрудника: открытие и закрытие дня, пауза, текущий статус, настройки портала и график работы. **Скоуп:** `timeman` | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` [Какой ключ выбрать](#какой-ключ-выбрать) | [Быстрый старт](#быстрый-старт) | [Полный пример](#полный-пример-автоматический-учёт-рабочего-дня) | [Справочник эндпоинтов](#справочник-эндпоинтов) | [Коды ошибок](#коды-ошибок) ## Какой ключ выбрать Раздел работает с двумя типами ключей. Выбор определяет, от чьего имени фиксируется рабочий день. | Сценарий | Ключ | Заголовки запроса | |---------|------|-------------------| | Личный учёт времени, скрипт на собственном сервере | Личный API-ключ `vibe_api_…` | `X-Api-Key: vibe_api_…` | | OAuth-приложение из каталога Вайбкод — учёт времени для каждого пользователя, установившего приложение | Ключ авторизации `vibe_app_…` | `X-Api-Key: vibe_app_…` + `Authorization: Bearer ` | Действия фиксируются от лица владельца ключа (для личного) или пользователя сессии (для OAuth). Подробное описание форматов и получение `session_token` — [Ключи и авторизация](/docs/keys-auth). --- ## Быстрый старт ### 1. Узнайте текущий статус ```bash curl -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/workday/status ``` ```json { "success": true, "data": { "status": "CLOSED", "timeStart": "2026-05-04T09:00:00+03:00", "timeFinish": "2026-05-04T18:00:00+03:00", "duration": "08:00:00", "timeLeaks": "00:30:00", "active": true, "ipOpen": "203.0.113.10", "ipClose": "203.0.113.10", "latOpen": 0, "lonOpen": 0, "latClose": 0, "lonClose": 0, "tzOffset": 10800 } } ``` ### 2. Откройте рабочий день ```bash curl -X POST https://vibecode.bitrix24.tech/v1/workday/open \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{}' ``` ### 3. Закройте день с отчётом ```bash curl -X POST https://vibecode.bitrix24.tech/v1/workday/close \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "report": "Закрыл 5 сделок, обработал 12 лидов" }' ``` --- ## Полный пример: автоматический учёт рабочего дня Сценарий: скрипт открывает день в 9:00, отслеживает обеденный перерыв и закрывает день в 18:00 с автоматическим отчётом. ```javascript const VIBE_KEY = process.env.VIBE_KEY const BASE = 'https://vibecode.bitrix24.tech/v1' async function api(method, path, body = null) { const opts = { method, headers: { 'X-Api-Key': VIBE_KEY } } if (body) { opts.headers['Content-Type'] = 'application/json' opts.body = JSON.stringify(body) } const res = await fetch(`${BASE}${path}`, opts) return res.json() } // 1. Узнаём текущий статус — чтобы не открывать уже открытый день const { data: current } = await api('GET', '/workday/status') console.log('Текущий статус:', current.status) // 2. Открываем рабочий день, если он закрыт if (current.status === 'CLOSED' || !current.status) { const { data: opened } = await api('POST', '/workday/open', {}) console.log('День открыт в', opened.timeStart) } else { console.log('День уже открыт с', current.timeStart) } // 3. Получаем настройки учёта на портале const { data: settings } = await api('GET', '/workday/settings') console.log('Допустимое начало дня до:', settings.ufTmMaxStart) console.log('Минимальная длительность дня:', settings.ufTmMinDuration) // 4. Уход на обед — ставим паузу const { data: paused } = await api('POST', '/workday/pause', {}) console.log('День на паузе с', paused.timeFinish) // ...перерыв... // 5. Возвращаемся с обеда — продолжаем день const { data: resumed } = await api('POST', '/workday/open', {}) console.log('День продолжен, статус:', resumed.status) // 6. Конец рабочего дня — закрываем с отчётом const { data: closed } = await api('POST', '/workday/close', { report: 'Автоматическое закрытие' }) console.log('День закрыт, отработано:', closed.duration) console.log('Длительность перерыва:', closed.timeLeaks) ``` --- ## Справочник эндпоинтов | Метод | Путь | Bitrix24 метод | Описание | |-------|------|---------------|---------| | POST | [/v1/workday/open](/docs/workday/open) | timeman.open | Открыть или продолжить рабочий день | | POST | [/v1/workday/close](/docs/workday/close) | timeman.close | Закрыть рабочий день | | POST | [/v1/workday/pause](/docs/workday/pause) | timeman.pause | Приостановить рабочий день | | GET | [/v1/workday/status](/docs/workday/status) | timeman.status | Текущий статус рабочего дня | | GET | [/v1/workday/settings](/docs/workday/settings) | timeman.settings | Настройки учёта на портале | | GET | [/v1/workday/schedule](/docs/workday/schedule) | timeman.schedule.get | Сведения о графике работы по `id` | Интерактивный переключатель методов с примерами и таблицами полей — [Эндпоинты](/docs/workday/endpoints). --- ## Коды ошибок | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Битрикс24 вернул `INVALID_PARAMS` — нарушена валидация полей запроса | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `KEY_EXPIRED` | Срок действия API-ключа истёк | | 401 | `TOKEN_MISSING` | Ключу не настроены OAuth-токены для портала | | 402 | `ACCOUNT_FROZEN` | Баланс портала заморожен — пополните баланс | | 403 | `SCOPE_DENIED` | У ключа нет скоупа `timeman` | | 422 | `BITRIX_ERROR` | Битрикс24 отклонил запрос — текст в `message` (например, попытка закрыть уже закрытый день) | | 429 | `RATE_LIMITED` | Превышен лимит запросов к Битрикс24 | | 502 | `BITRIX_UNAVAILABLE` | Портал Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). --- ## Смотрите также - [Ключи и авторизация](/docs/keys-auth) - [Лимиты и оптимизация](/docs/optimization) - [Ошибки](/docs/errors) --- # MCP для AI Вайбкод публикует два MCP-сервера для AI-агентов — подходят для Claude Desktop, Claude Code, Cursor, Codex CLI, Windsurf, Gemini CLI и любого другого клиента с поддержкой Model Context Protocol. - `mcp-vibe-api` — инструменты для работы с Битрикс24 через API Вайбкод. - `mcp-docs` — справочник по REST-методам Битрикс24. [Установка mcp-vibe-api](#mcp-vibe-api) | [Инструменты (51)](#инструменты-51) | [HTTP-транспорт](#http-транспорт) | [mcp-docs](#mcp-docs) | [Безопасность](#безопасность) ## Что можно делать через MCP Подборка диалогов с AI-агентом и инструментов, которые агент реально вызывает. Помогает оценить возможности `mcp-vibe-api` и подобрать набор скоупов для ключа. ### Аналитика по сделкам > **Пользователь:** Покажи сумму сделок в работе по каждому ответственному за последний месяц. Агент по очереди вызывает: 1. `aggregate_entities` для сущности `deals` с фильтром по `closeDate`, агрегатом `sum` по полю `amount` и группировкой по `assignedById`. 2. `list_entities` для сущности `users` — чтобы заменить идентификаторы на имена сотрудников. Скоуп ключа: `crm`, `user`. ### Создание и публикация бота > **Пользователь:** Зарегистрируй бота с именем «Помощник» и пришли тестовое сообщение в чат с моим коллегой. Агент по очереди вызывает: 1. `manage_bot` с действием `register` — создаёт бота на портале. 2. `manage_bot` с действием `get_events` — получает идентификатор диалога с коллегой из входящего события. 3. `manage_bot_messages` с действием `send` — отправляет приветственное сообщение в нужный диалог. Скоуп ключа: `imbot`. ### Развёртывание приложения на сервере > **Пользователь:** Подними новый сервер в Bitrix Cloud и разверни туда архив с приложением. Агент по очереди вызывает: 1. `manage_server` с действиями `list_providers`, `list_plans`, `list_regions`, `list_images` — собирает каталог. 2. `manage_server` с действием `create` — создаёт сервер в выбранной конфигурации. 3. `manage_server` с действием `get` — ждёт, пока статус станет `RUNNING` и `CONNECTED`. 4. `manage_server_deploy` с действием `deploy` — запускает конвейер развёртывания (загрузка архива, установка, systemd, проверка работоспособности). 5. `manage_server_deploy` с действием `logs` — читает журналы при ошибках. Скоуп ключа: `vibe:infra`. ### Подключение собственного провайдера AI > **Пользователь:** Добавь мой ключ OpenAI и сделай тестовый запрос к gpt-4o. Агент по очереди вызывает: 1. `manage_ai_credentials` с действием `list_providers` — выясняет идентификатор провайдера OpenAI. 2. `manage_ai_credentials` с действием `create` — сохраняет ключ; провайдер проверяется до записи и возвращает `422 CREDENTIAL_INVALID`, если ключ не работает. 3. `ai_chat` с действием `chat` и параметром `model: "openai/gpt-4o"` — отправляет тестовый запрос через AI Router. Скоуп ключа: `vibe:ai`. ### Оставить запрос в поддержку через AI > **Пользователь:** Эндпоинт `/v1/deals/aggregate` иногда возвращает пустой ответ — заведи тикет с подробностями. Агент по очереди вызывает: 1. `get_me` — забирает идентификатор портала и текущий тариф для поля `context`. 2. `manage_feedback` с действием `create` — отправляет тикет с категорией `BUG`, заголовком, описанием воспроизведения и сериализованным `context` (эндпоинт, тело запроса, код ответа). Скоуп ключа: создание тикетов доступно любому ключу. ## mcp-vibe-api Сервер, который даёт AI-агенту доступ к Битрикс24 через API Вайбкод. Дальше — установка, параметры запуска, инструменты, Resources, Prompts и HTTP-транспорт. ### Установка Пакет [`@bitrix24/mcp-vibecode-api`](https://www.npmjs.com/package/@bitrix24/mcp-vibecode-api). После установки доступна команда `mcp-vibe-api`. Нужен Node.js версии 18 или выше — подойдёт любая актуальная LTS-сборка (18, 20, 22). ```bash npm install -g @bitrix24/mcp-vibecode-api ``` ### Регистрация в клиенте через CLI Если клиент умеет управлять MCP-серверами через консоль, конфиг-файл редактировать не нужно — достаточно одной команды. Claude Code: ```bash claude mcp add vibecode -- mcp-vibe-api --key vibe_api_your_key_here ``` Команда добавит сервер в локальный конфиг текущего пользователя. Чтобы поделиться настройкой со всем проектом, добавьте флаг `-s project` — конфиг попадёт в `.mcp.json` репозитория. Управлять списком: `claude mcp list`, `claude mcp remove vibecode`. Codex CLI: ```bash codex mcp add vibecode -- mcp-vibe-api --key vibe_api_your_key_here ``` Запись попадёт в `~/.codex/config.toml`. Передать API-ключ через переменную окружения вместо аргумента: `codex mcp add vibecode --env VIBE_API_KEY=vibe_api_your_key_here -- mcp-vibe-api`. Для проектного scope создайте `.codex/config.toml` в корне репозитория и пропишите блок `[mcp_servers.vibecode]` напрямую. Gemini CLI: ```bash gemini mcp add vibecode mcp-vibe-api --key vibe_api_your_key_here ``` Запись попадёт в `~/.gemini/settings.json`. Передать ключ через переменную окружения: `gemini mcp add -e VIBE_API_KEY=vibe_api_your_key_here vibecode mcp-vibe-api`. Для проектного scope используйте `.gemini/settings.json` в корне репозитория. ### Регистрация через конфиг-файл Claude Desktop (`~/Library/Application Support/Claude/claude_desktop_config.json` на macOS, `%APPDATA%\Claude\claude_desktop_config.json` на Windows): ```json { "mcpServers": { "vibecode": { "command": "mcp-vibe-api", "args": ["--key", "vibe_api_your_key_here"] } } } ``` Cursor (`.cursor/mcp.json` в корне проекта): ```json { "mcpServers": { "vibecode": { "command": "mcp-vibe-api", "args": ["--key", "vibe_api_your_key_here"] } } } ``` Codex CLI (`~/.codex/config.toml`): ```toml [mcp_servers.vibecode] command = "mcp-vibe-api" args = ["--key", "vibe_api_your_key_here"] ``` ### Запуск без глобальной установки Если глобально установить пакет нельзя, замените `mcp-vibe-api` на `npx -y @bitrix24/mcp-vibecode-api` в любом конфиге выше. Пример для Claude Desktop: ```json { "mcpServers": { "vibecode": { "command": "npx", "args": ["-y", "@bitrix24/mcp-vibecode-api", "--key", "vibe_api_your_key_here"] } } } ``` ### Параметры запуска Ключ и базовый URL передаются флагами командной строки или через переменные окружения. При коллизии флаг побеждает. | Флаг | Переменная окружения | По умолчанию | Описание | |------|----------------------|--------------|----------| | `--key ` | `VIBE_API_KEY` | — | API-ключ Вайбкод (`vibe_api_...` или `vibe_app_...`) | | `--api-url ` | `VIBE_API_URL` | `https://vibecode.bitrix24.tech` | Базовый URL API Вайбкод | | `--http` | — | выключен | Включить HTTP-транспорт вместо stdio | | `--http-token ` | `VIBE_MCP_HTTP_TOKEN` | — | Bearer-токен для HTTP-транспорта (обязателен с `--http`) | | `--host ` | — | `127.0.0.1` | Адрес для HTTP-транспорта | | `--port ` | — | `3001` | TCP-порт для HTTP-транспорта | | `--allowed-origins ` | — | пусто | Список разрешённых браузерных `Origin`, через запятую | | `--max-body-kb ` | — | `256` | Лимит тела запроса в килобайтах | | `--rate-limit ` | — | `300` | Лимит запросов в минуту на IP | | `-h`, `--help` | — | — | Показать справку | | `-v`, `--version` | — | — | Показать версию пакета | Установка ключа через переменную окружения, чтобы не хранить его в конфигах: ```bash export VIBE_API_KEY="vibe_api_your_key_here" mcp-vibe-api ``` ### Доступ по типу ключа `mcp-vibe-api` работает с двумя типами ключей Вайбкод и при старте запрашивает `/v1/me`, чтобы определить тип. Дальше клиенту отдаются только те инструменты, которые ключ может использовать. | Тип ключа | Какие инструменты доступны | |-----------|----------------------------| | `vibe_api_...` или `vibe_app_...` (ключ портала) | Данные Битрикс24, AI, сборка приложений, служебные | | `vibe_live_...` (управляющий ключ) | Платформенное управление, служебные | В описании каждой группы инструментов ниже указан тип ключа, который к ней подходит. ### Инструменты (51) Все инструменты возвращают JSON. Для специализированных эндпоинтов есть типизированные обёртки — используйте их вместо `call_api`, когда они доступны: подсказки по параметрам и валидация выше. Инструменты сгруппированы в пять кластеров по типу задачи. #### Данные Битрикс24 (27) — ключ портала Чтение и запись данных портала: CRM-сущности, чаты и боты, расширения для CRM, телефония, файлы, бизнес-процессы, рабочее время. Подходит большинству задач AI-агента. ##### Сущности CRM и других модулей (10) Покрывают единый CRUD-интерфейс над 40+ сущностями Битрикс24 — от сделок и контактов до задач, файлов, документов и записей смарт-процессов. | Инструмент | Описание | |------------|----------| | `discover` | Список сущностей и их полей из OpenAPI-схемы | | `get_fields` | Поля сущности с учётом пользовательских полей `UF_*` | | `list_entities` | Список записей с фильтрацией, сортировкой, автопагинацией при `limit > 50` | | `get_entity` | Запись по ID | | `create_entity` | Создание записи | | `update_entity` | Частичное обновление записи | | `delete_entity` | Удаление записи | | `search_entities` | Поиск с операторами `$gt`, `$gte`, `$lt`, `$lte`, `$ne`, `$contains`, `$in`, `$nin` | | `batch_entities` | Массовое создание, обновление и удаление до 500 записей за вызов | | `aggregate_entities` | Агрегация: `count`, `sum`, `avg`, `min`, `max` с группировкой через `groupBy` | Поддерживаемые сущности: `deals`, `contacts`, `companies`, `leads`, `quotes`, `activities`, `products`, `product-sections`, `statuses`, `currencies`, `deal-categories`, `requisites`, `timelines`, `invoices`, `items`, `smart-processes`, `tasks`, `calendar-events`, `files`, `folders`, `storages`, `users`, `departments`, `workgroups`, `chats`, `list-elements`, `catalog-products`, `catalog-sections`, `catalog-prices`, `orders`, `order-statuses`, `basket-items`, `payments`, `sites`, `pages`, `doc-templates`, `documents`, `bookings`, `bizproc-templates`, `openline-configs`, `telephony-lines` и другие. ##### Чаты (1) | Инструмент | Действия | |------------|----------| | `manage_chat` | `list_recent`, `find`, `get`, `send_message`, `read_messages`, `create`, `add_users`, `bulk_messages` | Скоуп: `im`. Управляет чатами и сообщениями на стороне пользователя; для чатов, принадлежащих боту, нужен `manage_bot_chat`. ##### Боты (3) Управление ботами на платформе Битрикс24 — регистрация, чаты, обмен сообщениями. Скоуп ключа: `imbot`. | Инструмент | Действия | |------------|----------| | `manage_bot` | `register`, `unregister`, `update`, `list`, `get`, `get_events` | | `manage_bot_chat` | `create`, `get`, `update`, `leave`, `add_user`, `remove_user`, `set_owner` | | `manage_bot_messages` | `send`, `edit`, `delete`, `add_reaction`, `remove_reaction`, `read`, `get_history`, `send_typing` | ##### CRM-расширения и работа с порталом (12) | Инструмент | Действия | |------------|----------| | `manage_workday` | `open`, `close`, `pause`, `status`, `settings`, `schedule` — учёт рабочего времени. Скоуп: `timeman` | | `manage_workflow` | `start`, `list`, `terminate`, `send_event` — бизнес-процессы. Скоуп: `bizproc` | | `send_notification` | Push-уведомление пользователю Битрикс24. Скоуп: `im` | | `manage_call` | `register`, `finish`, `auto_call`, `callback`, `statistics`, `voices` — телефония и автообзвон с TTS. Скоуп: `telephony` | | `manage_trigger` | `fire`, `list` — CRM-триггеры автоматизации. Скоуп: `bizproc` | | `manage_timeline_log` | `create`, `list`, `get`, `delete`, `add_note`, `get_note`, `delete_note`, `pin`, `unpin`, `bind`, `unbind`, `get_bindings` — записи в таймлайне CRM-сущностей. Скоуп: `crm` | | `manage_warehouse` | `list`, `get`, `create`, `delete`, `get_stock` — склады и остатки. Скоуп: `catalog` | | `manage_post` | `list`, `create`, `update`, `delete`, `share`, `add_comment` — посты в живой ленте. Скоуп: `log` | | `manage_userfield` | `list`, `get`, `types`, `create`, `update`, `delete` — пользовательские поля в фиксированных CRM-сущностях и смарт-процессах. Скоуп: `crm` | | `manage_task_time` | `list`, `get`, `add`, `update`, `delete` — учёт времени по задачам. Скоуп: `task` | | `crm_extras` | `stage_history`, `find_duplicates` — история стадий и поиск дубликатов. Скоуп: `crm` | | `manage_file` | `upload`, `download` — загрузка и скачивание файлов в Битрикс24.Диске. Скоуп: `disk` | ##### Универсальный вызов API Вайбкод (1) | Инструмент | Описание | |------------|----------| | `call_api` | Произвольный HTTP-вызов к API Вайбкод: `method`, `path`, `body`, `query`. Запасной канал для эндпоинтов без типизированной обёртки | Пример вызова: `call_api({ method: "GET", path: "/v1/calls/statistics" })`. #### AI (2) — ключ портала Подключение AI-моделей через AI Router и управление BYOK-учётными данными. Скоуп: `vibe:ai`. | Инструмент | Действия | |------------|----------| | `ai_chat` | `list_models`, `chat` — OpenAI-совместимые chat completions через `/v1/chat/completions`; модель по умолчанию — бесплатная `bitrix/bitrixgpt-5.5` | | `manage_ai_credentials` | `list`, `create`, `update`, `delete`, `test`, `usage`, `list_providers` — управление BYOK-учётными данными для подключения сторонних AI-провайдеров. Создание и обновление проверяют ключ перед сохранением и возвращают `422 CREDENTIAL_INVALID` при ошибке | #### Сборка приложений (12) — ключ портала Создание приложений Битрикс24, развёртывание серверной части на облачных VM, настройка плейсментов в интерфейсе портала. ##### Инфраструктура (3) Облачные серверы для приложений и Black Hole-туннели. Скоуп: `vibe:infra`. | Инструмент | Действия | |------------|----------| | `manage_server` | Каталог: `list_providers`, `list_plans`, `list_regions`, `list_images`. Жизненный цикл: `create`, `list`, `get`, `delete`, `get_ssh`. Состояние: `start`, `stop`, `reboot`, `wake`, `sleep_now`, `refresh`. Операции: `metrics`, `set_port`, `set_sleep`, `set_mode`, `repair`, `repair_status` | | `manage_server_deploy` | `deploy`, `exec`, `upload`, `logs`, `clear_lock` — конвейер развёртывания с шагами `stop → clean → download → runtime → install → env → platform_env → pre_start → service_user → systemd → start → hardening → healthcheck → tunnel_routing` | | `manage_server_access` | `list_access`, `add_access`, `remove_access`, `b24_users_search` — списки доступа Black Hole с автодополнением пользователей Битрикс24 | ##### Приложения (5) | Инструмент | Описание | |------------|----------| | `list_apps` | Список приложений, опциональный фильтр по статусу | | `get_app` | Приложение по ID | | `create_app` | Создание приложения | | `update_app` | Обновление приложения | | `delete_app` | Удаление приложения | ##### Публикация приложений (3) | Инструмент | Описание | |------------|----------| | `publish_app` | Публикация приложения для всего портала | | `unpublish_app` | Снятие приложения с публикации (статус `UNPUBLISHED`) | | `deploy_app` | Публикация приложения в каталог портала (цель `PORTAL`). Деплой исходного кода на сервер — через `manage_server_deploy` | ##### Плейсменты (1) | Инструмент | Действия | |------------|----------| | `manage_placements` | `list_bound`, `list_available`, `bind`, `unbind` — встройка приложения в интерфейс Битрикс24, полное описание операций — [Места встраивания](/docs/apps/placements). Для IM-плейсментов (`IM_SIDEBAR`, `IM_NAVIGATION`, `IM_TEXTAREA`) обязателен параметр `options.iconName` — проверяется на стороне клиента до отправки запроса | Скоуп: `placement`. Действие `list_bound` (под капотом — `GET /v1/placements`) возвращает список placement-кодов, привязанных на платформе Вайбкод, и — при наличии токена сессии (`Authorization: Bearer`) — дополнительное поле `handlers`. Это массив с фактическим URL-обработчиком из Битрикс24 для каждого код-а: `{ placement, handler, title?, options?, langAll? }`. Тип: `Array<{...}> | undefined` — поле отсутствует, если запрос пришёл без `Bearer`, у приложения нет привязанных плейсментов или ответ Битрикс24 не удалось получить (тогда базовый список `placements` всё равно вернётся — graceful-degrade). Поле `handlers` строится как пересечение нашего `App.placements` с ответом Битрикс24-метода `placement.get`. Коды, которые есть в нашей базе, но отсутствуют у Битрикс24, в `handlers` не попадают — это сигнал расхождения (drift), полезный для диагностики: пользователь видит привязку на платформе Вайбкод, но в портале её фактически нет (например, кто-то снял её через интерфейс Битрикс24). Базовый список `data.placements` при этом остаётся прежним — несовместимых изменений в форме ответа нет. Пример (наличие `handlers`): ```json { "success": true, "data": { "placements": ["CRM_DEAL_DETAIL_TAB", "LEFT_MENU"], "appId": "5b5c7e6f-…", "appTitle": "My App", "handlers": [ { "placement": "CRM_DEAL_DETAIL_TAB", "handler": "https://myapp.example.com/deal-tab", "title": "My tab", "options": {}, "langAll": { "ru": { "TITLE": "Моя вкладка" } } } ] } } ``` В примере выше `LEFT_MENU` есть в `placements`, но отсутствует в `handlers` — на портале он не привязан, нужна повторная регистрация через `bind`. Пример без `handlers` (вызов без `Bearer` или нет привязок): ```json { "success": true, "data": { "placements": [], "appId": "5b5c7e6f-…", "appTitle": "My App" } } ``` #### Платформенное управление (8) — управляющий ключ Эта группа доступна только управляющим ключам Вайбкод (формат `vibe_live_...`). | Инструмент | Описание | |------------|----------| | `list_portals` | Список порталов, доступных по управляющему ключу | | `list_keys` | Список API-ключей портала | | `get_key` | Ключ по ID | | `create_key` | Создание ключа со скоупами, IP-вайтлистом и сроком действия | | `update_key` | Изменение ключа | | `delete_key` | Удаление ключа | | `rotate_key` | Ротация секрета ключа | | `manage_feedback` | `create`, `list`, `get`, `update`, `comment` — обращения через `/v1/feedback`. Управляющий ключ работает со всеми порталами; для ключа портала это создание и чтение собственных тикетов, а с дополнительным скоупом `vibe:feedback` — также обновление и комментирование | #### Служебные (2) — любой ключ Доступны и ключу портала, и управляющему. | Инструмент | Описание | |------------|----------| | `get_me` | Снимок текущего ключа: владелец, портал, тариф, capabilities. Параметр `sections` сужает ответ и принимает только `portal`, `tariff`, `capabilities`, `scopes`; вердикт доступа к инфраструктуре лежит в `capabilities.servers.create`. `refresh: 'tariff'` принудительно перепроверяет тариф через Битрикс24 | | `check_for_updates` | Проверка наличия обновлений `mcp-vibe-api` в реестре npm. Возвращает текущую и последнюю версии, команду обновления | ### Resources URI вида `vibe://...` отдают справочные материалы для AI-агента. | URI | Описание | |-----|----------| | `vibe://api-reference` | Полный справочник API Вайбкод в формате Markdown | | `vibe://entity/{plural}` | Справочник по конкретной сущности — например `vibe://entity/deals`, `vibe://entity/tasks` | | `vibe://tariff-gate` | Карта 402-ошибок тарифного шлюза, пробного периода и баланса с подсказками `userMessage` / `alternatives` / `hint` | | `vibe://error-codes` | Каталог кодов ошибок API Вайбкод и форма их ответа | ### Prompts Готовые мульти-шаговые подсказки для AI-агента. Активируются клиентом по имени. | Имя | Описание | |-----|----------| | `create-bitrix24-app` | Сценарий создания, публикации и развёртывания приложения для Битрикс24 | | `deploy-app-step-by-step` | Развёртывание приложения на сервере: пробуждение, загрузка, выполнение команд, проверка работоспособности | | `diagnose-server-issue` | Диагностика проблем сервера: статус, метрики, журналы, варианты восстановления | | `upgrade-from-trial` | Объяснение блокировок тарифного шлюза и пути перехода на коммерческий тариф | ### HTTP-транспорт Помимо stdio (используется по умолчанию) `mcp-vibe-api` поддерживает HTTP-транспорт. Подходит для серверных интеграций, где stdio неудобен. ```bash mcp-vibe-api \ --key vibe_api_your_key_here \ --http \ --http-token "$(openssl rand -hex 32)" \ --allowed-origins https://your-client.example.com ``` Клиент отправляет `POST http://127.0.0.1:3001/mcp` с заголовками: ``` Authorization: Bearer Content-Type: application/json ``` | Код ответа | Причина | |------------|---------| | `401` | Отсутствует или некорректный Bearer-токен | | `403` | Не совпал заголовок `Host`, `Origin` не в списке разрешённых, либо `OPTIONS` без разрешённого `Origin` | | `404` | Путь отличается от `/mcp` | | `405` | Метод запроса отличается от `POST` или `OPTIONS` | | `413` | Тело запроса превышает `--max-body-kb` | | `415` | `Content-Type` отличается от `application/json` | | `429` | Превышен лимит запросов в минуту, ответ содержит `Retry-After: 60` | Сервер откажется стартовать, если `--http` указан без токена. Сами токены не пишутся в журналы — на старте указывается только их источник (флаг или переменная окружения). ## mcp-docs Справочник по REST API Битрикс24: методы, скоупы, плейсменты, типы и категории приложений. Работает офлайн без API-ключа — все данные встроены в пакет. ### Установка Пакет [`@bitrix24/mcp-docs`](https://www.npmjs.com/package/@bitrix24/mcp-docs). После установки доступна команда `mcp-docs`. API-ключ не нужен — справочник встроен в пакет и работает без сети. ```bash npm install -g @bitrix24/mcp-docs ``` ### Регистрация в клиенте Через CLI: ```bash claude mcp add bitrix24-docs -- mcp-docs codex mcp add bitrix24-docs -- mcp-docs gemini mcp add bitrix24-docs mcp-docs ``` Через конфиг-файл: ```json { "mcpServers": { "bitrix24-docs": { "command": "mcp-docs" } } } ``` ### Инструменты (8) | Инструмент | Описание | |------------|----------| | `search_docs` | Полнотекстовый поиск по справочнику | | `get_rest_methods` | Список REST-методов с фильтром по скоупу или поисковому запросу | | `get_method_detail` | Подробное описание метода: параметры, ответ, примеры | | `get_scopes` | Список скоупов с описаниями | | `get_placements` | Список UI-плейсментов с фильтром по модулю | | `get_placement_detail` | Подробное описание плейсмента | | `get_app_types` | Типы приложений Битрикс24 | | `get_categories` | Категории приложений Битрикс24 | Дополнительно сервер публикует ресурс с гайдом по REST API и промпт `bitrix24-rest-intro` — введение в REST и в синтаксис Вайбкод-прокси. ## Прямое использование API Вайбкод без MCP Если MCP-клиент недоступен, дайте AI-модели API-ключ и ссылку на полный справочник: ``` Вот мой API-ключ Вайбкод: vibe_api_your_key_here Полная документация: https://vibecode.bitrix24.tech/llms-full.txt Опишите вашу задачу... ``` `mcp-vibe-api` подключается к любому клиенту с поддержкой Model Context Protocol — Claude Desktop, Claude Code, Cursor, Codex CLI, Windsurf, Gemini CLI и другим. Прямой ключ без MCP подойдёт даже клиентам без поддержки протокола, например ChatGPT. ## Безопасность - Передавайте API-ключ через переменную окружения `VIBE_API_KEY` или флаг `--key` — не вписывайте ключ в скрипты, репозитории и публичные конфиги. - Создавайте отдельный ключ для каждого AI-агента и оставляйте только нужные скоупы — ключи `vibe_api_...` поддерживают список скоупов и срок действия. - Для серверных сценариев настраивайте IP-вайтлист и фиксированный срок жизни ключа. - В HTTP-транспорте используйте Bearer-токен из `--http-token` или `VIBE_MCP_HTTP_TOKEN` и оставляйте `--host 127.0.0.1`, если внешний доступ не нужен. - Если ключ скомпрометирован — отзовите его в [разделе ключей](https://vibecode.bitrix24.tech/keys) и создайте новый. ## Смотрите также - [Ключи и авторизация](/docs/keys-auth) - [Эндпоинты API Вайбкод](/docs/entity-api) - [AI Router](/docs/ai) - [Обратная связь](/docs/feedback) --- # Таймлайн CRM 12 REST-эндпоинтов для журналирования действий в таймлайне CRM-сущностей: создание лог-записей, заметки к ним, закрепление, привязка к нескольким сущностям одновременно. Записи оставляют AI-агенты, фоновые интеграции и сценарии автоматизации, когда действие должно остаться структурированным следом в карточке сделки или контакта. **Скоуп:** `crm` | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` [Быстрый старт](#быстрый-старт) | [AI-агент логирует свои действия (полный пример)](#полный-пример-ai-агент-логирует-свои-действия) | [Коды ошибок](#коды-ошибок) | [Справочник эндпоинтов](#справочник-эндпоинтов) ## Разделы документации - [Записи журнала](/docs/timeline-logs/logs) — создание, просмотр, удаление лог-записей - [Заметки](/docs/timeline-logs/notes) — заметка-комментарий к лог-записи - [Закрепления](/docs/timeline-logs/pins) — закрепить или открепить запись в верхней части таймлайна - [Привязки](/docs/timeline-logs/bindings) — связать одну запись с несколькими сущностями CRM ## Когда использовать - Записать действие AI-агента: проанализировал клиента, подготовил коммерческое предложение, отправил уведомление. - Зафиксировать событие из внешней системы: оплата прошла, заказ собран, документ подписан. - Создать аудиторский след интеграции: какие данные обработала, на основании чего приняла решение. - Закрепить ключевое событие сделки в верхней части таймлайна, чтобы менеджер сразу видел контекст. Для текстовых комментариев пользователя (не системных событий) используйте [`/v1/timelines`](/docs/entities/timelines) — это отдельный API над `crm.timeline.comment.*`. ## Быстрый старт ### 1. Создайте запись в таймлайне сделки ```bash curl -X POST https://vibecode.bitrix24.tech/v1/timeline-logs \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "entityTypeId": 2, "entityId": 100, "title": "AI-агент обработал заявку", "text": "Проанализированы данные клиента. Рекомендация: предложить тариф Enterprise." }' ``` Ответ: ```json { "success": true, "data": { "id": 5012, "created": "2026-04-27T10:00:00+03:00", "authorId": 1, "title": "AI-агент обработал заявку", "text": "Проанализированы данные клиента. Рекомендация: предложить тариф Enterprise.", "iconCode": "" } } ``` ### 2. Закрепите запись в верхней части таймлайна ```bash curl -X POST https://vibecode.bitrix24.tech/v1/timeline-logs/5012/pin \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "entityTypeId": 2, "entityId": 100 }' ``` ### 3. Прикрепите внутреннюю заметку ```bash curl -X POST https://vibecode.bitrix24.tech/v1/timeline-logs/5012/note \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "entityTypeId": 2, "entityId": 100, "text": "Клиент обычно отвечает в течение 2 дней." }' ``` ## Полный пример: AI-агент логирует свои действия Сценарий: AI-агент анализирует сделку, оставляет лог-запись с результатом, привязывает её к контакту и компании, прикрепляет заметку для менеджера, закрепляет в таймлайне. ```javascript const VIBE_KEY = process.env.VIBE_KEY const BASE = 'https://vibecode.bitrix24.tech/v1' async function api(method, path, body = null) { const opts = { method, headers: { 'X-Api-Key': VIBE_KEY } } if (body) { opts.headers['Content-Type'] = 'application/json' opts.body = JSON.stringify(body) } const res = await fetch(`${BASE}${path}`, opts) return res.json() } const dealId = 100 const contactId = 50 const companyId = 10 // 1. Записать факт начала работы const start = await api('POST', '/timeline-logs', { entityTypeId: 2, entityId: dealId, title: 'AI-агент начал обработку', text: 'Анализ данных клиента, проверка кредитного лимита, подготовка предложения.', }) const startId = start.data.id // 2. Связать запись с контактом и компанией — менеджеры обоих увидят // то же событие в своих таймлайнах await api('POST', `/timeline-logs/${startId}/bind`, { entityTypeId: 3, entityId: contactId }) await api('POST', `/timeline-logs/${startId}/bind`, { entityTypeId: 4, entityId: companyId }) // ... AI-агент выполняет работу ... // 3. Записать результат отдельной лог-записью const result = await api('POST', '/timeline-logs', { entityTypeId: 2, entityId: dealId, title: 'AI-агент завершил обработку', text: [ '[b]Результаты анализа:[/b]', '- Кредитный лимит: OK (500 000 руб.)', '- Рекомендованный тариф: Enterprise', '- Скидка: 10% (постоянный клиент)', '- КП сформировано и отправлено на email', ].join('\n'), }) const resultId = result.data.id // 4. Закрепить итоговую запись в верхней части таймлайна await api('POST', `/timeline-logs/${resultId}/pin`, { entityTypeId: 2, entityId: dealId }) // 5. Оставить внутреннюю заметку для менеджера await api('POST', `/timeline-logs/${resultId}/note`, { entityTypeId: 2, entityId: dealId, text: 'Клиент обычно отвечает в течение 2 дней. Напомнить менеджеру, если нет ответа.', }) console.log('AI-агент завершил работу, все действия залогированы') ``` ## Какой ключ использовать CRUD-операции работают с любым типом ключа — личным (`vibe_api_*`) или OAuth-приложением (`vibe_app_*`). Однако **`DELETE /v1/timeline-logs/:id` накладывает ограничение**: Битрикс24 разрешает удалить лог-запись только тому же приложению, которое её создало. - **OAuth-приложение** (`vibe_app_*` + `Authorization: Bearer ...`) — стабильное `client_id`, удалить свои записи можно. Если планируете удалять созданные записи через API, используйте этот тип ключа. - **Личный ключ** (`vibe_api_*`) — Вайбкод ротирует токены между вызовами, для Битрикс24 каждый вызов выглядит как отдельное приложение. `DELETE` всегда возвращает `403 CROSS_APP_DELETE_FORBIDDEN`, в том числе на свежесозданные записи. Если приложение, создавшее запись, недоступно — удалить её нельзя в принципе. Битрикс24 не предоставляет UI-кнопку удаления log-записи в карточке сущности. Учитывайте это при проектировании сценариев аудита. Подробнее — [Удалить запись](/docs/timeline-logs/logs/delete). ## Типы родительских сущностей Параметр `entityTypeId` (числовой код CRM-сущности) указывает, в чьём таймлайне создаётся запись: | `entityTypeId` | Сущность | Где найти ID | |:---:|----------|--------------| | 1 | Лид | [`GET /v1/leads`](/docs/entities/leads/list) | | 2 | Сделка | [`GET /v1/deals`](/docs/entities/deals/list) | | 3 | Контакт | [`GET /v1/contacts`](/docs/entities/contacts) | | 4 | Компания | [`GET /v1/companies`](/docs/entities/companies) | | 7 | Предложение | [`GET /v1/quotes`](/docs/entities/quotes) | | 14 | Заказ | [`GET /v1/orders`](/docs/entities/orders) | | 31 | Счёт | [`GET /v1/invoices`](/docs/entities/invoices) | | ≥ 128 | Смарт-процесс | [`GET /v1/items/:entityTypeId`](/docs/entities/items/list); список процессов — [`GET /v1/smart-processes`](/docs/entities/smart-processes/list) | В привязках (`bind`/`unbind`) можно использовать как числовой `entityTypeId`, так и строковый `entityType` напрямую (`"deal"`, `"contact"`, `"dynamic_174"` и т. п.) — см. [Привязать запись](/docs/timeline-logs/bindings/bind). ## Коды ошибок ### Ошибки таймлайна | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Не переданы или некорректны обязательные параметры (`entityTypeId`, `entityId`, `title`, `text`, `itemType` и т. д. — конкретное поле в `message`) | | 400 | `INVALID_ENTITY_TYPE_ID` | В `bindings.bind`/`unbind` передан `entityTypeId` без отображения на `ENTITY_TYPE` (`< 128` и не из таблицы выше) | | 403 | `CROSS_APP_DELETE_FORBIDDEN` | Попытка удалить лог-запись через ключ, отличный от того, которым она создана | | 404 | `ENTITY_NOT_FOUND` | Лог-запись с указанным `id` не существует — Битрикс24 вернул ошибку `NOT_FOUND` | | 404 | `NOT_FOUND` | Только `GET /v1/timeline-logs/:id`: Битрикс24 вернул успешный ответ, но объект записи пуст | | 404 | `NOTE_NOT_FOUND` | У указанного элемента таймлайна нет привязанной заметки | ### Системные ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `MISSING_API_KEY` | Отсутствует `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов (для `vibe_app_*` нужен `Authorization: Bearer ...`) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку (текст в `message`) | | 429 | `RATE_LIMITED` | Превышен лимит запросов. Подождите 1–2 секунды и повторите. Несколько вызовов можно объединить в [`POST /v1/batch`](/docs/batch) | | 429 | `QUEUE_TIMEOUT` | Запрос к B24 не успел выполниться в очереди портала. Запрос не был отправлен в Битрикс24 — безопасно повторить (`Retry-After`). Сузьте фильтр или повторите позже | | 429 | `ERROR_LOOP_DETECTED` | Блокировка на стороне Вайбкод: подряд много одинаковых ошибок на одном методе. Повторяйте с задержкой — каждый N-й запрос пробрасывается для проверки восстановления | | 502 | `BITRIX_UNAVAILABLE` | Портал Битрикс24 недоступен | | 503 | `BITRIX_TIMEOUT` | Битрикс24 принял запрос, но не ответил за 15 секунд. Для write-операций — сначала перечитайте сущность, изменение могло примениться | | 500 | `INTERNAL_ERROR` | Внутренняя ошибка сервера | Полный список общих кодов API — [Ошибки](/docs/errors). ## Справочник эндпоинтов Все 12 эндпоинтов: | Метод | Путь | Bitrix24 метод | Описание | |-------|------|---------------|---------| | POST | [/v1/timeline-logs](/docs/timeline-logs/logs/create) | `crm.timeline.logmessage.add` | Создать лог-запись | | GET | [/v1/timeline-logs](/docs/timeline-logs/logs/list) | `crm.timeline.logmessage.list` | Список лог-записей | | GET | [/v1/timeline-logs/:id](/docs/timeline-logs/logs/get) | `crm.timeline.logmessage.get` | Получить одну запись | | DELETE | [/v1/timeline-logs/:id](/docs/timeline-logs/logs/delete) | `crm.timeline.logmessage.delete` | Удалить запись | | POST | [/v1/timeline-logs/:id/note](/docs/timeline-logs/notes/save) | `crm.timeline.note.save` | Сохранить или обновить заметку | | GET | [/v1/timeline-logs/:id/note](/docs/timeline-logs/notes/get) | `crm.timeline.note.get` | Получить заметку | | DELETE | [/v1/timeline-logs/:id/note](/docs/timeline-logs/notes/delete) | `crm.timeline.note.delete` | Удалить заметку | | POST | [/v1/timeline-logs/:id/pin](/docs/timeline-logs/pins/pin) | `crm.timeline.item.pin` | Закрепить запись | | POST | [/v1/timeline-logs/:id/unpin](/docs/timeline-logs/pins/unpin) | `crm.timeline.item.unpin` | Открепить запись | | POST | [/v1/timeline-logs/:id/bind](/docs/timeline-logs/bindings/bind) | `crm.timeline.bindings.bind` | Привязать к ещё одной сущности | | POST | [/v1/timeline-logs/:id/unbind](/docs/timeline-logs/bindings/unbind) | `crm.timeline.bindings.unbind` | Отвязать от сущности | | GET | [/v1/timeline-logs/:id/bindings](/docs/timeline-logs/bindings/list) | `crm.timeline.bindings.list` | Список всех привязок записи | ## Смотрите также - [Комментарии таймлайна](/docs/entities/timelines) - [Сделки](/docs/entities/deals) - [Лиды](/docs/entities/leads) - [Контакты](/docs/entities/contacts) - [Компании](/docs/entities/companies) - [Смарт-процессы](/docs/entities/smart-processes) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Пользовательские поля Управление пользовательскими полями CRM-сущностей и смарт-процессов Битрикс24: создание, обновление, удаление текстовых полей, списков, дат, чисел, привязок к сотрудникам и сущностям CRM. Изменения применяются к полям сущности на всём портале — учитывайте это при работе на боевых данных. **Скоуп:** `crm`, `userfieldconfig` | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` [Быстрый старт](#быстрый-старт) | [Полный пример](#полный-пример) | [Справочник эндпоинтов](#справочник-эндпоинтов) | [Коды ошибок](#коды-ошибок) ## Разделы документации - [Поля CRM-сущностей](/docs/userfields/crm) — управление полями сделок, лидов, контактов, компаний, предложений и реквизитов - [Поля смарт-процессов](/docs/userfields/smart-processes) — управление полями элементов смарт-процессов по `entityTypeId` ## Значения полей в записях Эндпоинты этого раздела управляют самим полем — его типом, подписью и настройками. Значение поля в конкретной записи читается и записывается вместе с самой записью: `POST /v1/deals`, `PATCH /v1/deals/:id`, `GET /v1/deals/:id`. Имя, под которым поле принимается в этих запросах, отличается от значения `fieldName`, которое возвращают эндпоинты этого раздела. Поле, созданное на сделках как `fieldName: "PROJECT_CODE"`, стоит в списке определений под именем `UF_CRM_PROJECT_CODE`, а в схеме сделки — под именем `ufCrmProjectCode`. Рабочее имя всегда берётся из `GET /v1/{entity}/fields`. Формат значения для каждого из типов, множественные поля и очистка — [Пользовательские поля (UF)](/docs/entity-api#пользовательские-поля-uf). --- ## Быстрый старт ### 1. Посмотрите существующие поля сделки ```bash curl -H "X-Api-Key: YOUR_API_KEY" \ "https://vibecode.bitrix24.tech/v1/userfields/deals" ``` Ответ: ```json { "success": true, "data": [ { "id": 7115, "entityId": "CRM_DEAL", "fieldName": "UF_CRM_PROJECT_CODE", "userTypeId": "string", "mandatory": "N", "sort": "100", "editFormLabel": { "ru": "Код проекта" } } ], "meta": { "total": 44 } } ``` ### 2. Создайте новое поле ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/userfields/deals" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "userTypeId": "string", "fieldName": "PROJECT_CODE", "label": "Код проекта" }' ``` При успешном создании возвращается HTTP `201 Created` с числовым `id` нового поля. --- ## Полный пример Сценарий: добавить поле-список «Источник лида», получить его полное описание, сделать видимым в фильтре, удалить. ```javascript const KEY = process.env.VIBECODE_API_KEY const BASE = 'https://vibecode.bitrix24.tech/v1' async function api(method, path, body) { const opts = { method, headers: { 'X-Api-Key': KEY } } if (body) { opts.headers['Content-Type'] = 'application/json' opts.body = JSON.stringify(body) } const res = await fetch(`${BASE}${path}`, opts) return res.status === 204 ? null : res.json() } // 1. Узнать, сколько пользовательских полей уже создано const before = await api('GET', '/userfields/deals') console.log(`Полей до создания: ${before.meta.total}`) // 2. Создать поле-список «Источник лида» const created = await api('POST', '/userfields/deals', { userTypeId: 'enumeration', fieldName: 'LEAD_SOURCE', label: 'Источник лида', mandatory: 'Y', list: [ { VALUE: 'Сайт', SORT: 10 }, { VALUE: 'Соцсети', SORT: 20 }, { VALUE: 'Реклама', SORT: 30 } ] }) const newId = created.data.id console.log('Создано поле с id:', newId) // 3. Получить полное описание созданного поля const detail = await api('GET', `/userfields/deals/${newId}`) console.log('Варианты списка:', detail.data.list.map(v => v.VALUE).join(', ')) // 4. Сделать поле видимым в фильтре карточки await api('PATCH', `/userfields/deals/${newId}`, { showFilter: 'Y' }) // 5. Удалить поле — ответ HTTP 204 с пустым телом await api('DELETE', `/userfields/deals/${newId}`) console.log('Поле удалено') ``` --- ## Справочник эндпоинтов ### Поля CRM-сущностей | Метод | Путь | Bitrix24 метод | Описание | |-------|------|----------------|---------| | GET | [/v1/userfields/:entity](/docs/userfields/crm/list) | crm.:entity.userfield.list | Список полей сущности | | GET | [/v1/userfields/:entity/types](/docs/userfields/crm/types) | crm.userfield.types | Каталог типов полей | | GET | [/v1/userfields/:entity/:id](/docs/userfields/crm/get) | crm.:entity.userfield.get | Одно поле по идентификатору | | POST | [/v1/userfields/:entity](/docs/userfields/crm/create) | crm.:entity.userfield.add | Создать поле | | PATCH | [/v1/userfields/:entity/:id](/docs/userfields/crm/update) | crm.:entity.userfield.update | Обновить поле | | DELETE | [/v1/userfields/:entity/:id](/docs/userfields/crm/delete) | crm.:entity.userfield.delete | Удалить поле | `:entity` — одно из значений: `deals`, `leads`, `contacts`, `companies`, `quotes`, `requisites`. ### Поля смарт-процессов | Метод | Путь | Bitrix24 метод | Описание | |-------|------|----------------|---------| | GET | [/v1/items/:entityTypeId/userfields](/docs/userfields/smart-processes/list) | userfieldconfig.list | Список полей смарт-процесса | | GET | [/v1/items/:entityTypeId/userfields/types](/docs/userfields/smart-processes/types) | crm.userfield.types | Каталог типов полей | | GET | [/v1/items/:entityTypeId/userfields/:id](/docs/userfields/smart-processes/get) | userfieldconfig.get | Одно поле по идентификатору | | POST | [/v1/items/:entityTypeId/userfields](/docs/userfields/smart-processes/create) | userfieldconfig.add | Создать поле | | PATCH | [/v1/items/:entityTypeId/userfields/:id](/docs/userfields/smart-processes/update) | userfieldconfig.update | Обновить поле | | DELETE | [/v1/items/:entityTypeId/userfields/:id](/docs/userfields/smart-processes/delete) | userfieldconfig.delete | Удалить поле | `entityTypeId` — идентификатор типа смарт-процесса из ответа [`GET /v1/smart-processes`](/docs/entities/smart-processes). --- ## Коды ошибок ### Ошибки пользовательских полей | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNKNOWN_ENTITY` | Сущность не из списка поддерживаемых (`deals`, `leads`, `contacts`, `companies`, `quotes`, `requisites`) | | 400 | `INVALID_ENTITY_TYPE_ID` | `entityTypeId` смарт-процесса не является положительным целым числом | | 400 | `MISSING_FIELD` | Не передан обязательный параметр `userTypeId` при создании | | 400 | `INVALID_REQUEST` | Тело запроса не является объектом | | 403 | `BITRIX_ACCESS_DENIED` | OAuth-приложению Битрикс24 не хватает прав на `userfieldconfig.*` для смарт-процессов | | 404 | `ENTITY_NOT_FOUND` | Поле с указанным `id` не существует | | 404 | `SMART_PROCESS_NOT_FOUND` | Смарт-процесс с указанным `entityTypeId` не найден на портале | | 422 | `BITRIX_ERROR` | Битрикс24 отклонил запрос — некорректное значение, недопустимое имя поля, неизвестный `userTypeId` | ### Системные ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `MISSING_API_KEY` | Отсутствует заголовок `X-Api-Key` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 502 | `BITRIX_UNAVAILABLE` | Портал Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). --- ## Смотрите также - [Поля CRM-сущностей](/docs/userfields/crm) - [Поля смарт-процессов](/docs/userfields/smart-processes) - [Справочник сущностей](/docs/entity-api) - [Смарт-процессы](/docs/entities/smart-processes) - [Сделки](/docs/entities/deals) - [Реквизиты](/docs/entities/requisites) - [Ошибки](/docs/errors) --- # Каталог и склад Управляйте каталогом товаров, ценами и складскими остатками через Entity API. Разделы каталога, ценовые предложения, склады — всё через стандартные CRUD-операции. ## Обзор Catalog API расширяет базовые entity-обёртки для торгового каталога Битрикс24: - **Разделы каталога** (`/v1/catalog-sections/*`) — категории и подкатегории товаров - **Цены** (`/v1/catalog-prices/*`) — ценовые предложения (прайс-листы) - **Склады** (`/v1/warehouses/*`) — управление складами и остатками **Требуемые скоупы:** `catalog`, `crm` **Базовый URL:** `https://vibecode.bitrix24.tech/v1` **Авторизация:** заголовок `X-Api-Key` с вашим API-ключом. ## Быстрый старт ### Создайте раздел каталога ```bash curl -X POST https://vibecode.bitrix24.tech/v1/catalog-sections \ -H "X-Api-Key: $VIBE_KEY" \ -H "Content-Type: application/json" \ -d '{ "fields": { "iblockId": 14, "name": "Электроника", "iblockSectionId": null } }' ``` Ответ: ```json { "success": true, "data": { "section": { "id": 42 } } } ``` ## Разделы каталога Entity: `catalog-sections` — разделы (категории) торгового каталога. ### POST /v1/catalog-sections Создаёт новый раздел каталога. **Параметры тела запроса (в `fields`):** | Параметр | Тип | Обязательный | Описание | |----------|-----|:---:|---------| | `iblockId` | number | да | ID инфоблока каталога | | `name` | string | да | Название раздела | | `iblockSectionId` | number | нет | ID родительского раздела (`null` — корневой) | | `xmlId` | string | нет | Внешний ID для синхронизации | | `description` | string | нет | Описание раздела | | `sort` | number | нет | Порядок сортировки | **JavaScript:** ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-sections', { method: 'POST', headers: { 'X-Api-Key': VIBE_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ fields: { iblockId: 14, name: 'Смартфоны', iblockSectionId: 42, // дочерний раздел "Электроники" sort: 100 } }) }) const { data } = await res.json() console.log('Section ID:', data.section.id) ``` ### GET /v1/catalog-sections Возвращает список разделов каталога с фильтрацией. ```bash curl -H "X-Api-Key: $VIBE_KEY" \ "https://vibecode.bitrix24.tech/v1/catalog-sections?filter[iblockId]=14" ``` ### GET /v1/catalog-sections/:id Получает раздел по ID. ```bash curl -H "X-Api-Key: $VIBE_KEY" \ https://vibecode.bitrix24.tech/v1/catalog-sections/42 ``` ### PATCH /v1/catalog-sections/:id Обновляет раздел каталога. ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/catalog-sections/42 \ -H "X-Api-Key: $VIBE_KEY" \ -H "Content-Type: application/json" \ -d '{ "fields": { "name": "Электроника и гаджеты", "sort": 50 } }' ``` ### DELETE /v1/catalog-sections/:id Удаляет раздел каталога. ```bash curl -X DELETE -H "X-Api-Key: $VIBE_KEY" \ https://vibecode.bitrix24.tech/v1/catalog-sections/42 ``` ## Цены Entity: `catalog-prices` — ценовые предложения для товаров. ### POST /v1/catalog-prices Создаёт новое ценовое предложение для товара. **Параметры тела запроса (в `fields`):** | Параметр | Тип | Обязательный | Описание | |----------|-----|:---:|---------| | `catalogGroupId` | number | да | ID типа цены | | `productId` | number | да | ID товара | | `price` | number | да | Цена | | `currency` | string | да | Валюта (`RUB`, `USD`, `EUR`) | | `quantityFrom` | number | нет | Количество «от» для оптовой цены | | `quantityTo` | number | нет | Количество «до» | ```bash curl -X POST https://vibecode.bitrix24.tech/v1/catalog-prices \ -H "X-Api-Key: $VIBE_KEY" \ -H "Content-Type: application/json" \ -d '{ "fields": { "catalogGroupId": 1, "productId": 200, "price": 49990, "currency": "RUB" } }' ``` **JavaScript — оптовые цены:** ```javascript // Розничная цена await fetch('https://vibecode.bitrix24.tech/v1/catalog-prices', { method: 'POST', headers: { 'X-Api-Key': VIBE_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ fields: { catalogGroupId: 1, // розничная productId: 200, price: 49990, currency: 'RUB' } }) }) // Оптовая цена (от 10 штук) await fetch('https://vibecode.bitrix24.tech/v1/catalog-prices', { method: 'POST', headers: { 'X-Api-Key': VIBE_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ fields: { catalogGroupId: 2, // оптовая productId: 200, price: 39990, currency: 'RUB', quantityFrom: 10 } }) }) ``` ### GET /v1/catalog-prices Список цен с фильтрацией по товару. ```bash curl -H "X-Api-Key: $VIBE_KEY" \ "https://vibecode.bitrix24.tech/v1/catalog-prices?filter[productId]=200" ``` ### GET /v1/catalog-prices/:id Получает цену по ID. ```bash curl -H "X-Api-Key: $VIBE_KEY" \ https://vibecode.bitrix24.tech/v1/catalog-prices/15 ``` ### PATCH /v1/catalog-prices/:id Обновляет цену. ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/catalog-prices/15 \ -H "X-Api-Key: $VIBE_KEY" \ -H "Content-Type: application/json" \ -d '{ "fields": { "price": 44990 } }' ``` ### DELETE /v1/catalog-prices/:id Удаляет ценовое предложение. ```bash curl -X DELETE -H "X-Api-Key: $VIBE_KEY" \ https://vibecode.bitrix24.tech/v1/catalog-prices/15 ``` ## Склады Склады и складские остатки вынесены в отдельный раздел — **[Склады](/docs/entities/warehouses)** — с отдельной страницей на каждую операцию и проверенными примерами. ## Полный пример: Синхронизация каталога из 1С ```javascript const VIBE_KEY = process.env.VIBE_KEY const BASE = 'https://vibecode.bitrix24.tech/v1' async function api(method, path, body = null) { const opts = { method, headers: { 'X-Api-Key': VIBE_KEY } } if (body) { opts.headers['Content-Type'] = 'application/json' opts.body = JSON.stringify(body) } const res = await fetch(`${BASE}${path}`, opts) return res.json() } // Данные из 1С const categories = [ { name: 'Электроника', xmlId: '1c_cat_001', children: [ { name: 'Смартфоны', xmlId: '1c_cat_002' }, { name: 'Ноутбуки', xmlId: '1c_cat_003' } ]}, { name: 'Аксессуары', xmlId: '1c_cat_010' } ] const IBLOCK_ID = 14 // 1. Создаём корневые разделы for (const cat of categories) { const { data } = await api('POST', '/catalog-sections', { fields: { iblockId: IBLOCK_ID, name: cat.name, xmlId: cat.xmlId } }) const parentId = data.section.id console.log(`Раздел "${cat.name}" создан, ID: ${parentId}`) // 2. Создаём дочерние разделы if (cat.children) { for (const child of cat.children) { const { data: childData } = await api('POST', '/catalog-sections', { fields: { iblockId: IBLOCK_ID, name: child.name, xmlId: child.xmlId, iblockSectionId: parentId } }) console.log(` Подраздел "${child.name}" создан, ID: ${childData.section.id}`) } } } // 3. Устанавливаем цены на товары const products = [ { id: 200, retail: 49990, wholesale: 39990 }, { id: 201, retail: 79990, wholesale: 64990 } ] for (const product of products) { // Розничная цена await api('POST', '/catalog-prices', { fields: { catalogGroupId: 1, productId: product.id, price: product.retail, currency: 'RUB' } }) // Оптовая цена await api('POST', '/catalog-prices', { fields: { catalogGroupId: 2, productId: product.id, price: product.wholesale, currency: 'RUB', quantityFrom: 10 } }) console.log(`Цены для товара ${product.id}: розн. ${product.retail}, опт. ${product.wholesale}`) } console.log('Синхронизация завершена') ``` ## Справочник эндпоинтов | Метод | Путь | Bitrix24 метод | Описание | |-------|------|---------------|---------| | POST | /v1/catalog-sections | catalog.section.add | Создать раздел | | GET | /v1/catalog-sections | catalog.section.list | Список разделов | | GET | /v1/catalog-sections/:id | catalog.section.get | Получить раздел | | PATCH | /v1/catalog-sections/:id | catalog.section.update | Обновить раздел | | DELETE | /v1/catalog-sections/:id | catalog.section.delete | Удалить раздел | | POST | /v1/catalog-prices | catalog.price.add | Создать цену | | GET | /v1/catalog-prices | catalog.price.list | Список цен | | GET | /v1/catalog-prices/:id | catalog.price.get | Получить цену | | PATCH | /v1/catalog-prices/:id | catalog.price.update | Обновить цену | | DELETE | /v1/catalog-prices/:id | catalog.price.delete | Удалить цену | ## Коды ошибок | Код | HTTP | Описание | |-----|------|---------| | `SCOPE_DENIED` | 403 | API-ключ не имеет скоупа `catalog` | | `TOKEN_MISSING` | 401 | Ключ не имеет настроенных токенов | | `SECTION_NOT_FOUND` | 404 | Раздел каталога не найден | | `PRODUCT_NOT_FOUND` | 404 | Товар не найден | | `BITRIX_UNAVAILABLE` | 502 | Битрикс24 недоступен | | `BITRIX_ERROR` | 422 | Ошибка Bitrix24 REST API | --- # Лента новостей Публикация постов в Ленте новостей Битрикс24 через API: посты с адресацией отделам и сотрудникам, открытие доступа дополнительным получателям и комментарии. **Скоуп:** `log` | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` [Быстрый старт](#быстрый-старт) | [Полный пример](#полный-пример) | [Справочник эндпоинтов](#справочник-эндпоинтов) | [Коды ошибок](#коды-ошибок) ## Разделы документации - [Посты](/docs/feed/posts) — создание, список, обновление, удаление постов и добавление получателей - [Комментарии](/docs/feed/comments) — добавление и удаление комментариев к постам ## Быстрый старт ### 1. Опубликуйте пост ```bash curl -X POST https://vibecode.bitrix24.tech/v1/posts \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Обновление платформы", "text": "[b]Вышла новая версия[/b] — поддержка пакетных запросов.", "recipients": ["UA"] }' ``` Ответ — идентификатор созданного поста и получатели, которым он открыт: ```json { "success": true, "data": { "id": 512, "recipients": ["UA"] } } ``` ### 2. Прокомментируйте пост ```bash curl -X POST https://vibecode.bitrix24.tech/v1/posts/512/comments \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "text": "Отличная новость!" }' ``` Ответ — идентификатор комментария: ```json { "success": true, "data": 1024 } ``` ### 3. Откройте пост дополнительным получателям ```bash curl -X POST https://vibecode.bitrix24.tech/v1/posts/512/share \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "recipients": ["DR3", "U5"] }' ``` ```json { "success": true, "data": true } ``` ## Полный пример Автоматический отчёт в ленту: публикация поста, комментарий от интеграции и открытие доступа руководству. Сценарий использует только скоуп `log`. ```javascript const VIBE_KEY = process.env.VIBE_KEY const BASE = 'https://vibecode.bitrix24.tech/v1' async function api(method, path, body = null) { const opts = { method, headers: { 'X-Api-Key': VIBE_KEY } } if (body) { opts.headers['Content-Type'] = 'application/json' opts.body = JSON.stringify(body) } const res = await fetch(`${BASE}${path}`, opts) return res.status === 204 ? null : res.json() } // 1. Публикуем ежедневный отчёт, адресуя отделу с подотделами const created = await api('POST', '/posts', { title: 'Ежедневный отчёт', text: [ '[b]Итоги дня[/b]', '', 'Закрытых задач: 48', 'Новых обращений: 12' ].join('\n'), recipients: ['DR1'] }) const postId = created.data.id console.log('Пост опубликован, ID:', postId) // 2. Добавляем комментарий от интеграции const comment = await api('POST', `/posts/${postId}/comments`, { text: 'Отчёт сформирован автоматически интеграцией Вайбкод.' }) console.log('Комментарий добавлен, ID:', comment.data) // 3. Открываем отчёт руководству await api('POST', `/posts/${postId}/share`, { recipients: ['U1'] }) // 4. Проверяем, что пост в ленте const list = await api('GET', '/posts?limit=5') console.log('Всего постов:', list.meta.total) ``` ## Справочник эндпоинтов | Метод | Путь | Bitrix24 метод | Описание | |-------|------|---------------|---------| | POST | [/v1/posts](/docs/feed/posts/create) | log.blogpost.add | Создать пост | | GET | [/v1/posts](/docs/feed/posts/list) | log.blogpost.get | Список постов | | PATCH | [/v1/posts/:id](/docs/feed/posts/update) | log.blogpost.update | Обновить пост | | DELETE | [/v1/posts/:id](/docs/feed/posts/delete) | log.blogpost.delete | Удалить пост | | POST | [/v1/posts/:id/share](/docs/feed/posts/share) | log.blogpost.share | Добавить получателей | | POST | [/v1/posts/:id/comments](/docs/feed/comments/add) | log.blogcomment.add | Добавить комментарий | | DELETE | [/v1/posts/:id/comments/:commentId](/docs/feed/comments/delete) | log.blogcomment.delete | Удалить комментарий | ## Коды ошибок ### Ошибки ленты | Код | HTTP | Описание | |-----|------|---------| | `SCOPE_DENIED` | 403 | У API-ключа нет скоупа `log` | | `TOKEN_MISSING` | 401 | У API-ключа не настроены токены доступа | | `MISSING_PARAMS` | 400 | Не переданы обязательные параметры (`text` для поста или комментария, `recipients` для добавления получателей) | | `INVALID_LIMIT` | 400 | `limit` вне диапазона 1..50 | | `INVALID_OFFSET` | 400 | `offset` отрицательный | | `INVALID_POST_ID` | 400 | `id` поста не является положительным целым | | `POST_NOT_FOUND` | 404 | Пост не найден или недоступен с этим ключом | | `POST_NOT_FOUND_OR_INVALID_RECIPIENTS` | 404 | Добавление получателей отклонено: пост не существует или среди получателей есть неверный | | `INVALID_RECIPIENTS` | 400 | Неверный формат получателей | | `BITRIX_ACCESS_DENIED` | 403 | Недостаточно прав на пост | | `COMMENT_NOT_FOUND` | 404 | Комментарий не найден | | `INVALID_COMMENT_ID` | 400 | `commentId` неверный | | `COMMENT_ACCESS_DENIED` | 403 | Недостаточно прав на комментарий | | `DUPLICATE_COMMENT` | 409 | Повторный комментарий с тем же содержимым | ### Системные ошибки | Код | HTTP | Описание | |-----|------|---------| | `MISSING_API_KEY` | 401 | Отсутствует заголовок `X-Api-Key` | | `INVALID_API_KEY` | 401 | Неверный API-ключ | | `RATE_LIMITED` | 429 | Превышен лимит запросов | | `BITRIX_ERROR` | 422 | Битрикс24 вернул ошибку | | `BITRIX_UNAVAILABLE` | 502 | Портал Битрикс24 недоступен | | `INTERNAL_ERROR` | 500 | Внутренняя ошибка сервера | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Посты](/docs/feed/posts) - [Комментарии](/docs/feed/comments) - [Ключи и авторизация](/docs/keys-auth) - [Ошибки](/docs/errors) --- # Чаты и сообщения Работайте с мессенджером Битрикс24 от имени авторизованного пользователя: находите чаты CRM-сущностей, читайте и отправляйте сообщения, управляйте участниками, загружайте файлы и получайте события через опрос. **Скоуп:** `im` | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` [Быстрый старт](#быстрый-старт) | [Полный пример](#полный-пример) | [Справочник эндпоинтов](#справочник-эндпоинтов) | [Коды ошибок](#коды-ошибок) ## Разделы документации - [Поиск чатов](/docs/chats/discovery) — список последних диалогов, поиск чата CRM-сущности, текстовый поиск, информация о диалоге - [Сообщения](/docs/chats/messages) — чтение, отправка, редактирование, удаление, отметка прочитанными, массовая загрузка - [Управление чатами](/docs/chats/management) — создание групповых чатов, переименование, передача владения, выход - [Участники](/docs/chats/members) — список участников, добавление, удаление - [Файлы](/docs/chats/files) — загрузка файлов в чат, метаданные файла, папка чата на Диске - [События](/docs/chats/events) — подписка, опрос событий мессенджера, отписка ## Оформление сообщений Справочники по оформлению текста при отправке и редактировании сообщений: - [Форматирование текста (BB-коды)](/docs/chats/messages/formatting) - [Клавиатура](/docs/chats/messages/keyboard) - [Вложения](/docs/chats/messages/attach) ## Идентификаторы чатов В запросах встречаются два вида идентификаторов: - `dialogId` — идентификатор диалога: число (ID пользователя) для личной переписки, строка вида `chatN` (например `chat123`) для групповых чатов. - `chatId` — числовой ID чата без префикса `chat`. Нужен для управления чатом, участниками и файлами. Вместо своего идентификатора можно передать литерал `me` — он заменяется на ID текущего пользователя, которому принадлежит ключ. Так можно отправить сообщение самому себе, не запрашивая свой ID отдельным вызовом. Литерал пишется строчными буквами и работает везде, где принимается `dialogId`: информация о диалоге, чтение и отправка сообщений, список участников. Пример — отправить себе уведомление: ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/chats/me/messages" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"message": "Квартальный отчёт готов"}' ``` ## Личное сообщение сотруднику Чтобы отправить сотруднику личное сообщение, подставьте его числовой ID пользователя Битрикс24 в качестве `dialogId`. Отдельный поиск или создание диалога не нужны — `POST /v1/chats/:dialogId/messages` с числовым `dialogId` доставляет сообщение в личную переписку с этим сотрудником. Поиск чата [`GET /v1/chats/find`](/docs/chats/discovery/find) находит чаты CRM-сущностей, для личного диалога он не требуется. Числовой ID сотрудника — из списка пользователей [`GET /v1/users`](/docs/entities/users). ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/chats/42/messages" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"message": "Дайджест продаж за сегодня готов"}' ``` ## Быстрый старт Найдите чат CRM-сделки, прочитайте сообщения и отправьте ответ. ### 1. Найдите чат сделки ```bash curl -H "X-Api-Key: YOUR_API_KEY" \ "https://vibecode.bitrix24.tech/v1/chats/find?entityType=CRM&entityId=DEAL|123" ``` Ответ: ```json { "success": true, "data": { "id": 2741 } } ``` `data.id` — числовой `chatId`. Для построения `dialogId` при обращении к эндпоинтам сообщений добавьте префикс `chat`: `chat2741`. ### 2. Прочитайте сообщения ```bash curl -H "X-Api-Key: YOUR_API_KEY" \ "https://vibecode.bitrix24.tech/v1/chats/chat2741/messages?limit=5" ``` Ответ: ```json { "success": true, "data": { "chatId": 253, "messages": [ { "id": 9357, "chatId": 253, "authorId": 1, "date": "2026-04-26T18:10:54+03:00", "text": "Коллеги, КП утверждено. Можно выставлять счёт.", "unread": false } ], "users": [ { "id": 1, "name": "Иван Петров", "firstName": "Иван", "lastName": "Петров" } ], "files": [] } } ``` ### 3. Отправьте ответ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/chats/chat2741/messages" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"message": "Счёт выставлен. Номер: СЧ-2026-0458"}' ``` Ответ: ```json { "success": true, "data": 36889 } ``` `data` — ID отправленного сообщения. ## Полный пример Непрерывный сценарий: создать групповой чат, отправить приветствие, отметить переписку прочитанной, переименовать чат и выйти из него. ```javascript const VIBE_KEY = process.env.VIBE_KEY const BASE = 'https://vibecode.bitrix24.tech/v1' async function api(method, path, body = null) { const opts = { method, headers: { 'X-Api-Key': VIBE_KEY } } if (body) { opts.headers['Content-Type'] = 'application/json' opts.body = JSON.stringify(body) } const res = await fetch(`${BASE}${path}`, opts) return res.json() } // 1. Создаём групповой чат const created = await api('POST', '/chats', { title: 'Рабочая группа', users: [1, 5, 12], }) const chatId = created.data // числовой chatId const dialogId = `chat${chatId}` // dialogId для эндпоинтов сообщений console.log('Чат создан, ID:', chatId) // 2. Отправляем приветствие const sent = await api('POST', `/chats/${dialogId}/messages`, { message: 'Добро пожаловать в рабочую группу!', }) console.log('Сообщение отправлено, ID:', sent.data) // 3. Отмечаем переписку прочитанной const read = await api('POST', `/chats/${dialogId}/read`, {}) console.log('Непрочитанных осталось:', read.data.counter) // 4. Переименовываем чат — управление идёт по числовому chatId, без префикса chat await api('PATCH', `/chats/${chatId}`, { title: 'Проект: Поставка оборудования', }) // 5. Выходим из чата await api('POST', `/chats/${chatId}/leave`, {}) console.log('Готово') ``` > Если вы владелец чата, сначала передайте владение через `POST /v1/chats/:chatId/owner`, затем покидайте чат — иначе выход зафиксируется, но владельцем останетесь вы. ## Справочник эндпоинтов Все 23 эндпоинта раздела: | Метод | Путь | Bitrix24 метод | Описание | |-------|------|---------------|---------| | GET | [/v1/chats/recent](/docs/chats/discovery/recent) | im.recent.list | Последние диалоги | | GET | [/v1/chats/find](/docs/chats/discovery/find) | im.chat.get | Найти чат CRM-сущности | | GET | [/v1/chats/search](/docs/chats/discovery/search) | im.search.chat.list | Поиск чатов по тексту | | GET | [/v1/chats/:dialogId](/docs/chats/discovery/get) | im.dialog.get | Информация о диалоге | | GET | [/v1/chats/:dialogId/messages](/docs/chats/messages/list) | im.dialog.messages.get | Чтение сообщений | | POST | [/v1/chats/:dialogId/messages](/docs/chats/messages/send) | im.message.add | Отправка сообщения | | PATCH | [/v1/chats/:dialogId/messages/:messageId](/docs/chats/messages/update) | im.message.update | Редактирование сообщения | | DELETE | [/v1/chats/:dialogId/messages/:messageId](/docs/chats/messages/delete) | im.message.delete | Удаление сообщения | | POST | [/v1/chats/:dialogId/read](/docs/chats/messages/read) | im.dialog.read | Отметить прочитанным | | POST | [/v1/chats/messages/bulk](/docs/chats/messages/bulk) | batch (im.dialog.messages.get) | Массовая загрузка из нескольких диалогов | | POST | [/v1/chats](/docs/chats/management/create) | im.chat.add | Создать групповой чат | | PATCH | [/v1/chats/:chatId](/docs/chats/management/rename) | im.chat.updateTitle | Переименовать чат | | POST | [/v1/chats/:chatId/owner](/docs/chats/management/owner) | im.chat.setOwner | Передать владение | | POST | [/v1/chats/:chatId/leave](/docs/chats/management/leave) | im.chat.leave | Покинуть чат | | GET | [/v1/chats/:dialogId/users](/docs/chats/members/list) | im.dialog.users.list | Список участников | | POST | [/v1/chats/:chatId/users](/docs/chats/members/add) | im.chat.user.add | Добавить участников | | DELETE | [/v1/chats/:chatId/users](/docs/chats/members/remove) | im.chat.user.delete | Удалить участника | | POST | [/v1/chats/:chatId/files](/docs/chats/files/upload) | im.disk.folder.get + disk.folder.uploadfile + im.disk.file.commit | Загрузить файл в чат | | GET | [/v1/chats/files/:fileId](/docs/chats/files/file-get) | disk.file.get | Метаданные файла | | GET | [/v1/chats/:chatId/folder](/docs/chats/files/folder) | im.disk.folder.get | Папка чата на Диске | | POST | [/v1/chats/events/subscribe](/docs/chats/events/subscribe) | im.v2.Event.subscribe | Подписаться на события | | POST | [/v1/chats/events/unsubscribe](/docs/chats/events/unsubscribe) | im.v2.Event.unsubscribe | Отписаться от событий | | GET | [/v1/chats/events](/docs/chats/events/poll) | im.v2.Event.get | Получить события | ## Коды ошибок Коды, специфичные для работы с чатами: | Код | HTTP | Описание | |-----|------|---------| | `SCOPE_DENIED` | 403 | API-ключ не имеет скоупа `im` | | `TOKEN_MISSING` | 401 | У API-ключа не настроены токены Битрикс24 | | `MISSING_PARAMS` | 400 | Не переданы обязательные параметры (`entityType`/`entityId` при поиске, `filename`/`content` при загрузке файла) | | `INVALID_REQUEST` | 400 | Некорректное тело запроса (например, пустой массив `dialogs` в массовой загрузке) | | `BATCH_LIMIT_EXCEEDED` | 400 | Превышен лимит 50 диалогов в массовой загрузке | | `INVALID_CHAT_ID` | 400 | `chatId` не является положительным целым числом | | `TITLE_EMPTY` | 400 | Пустое название при переименовании чата | | `INVALID_OFFSET` | 400 | Некорректный `offset` при опросе событий | | `INVALID_LIMIT` | 400 | `limit` вне допустимого диапазона | | `CHAT_NOT_FOUND_OR_NO_ACCESS` | 404 | Чат не существует или нет прав на операцию | | `DIALOG_NOT_FOUND_OR_NO_ACCESS` | 404 | Диалог не существует или нет доступа | | `ENTITY_NOT_FOUND` | 404 | Запрошенный объект не найден | | `FILE_NOT_FOUND` | 404 | Файл с указанным `fileId` не найден | | `FOLDER_NOT_FOUND` | 404 | Папка чата на Диске не найдена | | `UPLOAD_FAILED` | 500 | Не удалось загрузить файл на Диск | | `ME_ALIAS_RESOLUTION_FAILED` | 502 | Не удалось определить текущего пользователя для алиаса `me` | | `BITRIX_ERROR` | 422 | Битрикс24 вернул ошибку (текст в поле `message`) | | `BITRIX_UNAVAILABLE` | 502 | Портал Битрикс24 недоступен или вернул ошибку сервера | Общие коды авторизации, ключей и лимитов — на странице [Ошибки](/docs/errors). ## Смотрите также - [Бот-платформа](/docs/bots) - [Уведомления](/docs/notifications) - [Ключи и авторизация](/docs/keys-auth) - [Лимиты и оптимизация](/docs/optimization) - [Справочник ошибок](/docs/errors) --- # Универсальные списки Программный доступ к модулю «Списки» Битрикс24: сами списки, их поля, разделы и элементы. **Скоуп:** `lists` | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` > **Модуль подключается на портале отдельно.** Универсальные списки — отдельный модуль Битрикс24. Если он не активирован на портале, вызовы возвращают `409 LISTS_MODULE_NOT_ENABLED`. Это не ошибка интеграции — попросите администратора портала включить модуль «Списки» и повторите запрос. ## Модель данных Список — это инфоблок. Каждый вызов адресует данные тремя уровнями ключей. **Тип инфоблока** — параметр `iblockTypeId`. Возможные значения: - `lists` — обычные списки. Значение по умолчанию. - `lists_socnet` — списки рабочих групп. Для них нужен `socnetGroupId`. - `bitrix_processes` — служебные бизнес-процессы. Тип передаётся в query для GET и DELETE, в теле для POST и PATCH. **Список** — сегмент пути `:iblockId`. Одни цифры — это числовой `IBLOCK_ID`, строка — символьный код `IBLOCK_CODE`. Оба варианта равнозначны. **Поле, раздел или элемент** — соответствующий вложенный сегмент пути. Ответы приходят в форме Битрикс24. Ключи — в верхнем регистре через подчёркивание: `ID`, `NAME`, `IBLOCK_TYPE_ID`. Числовые идентификаторы возвращаются строками, например `"ID": "121"`. Пользовательские свойства элемента адресуются ключами вида `PROPERTY_`. Эти ключи не приводятся к camelCase — часть из них динамическая. ## Разделы документации - [Списки](/docs/lists/lists) — создание, чтение, изменение и удаление самих списков, а также тип инфоблока. - [Поля списка](/docs/lists/fields) — набор полей списка и справочник допустимых типов поля. - [Разделы](/docs/lists/sections) — группировка элементов по разделам с поддержкой вложенности. - [Элементы](/docs/lists/elements) — строки списка и ссылки на файлы из свойств элемента. ## Быстрый старт ```bash # Все списки типа lists curl -H "X-Api-Key: YOUR_API_KEY" \ "https://vibecode.bitrix24.tech/v1/lists?iblockTypeId=lists" # Элементы списка 23 curl -H "X-Api-Key: YOUR_API_KEY" \ "https://vibecode.bitrix24.tech/v1/lists/23/elements" ``` ## Полный пример Сценарий из пяти шагов: создать список, добавить поле, добавить элемент со значением этого поля, прочитать результат, удалить список. ```bash KEY="YOUR_API_KEY" BASE="https://vibecode.bitrix24.tech/v1" # 1. Создать список → { "success": true, "data": { "id": 135 } } curl -s -X POST -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \ -d '{"iblockCode":"demo_orders","fields":{"NAME":"Демо: заявки","SORT":100}}' \ "$BASE/lists" # 2. Добавить поле → { "success": true, "data": { "id": "PROPERTY_1179" } } curl -s -X POST -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \ -d '{"fields":{"NAME":"Статус","TYPE":"S","CODE":"STATUS"}}' \ "$BASE/lists/135/fields" # 3. Добавить элемент со значением свойства → { "success": true, "data": { "id": 7043 } } curl -s -X POST -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \ -d '{"elementCode":"row-1","fields":{"NAME":"Заявка №1","PROPERTY_1179":"новая"}}' \ "$BASE/lists/135/elements" # 4. Прочитать элементы → data[0] = { "ID": "7043", "NAME": "Заявка №1", "PROPERTY_1179": { "3811": "новая" } } curl -s -H "X-Api-Key: $KEY" \ "$BASE/lists/135/elements?select=ID,NAME,PROPERTY_1179" # 5. Удалить список → HTTP 204 No Content (поля, разделы и элементы удаляются вместе с ним) curl -s -X DELETE -H "X-Api-Key: $KEY" "$BASE/lists/135" ``` Поле создаётся с обязательным `CODE`. Значение свойства при создании передаётся строкой (`"PROPERTY_1179": "новая"`), а при чтении возвращается в форме `{ id_значения: значение }`. ## Справочник эндпоинтов | Метод | Путь | Bitrix24 метод | Описание | |-------|------|----------------|----------| | GET | [`/v1/lists`](/docs/lists/lists/list) | lists.get | Список списков заданного типа | | POST | [`/v1/lists`](/docs/lists/lists/create) | lists.add | Создать список | | GET | [`/v1/lists/:iblockId`](/docs/lists/lists/get) | lists.get | Один список | | PATCH | [`/v1/lists/:iblockId`](/docs/lists/lists/update) | lists.update | Изменить список | | DELETE | [`/v1/lists/:iblockId`](/docs/lists/lists/delete) | lists.delete | Удалить список | | GET | [`/v1/lists/:iblockId/type`](/docs/lists/lists/type) | lists.get.iblock.type.id | Тип инфоблока по id или коду | | GET | [`/v1/lists/:iblockId/fields`](/docs/lists/fields/list) | lists.field.get | Все поля списка | | GET | [`/v1/lists/:iblockId/fields/:fieldId`](/docs/lists/fields/get) | lists.field.get | Одно поле | | POST | [`/v1/lists/:iblockId/fields`](/docs/lists/fields/create) | lists.field.add | Создать поле | | PATCH | [`/v1/lists/:iblockId/fields/:fieldId`](/docs/lists/fields/update) | lists.field.update | Изменить поле | | DELETE | [`/v1/lists/:iblockId/fields/:fieldId`](/docs/lists/fields/delete) | lists.field.delete | Удалить поле | | GET | [`/v1/lists/:iblockId/field-types`](/docs/lists/fields/field-types) | lists.field.type.get | Справочник типов поля | | GET | [`/v1/lists/:iblockId/sections`](/docs/lists/sections/list) | lists.section.get | Разделы списка | | GET | [`/v1/lists/:iblockId/sections/:sectionId`](/docs/lists/sections/get) | lists.section.get | Один раздел | | POST | [`/v1/lists/:iblockId/sections`](/docs/lists/sections/create) | lists.section.add | Создать раздел | | PATCH | [`/v1/lists/:iblockId/sections/:sectionId`](/docs/lists/sections/update) | lists.section.update | Изменить раздел | | DELETE | [`/v1/lists/:iblockId/sections/:sectionId`](/docs/lists/sections/delete) | lists.section.delete | Удалить раздел | | GET | [`/v1/lists/:iblockId/elements`](/docs/lists/elements/list) | lists.element.get | Элементы списка | | GET | [`/v1/lists/:iblockId/elements/:elementId`](/docs/lists/elements/get) | lists.element.get | Один элемент | | POST | [`/v1/lists/:iblockId/elements`](/docs/lists/elements/create) | lists.element.add | Создать элемент | | PATCH | [`/v1/lists/:iblockId/elements/:elementId`](/docs/lists/elements/update) | lists.element.update | Изменить элемент | | DELETE | [`/v1/lists/:iblockId/elements/:elementId`](/docs/lists/elements/delete) | lists.element.delete | Удалить элемент | | GET | [`/v1/lists/:iblockId/elements/:elementId/files/:fieldId`](/docs/lists/elements/files) | lists.element.get.file.url | Ссылки на файлы свойства | ## Коды ошибок | HTTP | Код | Когда | |------|-----|-------| | 409 | `LISTS_MODULE_NOT_ENABLED` | Модуль «Списки» не подключён на портале | | 400 | `INVALID_IBLOCK_TYPE` | `iblockTypeId` не из набора `lists`, `lists_socnet`, `bitrix_processes` | | 400 | `MISSING_REQUIRED_FIELDS` | Не передан обязательный `iblockCode`, `sectionCode`, `elementCode` или `fields` | | 400 | `INVALID_PARAMS` | Нечисловой `:sectionId` или `:elementId`, либо `fieldId` с префиксом `PROPERTY_` в маршруте файлов | | 400 | `INVALID_FILTER` | Параметр `filter` не является корректным JSON | | 400 | `INVALID_SORT_FIELD` | Параметр `sort` ссылается на неподдерживаемое поле или направление | | 422 | `BITRIX_ERROR` | Битрикс24 отклонил запрос. Например, поле создаётся без `CODE` или обновляется без `TYPE` | | 403 | `BITRIX_ACCESS_DENIED` | Нет прав на список, либо список с таким `:iblockId` не существует | | 404 | `LIST_NOT_FOUND` / `SECTION_NOT_FOUND` / `ELEMENT_NOT_FOUND` / `FIELD_NOT_FOUND` | Объект не найден | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ в режиме «только чтение» | | 403 | `SCOPE_DENIED` | У ключа нет скоупа `lists` | | 401 | `TOKEN_MISSING` | Не передан `X-Api-Key` или у ключа нет токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Лимиты | Лимит | Значение | |-------|----------| | Пагинация списков и элементов | Смещение выборки у `GET /v1/lists` и `GET /v1/lists/:iblockId/elements` задаётся параметром `start` либо его синонимом `offset`. Если переданы оба, применяется `start`. Ответ отдаётся страницами, следующую страницу берите, увеличивая смещение. Автоматического обхода всех страниц нет | | Rate limit | Общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Списки](/docs/lists/lists) - [Поля списка](/docs/lists/fields) - [Разделы](/docs/lists/sections) - [Элементы](/docs/lists/elements) --- # Менеджмент-ключи Менеджмент-ключи (`vibe_live_`) не привязаны к одному порталу и предназначены для автоматизации администрирования: управления API-ключами, просмотра порталов и работы с обратной связью. ## Отличие от ключей портала | Возможность | API-ключ (`vibe_api_`) | Ключ авторизации (`vibe_app_`) | Менеджмент-ключ (`vibe_live_`) | |-------------|------------------------|--------------------------------|--------------------------------| | Привязка к порталу | Да (один портал) | Да (один портал) | Нет (все порталы пользователя) | | Доступ к сущностям Битрикс24 (deals, tasks и др.) | Да | Да | Нет | | Управление API-ключами | Нет | Нет | Да | | Просмотр списка порталов | Нет | Нет | Да | | Работа с обратной связью | Только свои тикеты | Только свои тикеты | Все тикеты платформы | | Справочник API (`/v1/guide`) | Отфильтрован по скоупам | Отфильтрован по скоупам | Полный (все сущности) | ## Скоупы менеджмент-ключа Каждый менеджмент-ключ создаётся с одним или несколькими скоупами. Без нужного скоупа конкретный эндпоинт возвращает `403 MANAGEMENT_SCOPE_REQUIRED` — даже если эндпоинт в принципе доступен менеджмент-ключам. | Скоуп | Открывает | |-------|-----------| | `vibe:mgmt:keys` | `/v1/keys` (список, создание, изменение, удаление, перевыпуск) | | `vibe:mgmt:portals` | `/v1/portals` | | `vibe:mgmt:feedback` | `/v1/feedback` (список тикетов, чтение, обновление, комментарии) | Эндпоинты `/v1/me`, `/v1/guide` и `/v1/openapi.json` доступны любому менеджмент-ключу без отдельного скоупа. При создании ключа выбирайте только нужные скоупы — если ключ предназначен только для управления API-ключами, скоуп `vibe:mgmt:feedback` ему не нужен. ## Состояние аккаунта владельца Менеджмент-ключ действует от лица своего владельца, поэтому состояние его аккаунта проверяется на **каждом** эндпоинте контура — и на чтении, и на записи. Проверка идёт раньше проверки скоупа, поэтому эти коды приходят даже там, где нужного скоупа у ключа нет. | HTTP | Код | Когда возвращается | |------|-----|---------------------| | 403 | `OWNER_DELETED` | Аккаунт владельца ключа удалён | | 403 | `OWNER_BLOCKED` | Аккаунт владельца ключа заблокирован платформой | | 503 | `ACCOUNT_PENDING_ERASURE` | Владелец запросил удаление своих данных — до конца срока отмены ключ заморожен. В ответе заголовок `Retry-After: 3600`. Отмена запроса возвращает ключу работу, перевыпуск не нужен | Заморозка распространяется на все операции контура, включая выпуск, перевыпуск и удаление API-ключей. ## Доступные эндпоинты При обращении к эндпоинтам сущностей Битрикс24 возвращается `403 MANAGEMENT_KEY_NO_ENTITY_ACCESS`. ### `GET /v1/me` — самоописание ключа Возвращает тип ключа, список порталов с ролями и количеством ключей, перечень доступных эндпоинтов и быстрый старт. ```bash curl -H "X-Api-Key: vibe_live_abc123..." \ https://vibecode.bitrix24.tech/v1/me ``` Ответ: ```json { "success": true, "data": { "type": "management", "keyPrefix": "vibe_live_abc123", "keySuffix": "f9d2", "expiresAt": null, "scopes": [], "capabilities": [ "GET https://vibecode.bitrix24.tech/v1/me — this endpoint (management key self-description)", "GET https://vibecode.bitrix24.tech/v1/guide — full API reference (portal-agnostic)", "GET https://vibecode.bitrix24.tech/v1/keys — list APP keys for a portal (requires portalId query param)", "POST https://vibecode.bitrix24.tech/v1/keys — create APP key (requires portalId in body)", "GET https://vibecode.bitrix24.tech/v1/portals — list your portals", "GET https://vibecode.bitrix24.tech/v1/feedback — list ALL platform feedback (management key sees everything)", "GET https://vibecode.bitrix24.tech/v1/feedback/:id — feedback details including comment thread", "PATCH https://vibecode.bitrix24.tech/v1/feedback/:id — update status/resolution (legacy, prefer /comments)", "POST https://vibecode.bitrix24.tech/v1/feedback/:id/comments — post a team comment, changes status" ], "portals": [ { "id": "portal-uuid", "domain": "mycompany.bitrix24.ru", "status": "ACTIVE", "role": "ADMIN", "appKeyCount": 3 } ], "totalAppKeys": 3, "quickstart": { "step1": "GET https://vibecode.bitrix24.tech/v1/portals — list available portals", "step2": "GET https://vibecode.bitrix24.tech/v1/keys?portalId= — list APP keys for a portal", "step3": "POST https://vibecode.bitrix24.tech/v1/keys { portalId, name, scopes } — create an APP key", "step4": "Use the APP key for entity API calls (deals, tasks, etc.)" }, "docs": "https://vibecode.bitrix24.tech/docs/management-keys" } } ``` В ответе также присутствует объект `feedback` со справочником эндпоинтов, статусов и фильтров для работы с тикетами обратной связи — он используется AI-моделями для автоматической обработки тикетов. ### `GET /v1/guide` — справочник API Возвращает полный справочник API со всеми сущностями (без фильтрации по скоупам). Используется для подбора нужных эндпоинтов перед созданием API-ключей. ```bash curl -H "X-Api-Key: vibe_live_abc123..." \ https://vibecode.bitrix24.tech/v1/guide ``` ### `GET /v1/openapi.json` — OpenAPI-спецификация Возвращает машинно-читаемую OpenAPI 3.1 спецификацию платформы Вайбкод. ```bash curl -H "X-Api-Key: vibe_live_abc123..." \ https://vibecode.bitrix24.tech/v1/openapi.json ``` ### `GET /v1/portals` — список порталов Возвращает порталы, к которым пользователь имеет доступ, с ролью на каждом портале. ```bash curl -H "X-Api-Key: vibe_live_abc123..." \ https://vibecode.bitrix24.tech/v1/portals ``` ### `GET /v1/keys` — список API-ключей портала Параметр `portalId` обязателен. Возвращаются ключи владельца менеджмент-ключа на указанном портале — и личные `vibe_api_`, и ключи авторизации `vibe_app_`. Значения ключей не возвращаются: свой ключ узнаётся в списке по полям `prefix` и `suffix`. ```bash curl -H "X-Api-Key: vibe_live_abc123..." \ "https://vibecode.bitrix24.tech/v1/keys?portalId=portal-uuid" ``` | Поле | Тип | Описание | |------|-----|---------| | `data[].id` | string | Идентификатор записи ключа. Его принимают эндпоинты, которым нужен ключ как ресурс — например `targetApiKeyId` в [переносе владения ботом](/docs/bots/management/transfer) | | `data[].name` | string | Название ключа, заданное при создании | | `data[].prefix` | string | Начало значения ключа | | `data[].suffix` | string | Последние символы значения ключа | | `data[].type` | string | Тип ключа. У ключей портала — `APP` | | `data[].userId` | string | Идентификатор владельца ключа | | `data[].portalId` | string | Идентификатор портала | | `data[].clientId` | string \| null | Идентификатор OAuth-приложения у ключа авторизации, `null` у личного ключа | | `data[].scopes` | array | Скоупы ключа | | `data[].ipWhitelist` | array | Разрешённые IP-адреса, пустой массив — без ограничения | | `data[].rateLimit` | number \| null | Индивидуальный лимит запросов, `null` — общий лимит платформы | | `data[].status` | string | `ACTIVE`, `REVOKED` или `BLOCKED` | | `data[].accessMode` | string | `READWRITE` или `READONLY` | | `data[].expiresAt` | string \| null | Дата окончания срока действия, `null` — бессрочный | | `data[].lastUsedAt` | string \| null | Дата последнего запроса этим ключом | | `data[].createdAt` | string | Дата создания | | `data[].updatedAt` | string | Дата последнего изменения | ```json { "success": true, "data": [ { "id": "3f9a1c20-5e6b-4d18-9a77-0c2b8e4f1d33", "name": "Бот техподдержки", "prefix": "vibe_api_XXXXXXXXX", "suffix": "XXXX", "type": "APP", "userId": "a02e7b64-91c3-4f5a-8d20-7e1b3c95a4dc", "portalId": "d41f0b93-6c85-42e7-9a13-58bd0e7c2f46", "clientId": null, "scopes": ["imbot"], "ipWhitelist": [], "rateLimit": null, "status": "ACTIVE", "accessMode": "READWRITE", "expiresAt": null, "lastUsedAt": "2026-07-29T09:12:44.301Z", "createdAt": "2026-07-14T08:03:17.118Z", "updatedAt": "2026-07-14T08:03:17.118Z" } ] } ``` Отказы этого запроса: | HTTP | Код | Когда возвращается | |------|-----|---------------------| | 400 | `MISSING_PORTAL_ID` | Не передан обязательный параметр `portalId` | | 401 | `WRONG_KEY_TYPE` | Запрос отправлен ключом портала — список ключей отдаётся только менеджмент-ключу | | 403 | `NOT_PORTAL_MEMBER` | Владелец ключа не состоит в портале с указанным `portalId` | | 403 | `PORTAL_ACCESS_BLOCKED` | Доступ владельца ключа к этому порталу заблокирован | | 401 | `KEY_INACTIVE` | Менеджмент-ключ отозван или заблокирован | | 401 | `KEY_EXPIRED` | Срок действия менеджмент-ключа закончился | | 403 | `MANAGEMENT_SCOPE_REQUIRED` | У ключа нет скоупа `vibe:mgmt:keys` | ### `POST /v1/keys` — создание API-ключа Создаёт новый API-ключ (`vibe_api_`) для указанного портала. В теле передаётся `portalId`, имя и список скоупов. Полный ключ возвращается в поле `rawKey` один раз — сохраните его сразу. ```bash curl -X POST \ -H "X-Api-Key: vibe_live_abc123..." \ -H "Content-Type: application/json" \ -d '{"portalId": "portal-uuid", "name": "My Key", "scopes": ["crm", "task"]}' \ https://vibecode.bitrix24.tech/v1/keys ``` По умолчанию к запрошенным правам добавляются четыре платформенных: `vibe:infra`, `vibe:ai`, `vibe:search`, `vibe:storage`. Ключ из примера выше получит `crm`, `task` и эти четыре. Нужен ключ ровно с перечисленным — передайте `exactScopes: true`: ```bash curl -X POST \ -H "X-Api-Key: vibe_live_abc123..." \ -H "Content-Type: application/json" \ -d '{"portalId": "portal-uuid", "name": "Storage only", "scopes": ["crm", "vibe:storage"], "exactScopes": true}' \ https://vibecode.bitrix24.tech/v1/keys ``` Такой ключ получит только `crm` и `vibe:storage`, а на `POST /v1/infra/servers` и вызовы AI ответит `403`. Права такого ключа считаются окончательными: платформа не расширяет их на лету, поэтому `GET /v1/me` вернёт ровно то, что было сохранено при выпуске. | Поле | Тип | Описание | |------|-----|----------| | `exactScopes` | boolean | Необязательное, по умолчанию `false`. `true` — сохранить ровно перечисленные права, без четырёх платформенных | Дополнительные коды ошибок: | Код | HTTP | Когда возвращается | |-----|------|---------------------| | `MISSING_PORTAL_ID` | 400 | В теле запроса не указан `portalId` | | `NOT_PORTAL_MEMBER` | 403 | Владелец ключа не состоит в указанном портале | | `PORTAL_NOT_LINKED` | 400 | Портал не подключён к Битрикс24 Network — создать ключ невозможно | | `PERSONAL_KEY_WEBHOOK_SCOPES_INVALID` | 400 | В `scopes` не осталось ни одного права на данные. Ключ портала выписывается входящим вебхуком Битрикс24, а права `placement` и `entity` вебхук не несёт: они отбрасываются, и когда кроме них в запросе ничего нет, ключ не создаётся. Добавьте хотя бы одно право на данные, например `crm` или `user_brief`, либо заведите OAuth-приложение — там `placement` работает | | `MARKETPLACE_REQUIRED` | 402 | На портале нет активной подписки BitrixGPT + Маркетплейс | | `KZ_PAID_ONLY` | 402 | В Казахстане подписка BitrixGPT + Маркетплейс доступна только на платном тарифе — демо-доступа нет | | `UZ_PAID_ONLY` | 402 | В Узбекистане подписка BitrixGPT + Маркетплейс доступна только на платном тарифе — демо-доступа нет | | `INT_TARIFF_REQUIRED` | 402 | Портал международного сегмента на бесплатном тарифе Битрикс24. На `.com` инфраструктура и выпуск ключей дополнительно требуют тарифа Vibe+ (`INT_VIBE_PLUS_REQUIRED`) | | `BITRIX_UNAVAILABLE` | 502 | Битрикс24 не ответил на регистрацию входящего вебхука | Четыре отказа со статусом 402 приходят от проверки доступа портала — какой именно, зависит от региона лицензии. Проверка касается **только выписки нового ключа**: перевыпуск `POST /v1/keys/:id/rotate`, автоматическое восстановление ключа и передача владения ей не подчиняются, а уже выданные ключи продолжают работать. Права `placement` и `entity` не сохраняются и на успешном пути: у созданного ключа портала они не вернутся в `scopes` ответа, даже если были в запросе рядом с правами на данные. ### `GET /v1/keys/:id` — данные одного ключа Возвращает одну запись ключа без его значения. Состав полей тот же, что у `GET /v1/keys` выше. ```bash curl -H "X-Api-Key: vibe_live_abc123..." \ https://vibecode.bitrix24.tech/v1/keys/key-uuid ``` ### `PATCH /v1/keys/:id` — обновление ключа Можно изменить любое из полей ниже (все необязательны, передавайте только то, что меняете): | Поле | Тип | Описание | |------|-----|----------| | `name` | string | Имя ключа в личном кабинете | | `scopes` | string[] | Список скоупов — см. [Скоупы](./scopes.md) | | `status` | `"ACTIVE"` \| `"REVOKED"` | Активация или отзыв ключа | | `ipWhitelist` | string[] | Список разрешённых IP-адресов | | `rateLimit` | number \| null | Индивидуальный лимит запросов в секунду | | `expiresAt` | ISO-8601 \| null | Срок действия ключа (`null` — бессрочный) | Новый список `scopes` проходит ту же проверку, что и при создании: если после отбрасывания `placement` и `entity` не осталось ни одного права на данные, приходит `400 PERSONAL_KEY_WEBHOOK_SCOPES_INVALID`. ```bash curl -X PATCH \ -H "X-Api-Key: vibe_live_abc123..." \ -H "Content-Type: application/json" \ -d '{"status": "REVOKED"}' \ https://vibecode.bitrix24.tech/v1/keys/key-uuid ``` ### `DELETE /v1/keys/:id` — удаление ключа Удаляет ключ. Если на ключе есть активные серверы, возвращается `409 KEY_HAS_ACTIVE_SERVERS` — серверы нужно удалить первыми. Если ключом управляется агент или бот, удаление возвращает `409 KEY_HAS_LINKED_AGENT` с полями `details.linkedAgentCount`, `details.linkedBotCount` и списком `details.agents` — сначала удалите агента или бота. ```bash curl -X DELETE \ -H "X-Api-Key: vibe_live_abc123..." \ https://vibecode.bitrix24.tech/v1/keys/key-uuid ``` ### `POST /v1/keys/:id/rotate` — перевыпуск ключа Создаёт новый ключ с теми же настройками и оставляет старому переходный период 24 часа. После перевыпуска старый ключ автоматически становится недействительным. Права переносятся с прежнего ключа как есть, новый набор здесь не передаётся. Если у прежнего ключа портала в правах остались только `placement` и `entity`, перевыпуск не пройдёт: там, где ключ выписывает модуль-коннектор, приходит `400 PERSONAL_KEY_WEBHOOK_SCOPES_INVALID`, на остальных аккаунтах — общий отказ `502 BITRIX_UNAVAILABLE`. Сначала добавьте прежнему ключу право на данные через `PATCH /v1/keys/:id`. ```bash curl -X POST \ -H "X-Api-Key: vibe_live_abc123..." \ https://vibecode.bitrix24.tech/v1/keys/key-uuid/rotate ``` ### `GET /v1/feedback` — список тикетов обратной связи Возвращает все тикеты обратной связи на платформе. Поддерживает фильтры по статусу, категории, порталу и постраничную выборку. ```bash curl -H "X-Api-Key: vibe_live_abc123..." \ "https://vibecode.bitrix24.tech/v1/feedback?status=NEW&page=1&limit=50" ``` ### `GET /v1/feedback/:id` — карточка тикета Возвращает тикет со всей цепочкой комментариев. ### `PATCH /v1/feedback/:id` — обновление тикета Меняет статус и резолюцию тикета. ### `POST /v1/feedback/:id/comments` — комментарий к тикету Добавляет комментарий команды в цепочку и одновременно меняет статус. Используется AI-моделями для ответа пользователю. #### Статусы тикетов | Статус | Когда применяется | |--------|-------------------| | `NEW` | Пользователь только что отправил тикет, никто его ещё не смотрел | | `REVIEWING` | Команда взяла тикет в работу, пользователь пока не получает обновлений | | `AWAITING_USER` | Команда задала пользователю уточняющий вопрос — ждём ответа (пользователь получает письмо) | | `NEEDS_REVIEW` | Пользователь ответил на уточнение — команда читает новый комментарий и решает следующий шаг | | `RESOLVED` | Исправление опубликовано в продуктовой среде, пользователь получил уведомление | | `ARCHIVED` | Закрыт без правки кода (дубликат, вне темы, не воспроизводится) | #### Категории тикетов `BUG`, `SUGGESTION`, `DOCS`, `CHAT`, `BOTS`, `OTHER`. #### Фильтры списка `?status=NEW&category=BUG&portalId=&page=1&limit=50`. Параметр `limit` ограничен значением 100. ## Быстрый старт 1. Создайте менеджмент-ключ в личном кабинете (раздел «Менеджмент-ключи») 2. Получите список порталов: `GET /v1/portals` 3. Посмотрите существующие ключи на нужном портале: `GET /v1/keys?portalId=` 4. Создайте API-ключ с нужными скоупами: `POST /v1/keys { portalId, name, scopes }` 5. Используйте полученный API-ключ (`vibe_api_…`) для работы с данными Битрикс24 ## Ограничения - Менеджмент-ключи не могут обращаться к эндпоинтам сущностей Битрикс24 (`/v1/deals`, `/v1/tasks` и другим) - Для работы с данными используйте API-ключ (`vibe_api_`) или ключ авторизации (`vibe_app_`) - При попытке обратиться к неподдерживаемому эндпоинту возвращается `403 MANAGEMENT_KEY_NO_ENTITY_ACCESS` ## Смотрите также - [Ключи и авторизация](./keys-auth.md) - [Скоупы](./scopes.md) - [Быстрый старт](./quickstart.md) - [Оптимизация и batch](./optimization.md) - [Коды ошибок](./errors.md) - [Восстановление доступа к боту](./bots/ownership-recovery.md) --- # Partner Connect Подключение внешних сервисов к Битрикс24: ваше приложение запрашивает у пользователя разрешение на доступ к его порталу и получает API-ключ Вайбкод для дальнейших вызовов. Поток построен по схеме Authorization Code — той же, что у OAuth-провайдеров Google или GitHub. **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `client_id` + `client_secret` партнёра | **Скоупы ключа:** запрашиваются на странице согласия ## Содержание - [Когда применять](#когда-применять) - [Как это работает](#как-это-работает) - [Справочник эндпоинтов](#справочник-эндпоинтов) - [Полный сценарий](#полный-сценарий) — Express-обработчик от и до - [`GET /v1/connect/authorize`](#get-v1-connect-authorize) — старт потока, редирект на согласие - [`POST /v1/connect/token`](#post-v1-connect-token) — обмен кода на API-ключ - [Публичный клиент: поток с PKCE](#публичный-клиент-поток-с-pkce) — приложение без сервера - [Вход с устройства без браузера](#вход-с-устройства-без-браузера) — телевизор, приставка, терминал - [Использование API-ключа](#использование-api-ключа) - [Доступные скоупы](#доступные-скоупы) - [Время жизни и отзыв ключа](#время-жизни-и-отзыв-ключа) - [Безопасность](#безопасность) - [Регистрация партнёра](#регистрация-партнёра) - [Типы клиента](#типы-клиента) — публичный или конфиденциальный, с примерами - [Смотрите также](#смотрите-также) ## Когда применять Сценарий — внешний SaaS-продукт, который интегрируется с порталами Битрикс24 ваших клиентов: CRM-аналитика, синхронизация с 1С, чат-ассистент, конструктор лендингов. Кнопка «Подключить Битрикс24» на вашем сайте запускает поток: пользователь выбирает портал и подтверждает скоупы, ваш сервер получает постоянный API-ключ и работает с порталом от имени пользователя. Если вы пишете приложение, которое ставится **внутри** портала Битрикс24 и работает только с ним, — используйте обычный API-ключ, см. [Ключи и авторизация](/docs/keys-auth). ## Как это работает ``` Ваше приложение → [1. Redirect] → Вайбкод Consent Page → [2. Согласие] ↑ ↓ └──── [4. API-ключ] ←── [3. Code → redirect_uri] ──────────┘ ``` 1. **Redirect** — отправляете пользователя на `/v1/connect/authorize` с `client_id`, `redirect_uri`, `state` и списком скоупов. 2. **Согласие** — пользователь видит страницу Вайбкод, выбирает портал и подтверждает или отклоняет запрошенные скоупы. 3. **Код** — после одобрения пользователь возвращается на `redirect_uri` с параметрами `code` и `state`. При отказе — `redirect_uri?error=access_denied&state=...`. 4. **Обмен** — сервер партнёра отправляет `POST /v1/connect/token` и получает API-ключ. ## Справочник эндпоинтов | Метод | Путь | Описание | |-------|------|----------| | GET | [`/v1/connect/authorize`](#get-v1-connect-authorize) | Старт потока: редирект на страницу согласия | | POST | [`/v1/connect/token`](#post-v1-connect-token) | Обмен одноразового кода на постоянный API-ключ | ## Полный сценарий Пример Express-обработчика, который проводит пользователя через оба эндпоинта от и до. Перед запуском поместите `client_id` и `client_secret`, полученные при регистрации клиента, в переменные окружения, а `redirect_uri` зарегистрируйте у этого клиента. ```javascript import express from 'express' import crypto from 'node:crypto' const app = express() const sessions = new Map() // в продакшене — Redis или БД const CLIENT_ID = process.env.PARTNER_CLIENT_ID const CLIENT_SECRET = process.env.PARTNER_CLIENT_SECRET const REDIRECT_URI = 'https://yourapp.com/callback' // 1. Кнопка «Подключить Битрикс24» ведёт сюда app.get('/connect', (req, res) => { const state = crypto.randomBytes(16).toString('hex') sessions.set(state, { userId: req.user.id, createdAt: Date.now() }) const params = new URLSearchParams({ client_id: CLIENT_ID, redirect_uri: REDIRECT_URI, scope: 'crm task', state, }) res.redirect(`https://vibecode.bitrix24.tech/v1/connect/authorize?${params}`) }) // 2. Вайбкод возвращает пользователя сюда после согласия или отказа app.get('/callback', async (req, res) => { const { code, state, error } = req.query const session = sessions.get(state) if (!session) return res.status(400).send('Неизвестный state') sessions.delete(state) if (error === 'access_denied') { return res.redirect('/dashboard?connect=denied') } // 3. Обмениваем код на API-ключ — серверный запрос с client_secret const tokenRes = await fetch('https://vibecode.bitrix24.tech/v1/connect/token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ grant_type: 'authorization_code', client_id: CLIENT_ID, client_secret: CLIENT_SECRET, code, redirect_uri: REDIRECT_URI, }), }) const data = await tokenRes.json() if (!tokenRes.ok) { // Ошибка приходит в RFC-форме: { error, error_description } return res.status(400).send(`Ошибка обмена: ${data.error}`) } // 4. Сохраняем привязку: пользователь нашего сервиса ↔ портал Битрикс24 await db.connections.upsert({ userId: session.userId, portalDomain: data.portal.domain, portalName: data.portal.name, apiKey: encrypt(data.api_key), // секрет, шифруем перед хранением scopes: data.scopes, }) res.redirect('/dashboard?connect=ok') }) // 5. Дальше используем сохранённый ключ для вызовов от имени пользователя async function listDeals(userId) { const connection = await db.connections.findByUserId(userId) const apiKey = decrypt(connection.apiKey) const res = await fetch('https://vibecode.bitrix24.tech/v1/deals?limit=10', { headers: { 'X-Api-Key': apiKey }, }) return res.json() } ``` Ключевые моменты сценария: - `state` генерируется на сервере и проверяется при возврате — без этой проверки злоумышленник может подсунуть пользователю чужой код. - `client_secret` хранится только на сервере и в браузер не попадает. - API-ключ шифруется перед записью в БД и расшифровывается только в момент вызова. - При `error=access_denied` пользователь видит понятное сообщение, а не страницу с ошибкой обмена. ## GET /v1/connect/authorize Перенаправляет пользователя на страницу согласия Битрикс24 Вайбкод. **Query-параметры:** | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|----------| | `client_id` | string | да | Идентификатор партнёра, полученный при регистрации клиента | | `redirect_uri` | string | да | URL обратного вызова. Должен совпадать с одним из зарегистрированных у клиента | | `state` | string | да | Произвольная строка, которая вернётся вместе с кодом. Защита от CSRF | | `scope` | string | нет | Запрашиваемые права через пробел или запятую: `crm task im`. Если не передать — применяются права, зарегистрированные для клиента. Запрос права за пределами зарегистрированного набора отклоняется | **Пример URL:** ``` https://vibecode.bitrix24.tech/v1/connect/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=https://yourapp.com/callback&scope=crm%20task&state=abc123random ``` **Успешный редирект** после одобрения: ``` https://yourapp.com/callback?code=AUTH_CODE_HERE&state=abc123random ``` **Редирект при отказе** пользователя на странице согласия: ``` https://yourapp.com/callback?error=access_denied&state=abc123random ``` ### Ошибки Ошибки этого эндпоинта приходят двумя разными путями, и обработать нужно оба. **До того как `redirect_uri` проверен** — обычный ответ `400` с телом RFC 6749. Возвращать пользователя некуда: адрес ещё не подтверждён, редирект на непроверенный URL был бы дырой. | HTTP | `error` | Условие | |------|---------|---------| | 400 | `invalid_request` | Не передан один из `client_id`, `redirect_uri`, `state` | | 400 | `invalid_client` | `client_id` неизвестен либо клиент отключён | | 400 | `invalid_request` | `redirect_uri` не совпадает ни с одним зарегистрированным | ```json { "error": "invalid_client", "error_description": "Unknown or inactive client" } ``` **После того как `redirect_uri` проверен** — редирект обратно на него с параметрами `error` и `state` (RFC 6749 §4.1.2.1). Ваш обработчик `redirect_uri` обязан это разбирать. | `error` в редиректе | Условие | |---------------------|---------| | `invalid_scope` | Запрошено право за пределами зарегистрированного набора клиента | | `invalid_request` | Клиенту требуется PKCE, а `code_challenge` не передан либо метод не `S256` | | `access_denied` | Пользователь нажал «Отклонить» на странице согласия | ``` https://yourapp.com/callback?error=invalid_scope&state=abc123random ``` Полный справочник общих ошибок API — [Ошибки](/docs/errors). ## POST /v1/connect/token Обменивает одноразовый код авторизации на постоянный API-ключ. Принимает `application/json` и `application/x-www-form-urlencoded`. **Поля запроса (body):** | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|----------| | `grant_type` | string | да | Всегда `authorization_code`. Без него эндпоинт отвечает `unsupported_grant_type` | | `client_id` | string | да | Идентификатор партнёра | | `client_secret` | string | да | Секрет партнёра. Передавать только с серверной стороны | | `code` | string | да | Код из параметра `code` редиректа | | `redirect_uri` | string | да | Тот же `redirect_uri`, что был передан в `/v1/connect/authorize` | ### Примеры #### curl ```bash curl -X POST https://vibecode.bitrix24.tech/v1/connect/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d grant_type=authorization_code \ -d client_id=YOUR_CLIENT_ID \ -d client_secret=YOUR_CLIENT_SECRET \ -d code=RECEIVED_CODE \ -d redirect_uri=https://yourapp.com/callback ``` #### JavaScript ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/connect/token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ grant_type: 'authorization_code', client_id: 'YOUR_CLIENT_ID', client_secret: 'YOUR_CLIENT_SECRET', code: receivedCode, redirect_uri: 'https://yourapp.com/callback', }), }) const data = await res.json() // data.api_key — постоянный API-ключ Вайбкод // data.portal — выбранный пользователем портал // data.scopes — запрошенные скоупы, data.granted_scopes — права ключа // data.user — пользователь, выдавший доступ ``` ### Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `api_key` | string | API-ключ Вайбкод в формате `vibe_api_...`. Передавать в заголовке `X-Api-Key` при последующих вызовах | | `portal.domain` | string | Домен портала Битрикс24, например `example.bitrix24.ru` | | `portal.name` | string | Название портала | | `scopes` | string[] | Права, запрошенные приложением. На странице согласия пользователь подтверждает набор целиком | | `granted_scopes` | string[] | Права, которые реально несёт выданный ключ. У самостоятельно зарегистрированного партнёрского приложения, как правило, совпадают со `scopes` — разойдутся, если права ключа изменили после согласия | | `user.name` | string | Имя пользователя, выдавшего доступ | | `user.email` | string | Электронная почта пользователя | Два набора прав расходятся только у приложений, которым состав прав назначает сама платформа — например у настольного приложения [Cowork](/docs/cowork). Такое приложение может не запрашивать ничего, тогда `scopes` приходит пустым, а `granted_scopes` перечисляет весь набор ключа. Проверяйте доступ по `granted_scopes`. Поле `granted_scopes` может отсутствовать в ответе, если платформа не смогла прочитать права выданного ключа. Пустым оно при этом не приходит, поэтому отсутствие поля означает «набор неизвестен», а не «прав нет» — в таком ответе ориентируйтесь на `scopes`. Набор в `granted_scopes` отражает то, что записано в ключе. Отдельное право портал Битрикс24 может не подтвердить на своей стороне, поэтому отказ разбирайте по коду ответа Битрикс24, а не по наличию права в списке. ### Пример ответа ```json { "api_key": "vibe_api_...", "portal": { "domain": "example.bitrix24.ru", "name": "Моя компания" }, "scopes": ["crm", "task"], "granted_scopes": ["crm", "task"], "user": { "name": "Иван Иванов", "email": "ivan@example.com" } } ``` ### Пример ответа при ошибке 400 — не передан обязательный параметр: ```json { "error": "invalid_request", "error_description": "Missing client_id, code or redirect_uri" } ``` ### Ошибки Эндпоинт отвечает в форме RFC 6749 — `{ error, error_description }`, без обёртки `success`. Это сделано ради совместимости с готовыми OAuth-библиотеками. | HTTP | `error` | Условие | |------|---------|---------| | 400 | `invalid_request` | Не передан один из `client_id`, `code`, `redirect_uri` | | 400 | `invalid_grant` | Код не существует, истёк, уже был использован, либо `redirect_uri` не совпадает с переданным в `/v1/connect/authorize` | | 400 | `invalid_grant` | Проверка PKCE не прошла: `code_verifier` не соответствует переданному ранее `code_challenge` | | 400 | `invalid_client` | Публичный клиент прислал `client_secret` — публичному клиенту секрет не выдаётся и передавать его нельзя | | 400 | `unsupported_grant_type` | `grant_type` не передан или не равен `authorization_code` | | 401 | `invalid_client` | `client_id` неизвестен, клиент отключён, либо `client_secret` не совпадает | Полный справочник общих ошибок API — [Ошибки](/docs/errors). ## Публичный клиент: поток с PKCE Всё выше описывает конфиденциальный клиент — тот, у которого есть сервер и `client_secret`. Если сервера нет и секрет спрятать негде (мобильное приложение, десктопная программа, одностраничное веб-приложение), регистрируйте публичный клиент. Секрет ему не выдаётся, подлинность подтверждается механизмом PKCE. Отличий от основного потока три, всё остальное совпадает. **1. Приложение генерирует пару на каждый запуск потока.** Случайная строка (`code_verifier`) и её SHA-256-хеш в base64url без выравнивающих знаков `=` (`code_challenge`). ```javascript import crypto from 'node:crypto' const b64url = (buf) => buf.toString('base64url') const verifier = b64url(crypto.randomBytes(32)) const challenge = b64url(crypto.createHash('sha256').update(verifier).digest()) ``` `verifier` держите до конца потока, `challenge` уходит в первый запрос. **2. В `/v1/connect/authorize` добавляются два параметра.** | Параметр | Значение | |----------|----------| | `code_challenge` | Хеш из шага 1 | | `code_challenge_method` | Всегда `S256`. Другие значения отклоняются | Для публичного клиента они **обязательны**: без них поток завершится редиректом `?error=invalid_request`. **3. В `/v1/connect/token` вместо `client_secret` уходит `code_verifier`.** ```bash curl -X POST https://vibecode.bitrix24.tech/v1/connect/token \ -H "Content-Type: application/json" \ -d '{ "grant_type": "authorization_code", "client_id": "YOUR_CLIENT_ID", "code": "RECEIVED_CODE", "redirect_uri": "http://127.0.0.1:9999/callback", "code_verifier": "CODE_VERIFIER" }' ``` Ответ тот же, что у конфиденциального клиента: ```json { "api_key": "vibe_api_...", "scopes": ["crm"], "granted_scopes": ["crm"], "portal": { "domain": "example.bitrix24.ru", "name": "Моя компания" }, "user": { "name": "Иван Иванов", "email": "ivan@example.com" } } ``` **`client_secret` публичному клиенту передавать нельзя** — платформа ответит `400 invalid_client`. Это не придирка: секрет, зашитый в раздаваемое приложение, секретом не является, и поток построен так, чтобы им нельзя было пользоваться. ### Возврат на localhost У программы без своего сайта нет публичного адреса, куда вернуть код. Для таких случаев разрешён возврат на себя: зарегистрируйте `redirect_uri` вида `http://127.0.0.1:9999/callback`, поднимите на время потока временный слушатель на этом порту и закройте его сразу после получения кода. Порт при сверке **не учитывается** — если занят, приложение может слушать любой другой, повторно регистрировать адрес не нужно. Годятся `127.0.0.1`, `localhost` и `[::1]`, схема `http` для них разрешена. Все остальные адреса обязаны быть `https`. ## Вход с устройства без браузера Телевизор, приставка, утилита в терминале — там, где неудобно вводить логин и пароль. Пользователь подтверждает вход на телефоне или компьютере, а доступ получает устройство. Поток описан стандартом RFC 8628. Устройству нужен разрешённый device-режим: он включается платформенным администратором и только проверенным приложениям. Клиент, зарегистрированный самостоятельно, получит `400 unauthorized_client` — это защита пользователей от того, чтобы код подтверждения показывало непроверенное приложение. **Шаг 1. Устройство запрашивает код.** ```bash curl -X POST https://vibecode.bitrix24.tech/v1/connect/device/authorize \ -H "Content-Type: application/json" \ -d '{"client_id":"YOUR_CLIENT_ID","scope":"crm","code_challenge":"ХЕШ","code_challenge_method":"S256"}' ``` ```json { "device_code": "MYQnuWB3H0tR...", "user_code": "54BV-XT8F", "verification_uri": "https://vibecode.bitrix24.tech/connect/device", "verification_uri_complete": "https://vibecode.bitrix24.tech/connect/device?user_code=54BV-XT8F", "expires_in": 899, "interval": 5 } ``` `device_code` — секрет устройства, на экран не выводится. `user_code` показывается пользователю вместе с адресом. `expires_in` — сколько секунд у пользователя есть на подтверждение. **Шаг 2. Пользователь открывает адрес и подтверждает.** На экране подтверждения он видит карточку приложения, запрошенные права, выбор портала и предупреждение о фишинге: подтверждать следует только тот вход, который начал он сам. **Шаг 3. Устройство опрашивает `/v1/connect/token`.** ```bash curl -X POST https://vibecode.bitrix24.tech/v1/connect/token \ -H "Content-Type: application/json" \ -d '{ "grant_type": "urn:ietf:params:oauth:grant-type:device_code", "client_id": "YOUR_CLIENT_ID", "device_code": "DEVICE_CODE", "code_verifier": "CODE_VERIFIER" }' ``` Пока пользователь не подтвердил — `400` с одним из состояний: | `error` | Что делать | |---------|------------| | `authorization_pending` | Ждать и опрашивать дальше с интервалом `interval` | | `slow_down` | Опрос идёт чаще разрешённого. Увеличить интервал на 5 секунд и продолжать | | `access_denied` | Пользователь отклонил. Прекратить опрос | | `expired_token` | Код истёк. Запросить новый с шага 1 | После подтверждения тот же запрос отдаёт `200` с ключом и двумя наборами прав: ```json { "api_key": "vibe_api_...", "scopes": ["crm"], "granted_scopes": ["crm"] } ``` Обратите внимание: здесь объект **уже**, чем в основном потоке, — без блоков `portal` и `user`. Ключ отдаётся **один раз**. Повторный опрос тем же `device_code` вернёт `expired_token`, поэтому сохраняйте ключ сразу. ### Что обязано уметь устройство - **Показывать обратный отсчёт.** Код живёт 15 минут; по истечении показать новый, а не мёртвый экран. - **Соблюдать `interval` и реагировать на `slow_down`.** Опрос чаще разрешённого не ускорит выдачу, а приведёт к отказам. - **Не показывать `device_code`.** На экран идёт только `user_code`. ## Использование API-ключа Полученный ключ имеет тип `APP` и работает как стандартный API-ключ Вайбкод. Передавайте его в заголовке `X-Api-Key`: ```bash curl -H "X-Api-Key: vibe_api_..." \ https://vibecode.bitrix24.tech/v1/deals ``` Один и тот же ключ можно использовать с любым эндпоинтом Вайбкод API в пределах подтверждённых скоупов: список сделок, batch-запросы, агрегация и т. д. В отличие от ключа, созданного в кабинете, партнёрскому ключу платформенные скоупы `vibe:ai` (AI-роутер) и `vibe:search` (веб-поиск) **не** добавляются автоматически — ключ несёт ровно те права, которые пользователь подтвердил на странице согласия. Поэтому вызовы AI-роутера (`/v1/chat/completions`) и веб-поиска (`/v1/search`) через партнёрский ключ по умолчанию возвращают `403`. Партнёрский ключ работает с одним заголовком `X-Api-Key` и **не требует** `Authorization: Bearer `. По префиксу его видно сразу: партнёрский ключ начинается с `vibe_api_`, а ключ OAuth-приложения из каталога Вайбкод — с `vibe_app_`, и для второго сессия пользователя обязательна. ## Доступные скоупы При вызове `/v1/connect/authorize` передавайте те же скоупы, что и при создании стандартного API-ключа в портале Битрикс24. На странице согласия пользователь видит список запрошенных прав и подтверждает его целиком — снять отдельный пункт нельзя, доступны только «Разрешить» и «Отклонить». Итоговый набор приходит в поле `granted_scopes` ответа `/v1/connect/token`, а запрошенный — в поле `scopes` рядом. Актуальный перечень поддерживаемых значений описан в разделе [Ключи и авторизация](/docs/keys-auth) — он пополняется по мере появления новых модулей Битрикс24, поэтому здесь не дублируется. Платформенные права Вайбкод (`vibe:ai`, `vibe:search`, `vibe:infra`, `vibe:storage`, `vibe:feedback`) через саморегистрацию запросить нельзя — см. [Регистрация партнёра](#регистрация-партнёра). ## Время жизни и отзыв ключа - **Код авторизации (`code`)** действует **5 минут** и одноразовый. После обмена через `/v1/connect/token` повторный вызов с тем же кодом вернёт `invalid_grant`. - **Стейт согласия** (внутреннее состояние страницы согласия) живёт 10 минут — если пользователь не подтвердит за это время, ссылку придётся выдавать заново. - **API-ключ** не имеет срока истечения. Действует, пока его не отзовут. Отзыв происходит одним из трёх способов: 1. **Пользователь отзывает доступ сам** — раздел «Подключённые приложения» в его профиле Вайбкод. Это гасит **все** ключи, которые он выдал вашему приложению для этого портала, включая ключи от прежних авторизаций. Доступы других сотрудников того же портала не затрагиваются. 2. **Владелец приложения полностью удаляет клиента** — вызовом `DELETE /api/connect/clients/:id?purge=true` (клиент должен быть предварительно деактивирован); гасятся все ключи, выданные этим клиентом. В кабинете доступна только деактивация — ключи она не трогает. 3. **Платформенный администратор** отзывает выданные клиентом ключи. **Деактивация клиента ключи НЕ отзывает** — она только закрывает выдачу новых: с неактивным клиентом `/v1/connect/authorize` отклонит запрос, а уже выданные ключи продолжат работать. При отзыве ключа все запросы с ним возвращают `401 KEY_INACTIVE`. Если ключ удалён или неизвестен — `401 INVALID_API_KEY`. Партнёр должен корректно обработать оба кода и предложить пользователю повторно авторизоваться. ## Безопасность - **State-параметр** — генерируйте криптостойкую случайную строку на каждый запрос и сверяйте при возврате на `redirect_uri`. Защищает от CSRF. - **`client_secret` — только на сервере.** Никогда не передавайте секрет в браузер, мобильное приложение или клиентский код. Обмен кода на ключ выполняется только серверным запросом. - **Хранение ключа.** API-ключ — секрет, который даёт доступ к данным пользователя. Храните в зашифрованном виде, ограничивайте доступ к строке подключения, не логируйте. - **Привязка `redirect_uri`.** Значение в `/v1/connect/authorize` и `/v1/connect/token` должно совпадать символ в символ — несоответствие приведёт к `invalid_grant`. ## Регистрация партнёра Клиент регистрируется самостоятельно в кабинете Вайбкод — раздел [Connect-приложения](/connect-apps), боковое меню, группа «Доступ». Войдите под учётной записью Вайбкод и нажмите «Зарегистрировать приложение» — `client_id` выдаётся сразу, без заявки и предварительной проверки. В форме заполняются: - название и краткое описание приложения, - идентификатор — строчные латинские буквы, цифры и дефис, - один или несколько `redirect_uri` — адреса `https://` либо локальные `127.0.0.1` и `localhost`, - запрашиваемые права доступа. Набор прав не может быть пустым: регистрация без единого права возвращает `EMPTY_SCOPES`. Приложение без прав не может запросить у пользователя ничего. Тип клиента выбирается при создании и позже не меняется — разбор с примерами в разделе [Типы клиента](#типы-клиента). `client_secret` показывается один раз при создании. Прочитать его повторно нельзя, только перевыпустить действием «Обновить секрет». В ⋮-меню карточки приложения есть два помощника: **«Собрать ссылку»** — конструктор ссылки авторизации (выбор `redirect_uri` и прав, готовый URL и `curl` для обмена кода, для клиента без секрета — одноразовая пара строк PKCE), и **«Как увидит клиент»** — превью страницы согласия ровно в том виде, в каком её увидит пользователь, включая бейдж верификации. Платформенные скоупы `vibe:ai`, `vibe:search`, `vibe:infra`, `vibe:storage` и `vibe:feedback` при саморегистрации недоступны — запрос с ними отклоняется кодом `SCOPE_NOT_ALLOWED`. Их выдаёт платформенный администратор проверенному приложению. Число активных клиентов на одного пользователя ограничено. При достижении предела регистрация возвращает `CLIENT_LIMIT_REACHED`, текущее значение приходит в поле `limit`. Деактивация клиента освобождает место. Новое приложение получает статус «непроверенное» — пользователь видит эту отметку на странице согласия. Повысить статус может платформенный администратор, запрос отправляется действием «Запросить верификацию» в карточке приложения. Заявку могут отклонить с причиной — она приходит владельцу приложения, и после правок заявку подают заново. ### Что снимает отметку «проверено» Отметка держится на том, каким приложение прошло проверку, поэтому правка четырёх полей возвращает статус «непроверенное»: - название, - логотип, - адреса возврата `redirect_uri`, - набор запрашиваемых прав. Описание и адрес сайта на отметку не влияют. Кабинет предупреждает до сохранения: форма показывает подтверждение с перечнем полей, из-за которых отметка будет снята. Без подтверждения правка не сохраняется, ответ — `VERIFICATION_RESET_NOT_CONFIRMED` с тем же перечнем в теле. Заполнение пустого набора прав отметку не снимает, когда выбранные права укладываются в набор, выданный администратором. Сброс касается только отметки. Выданные ключи, подключённые пользователи, платформенные права и разрешённый вход по коду устройства сохраняются. Заявку на проверку подают заново. ## Типы клиента Тип отвечает на один вопрос: есть ли у приложения место, недоступное пользователю, где можно хранить секрет. От ответа зависит, выдаётся ли `client_secret`. ### Конфиденциальный У приложения есть серверная часть. `client_secret` лежит там и никогда не попадает в браузер или на устройство пользователя. Примеры: SaaS-сервис аналитики, который ходит в портал клиента по расписанию. Синхронизация с 1С на вашем сервере. Чат-ассистент, который принимает вебхуки и отвечает от своего бэкенда. Этот тип нужен для потока, описанного на этой странице: обмен кода на ключ выполняется серверным запросом с `client_secret`. ### Публичный Секрет спрятать негде — код целиком выполняется на устройстве пользователя. `client_secret` не выдаётся, вместо него подлинность подтверждает PKCE: приложение генерирует на каждый запуск потока случайную строку, отправляет в `/v1/connect/authorize` её хеш, а в `/v1/connect/token` — саму строку. Перехваченный код без неё не обменивается. Примеры: мобильное приложение. Десктопная программа. Одностраничное веб-приложение без собственного бэкенда. ### Как выбрать Если у приложения есть сервер, который вы контролируете, — конфиденциальный. Если код целиком уезжает пользователю — публичный. Тип задаётся один раз при регистрации. Чтобы сменить его, зарегистрируйте нового клиента. ## Смотрите также - [Ключи и авторизация](/docs/keys-auth) - [Управляющие ключи](/docs/management-keys) - [Ошибки API](/docs/errors) --- # Справочник сущностей Полный перечень сущностей и специализированных API с доступными операциями. Для каждой сущности указан путь, набор операций и требуемый скоуп. Описание общего формата запросов и ответов — в разделе [Обзор API](/docs/entity-api). ## Сущности по разделам ### CRM | Сущность | Путь | Операции | Скоуп | |----------|------|----------|-------| | [Сделки](/docs/entities/deals) | `/v1/deals` | `list` `get` `create` `update` `delete` `fields` `search` `aggregate` `products` | `crm` | | [Контакты](/docs/entities/contacts) | `/v1/contacts` | `list` `get` `create` `update` `delete` `fields` `search` `aggregate` | `crm` | | [Компании](/docs/entities/companies) | `/v1/companies` | `list` `get` `create` `update` `delete` `fields` `search` `aggregate` | `crm` | | [Лиды](/docs/entities/leads) | `/v1/leads` | `list` `get` `create` `update` `delete` `fields` `search` `aggregate` `products` | `crm` | | [Предложения](/docs/entities/quotes) | `/v1/quotes` | `list` `get` `create` `update` `delete` `fields` `search` `aggregate` `products` | `crm` | | [Счета](/docs/entities/invoices) | `/v1/invoices` | `list` `get` `create` `update` `delete` `fields` `search` `aggregate` `products` | `crm` | | [Воронки сделок](/docs/entities/deal-categories) | `/v1/deal-categories` | `list` `get` `create` `update` `delete` `fields` `search` `aggregate` | `crm` | | [Воронки](/docs/entities/categories) | `/v1/categories/:entityTypeId` | `list` `get` `create` `update` `delete` `fields` | `crm` | | [Дела](/docs/entities/activities) | `/v1/activities` | `list` `get` `create` `update` `delete` `fields` `search` `aggregate` | `crm` | | [Привязки дел](/docs/entities/activities/bindings) | `/v1/activities/:activityId/bindings` | `list` `bind` `unbind` `move` | `crm` | | [Конфигурируемые дела](/docs/entities/activities/configurable) | `/v1/activity-configurable` | `create` `get` `update` | `crm` | | [Расшифровки звонков CRM](/docs/entities/activities/transcript) | `/v1/activities/:activityId/transcript` | `get` | `crm` | | [Товары CRM](/docs/entities/products) | `/v1/products` | `list` `get` `create` `update` `delete` `fields` `search` `aggregate` | `crm` | | [Разделы товаров](/docs/entities/product-sections) | `/v1/product-sections` | `list` `get` `create` `update` `delete` `fields` `search` | `crm` | | [Статусы и стадии](/docs/entities/statuses) | `/v1/statuses` | `list` `get` `create` `update` `delete` `fields` `search` `aggregate` | `crm` | | [Валюты](/docs/entities/currencies) | `/v1/currencies` | `list` `get` `create` `update` `delete` `fields` `search` `aggregate` | `crm` | | [Реквизиты](/docs/entities/requisites) | `/v1/requisites` | `list` `get` `create` `update` `delete` `fields` `search` `aggregate` | `crm` | | [Шаблоны реквизитов](/docs/entities/requisite-presets) | `/v1/requisite-presets` | `list` `get` `create` `update` `delete` `fields` `search` | `crm` | | [Банковские реквизиты](/docs/entities/bank-details) | `/v1/bank-details` | `list` `get` `create` `update` `delete` `fields` `search` | `crm` | | [Адреса](/docs/entities/addresses) | `/v1/addresses`, `/v1/addresses/:typeId/:entityTypeId/:entityId` | `list` `get` `create` `update` `delete` `fields` `search` | `crm` | | [Связи реквизитов](/docs/entities/requisite-links) | `/v1/requisite-links`, `/v1/requisite-links/:entityTypeId/:entityId` | `list` `get` `register` `update` `unregister` `fields` `search` | `crm` | | [Комментарии таймлайна](/docs/entities/timelines) | `/v1/timelines` | `list` `get` `create` `update` `delete` `fields` `search` | `crm` | | [Раскладка карточки CRM](/docs/entities/crm-card-config) | `/v1/crm/card-config/:entityTypeId` | `get` `set` `reset` `force-common` | `crm` | ### Смарт-процессы | Сущность | Путь | Операции | Скоуп | |----------|------|----------|-------| | [Смарт-процессы](/docs/entities/smart-processes) | `/v1/smart-processes` | `list` `get` `create` `update` `delete` `fields` `search` `aggregate` | `crm` | | [Элементы смарт-процессов](/docs/entities/items) | `/v1/items/:entityTypeId` | `list` `get` `create` `update` `delete` `fields` `search` `aggregate` `products` | `crm` | ### Задачи | Сущность | Путь | Операции | Скоуп | |----------|------|----------|-------| | [Задачи](/docs/entities/tasks) | `/v1/tasks` | `list` `get` `create` `update` `delete` `fields` `search` `aggregate` | `tasks` | | [Комментарии к задачам](/docs/entities/task-comments) | `/v1/tasks/:taskId/comments` | `list` `get` `create` `update` `delete` | `task` | | [Учёт времени задач](/docs/entities/tasks/time) | `/v1/tasks/:taskId/time` | `list` `get` `create` `update` `delete` | `task` | | [Чат задачи](/docs/entities/tasks/chat) | `/v1/tasks/:taskId/chat/messages` | `get` | `task` | | [История изменений задачи](/docs/task-history) | `/v1/tasks/:taskId/history` | `get` | `task` | | [Стадии канбана задач](/docs/task-stages) | `/v1/tasks/stages/:entityId` | `get` | `task` | | [Scrum (эпики + размещение)](/docs/scrum) | `/v1/scrum/epics`, `/v1/scrum/tasks/:taskId` | `list` `get` `create` `update` | `task` | ### Календарь | Сущность | Путь | Операции | Скоуп | |----------|------|----------|-------| | [События календаря](/docs/entities/calendar-events) | `/v1/calendar-events` | `list` `get` `create` `update` `delete` `fields` `search` | `calendar` | ### Диск | Сущность | Путь | Операции | Скоуп | |----------|------|----------|-------| | [Файлы](/docs/entities/files) | `/v1/files` | `list` `get` `update` `delete` `fields` `search` `upload` `download` `moveto` `copyto` | `disk` | | [Папки](/docs/entities/folders) | `/v1/folders` | `list` `get` `create` `update` `delete` `fields` `search` | `disk` | | [Хранилища](/docs/entities/storages) | `/v1/storages` | `list` `get` `fields` `search` | `disk` | ### Пользователи и соцсеть | Сущность | Путь | Операции | Скоуп | |----------|------|----------|-------| | [Сотрудники](/docs/entities/users) | `/v1/users` | `list` `get` `create` `invite` `update` `delete` `fields` `search` `aggregate` | `user` | | [Отделы](/docs/entities/departments) | `/v1/departments` | `list` `get` `create` `update` `delete` `fields` `search` | `department` | | [Рабочие группы](/docs/entities/workgroups) | `/v1/workgroups` | `list` `get` `create` `update` `delete` `search` `fields` `aggregate` | `sonet_group` | ### Торговый каталог | Сущность | Путь | Операции | Скоуп | |----------|------|----------|-------| | [Каталоги](/docs/entities/catalogs) | `/v1/catalogs` | `list` `get` `search` `fields` | `catalog` | | [Товары каталога](/docs/entities/catalog-products) | `/v1/catalog-products` | `list` `get` `create` `update` `delete` `fields` `search` `aggregate` | `catalog` | | [Свойства товаров каталога](/docs/entities/catalog-product-properties) | `/v1/catalog-product-properties` | `list` `get` `create` `update` `delete` `search` `fields` | `catalog` | | [Значения списочных свойств](/docs/entities/catalog-product-property-enums) | `/v1/catalog-product-property-enums` | `list` `get` `search` `fields` | `catalog` | | [Разделы каталога](/docs/entities/catalog-sections) | `/v1/catalog-sections` | `list` `get` `create` `update` `delete` `fields` `search` | `catalog` | | [Цены каталога](/docs/entities/catalog-prices) | `/v1/catalog-prices` | `list` `get` `create` `update` `delete` `search` `fields` | `catalog` | | [Склады](/docs/entities/warehouses) | `/v1/warehouses` | `list` `get` `create` `update` `delete` `stock` | `catalog` | ### Интернет-магазин | Сущность | Путь | Операции | Скоуп | |----------|------|----------|-------| | [Заказы](/docs/entities/orders) | `/v1/orders` | `list` `get` `create` `update` `delete` `fields` `search` `aggregate` | `sale` | | [Оплаты](/docs/entities/payments) | `/v1/payments` | `list` `get` `create` `update` `delete` `fields` `search` `aggregate` | `sale` | | [Позиции корзины](/docs/entities/basket-items) | `/v1/basket-items` | `list` `get` `create` `update` `delete` `fields` `search` `aggregate` | `sale` | | [Статусы заказов](/docs/entities/order-statuses) | `/v1/order-statuses` | `list` `get` `create` `update` `delete` `fields` `search` `aggregate` | `sale` | ### Сайты | Сущность | Путь | Операции | Скоуп | |----------|------|----------|-------| | [Сайты](/docs/entities/sites) | `/v1/sites` | `list` `get` `create` `update` `delete` `search` `fields` `aggregate` | `landing` | | [Страницы](/docs/entities/pages) | `/v1/pages` | `list` `get` `create` `update` `delete` `search` `fields` `aggregate` | `landing` | ### Генератор документов | Сущность | Путь | Операции | Скоуп | |----------|------|----------|-------| | [Шаблоны документов](/docs/entities/doc-templates) | `/v1/doc-templates` | `list` `get` `create` `update` `delete` `fields` `search` `aggregate` | `documentgenerator` | | [Документы](/docs/entities/documents) | `/v1/documents` | `list` `get` `create` `update` `delete` `fields` `search` | `documentgenerator` | | [Документы по CRM-сущности](/docs/entities/documents/crm-list) | `/v1/crm-documents` | `list` | `crm` | ### Бронирование | Сущность | Путь | Операции | Скоуп | |----------|------|----------|-------| | [Бронирования](/docs/entities/bookings) | `/v1/bookings` | `list` `get` `create` `update` `delete` `search` `fields` | `booking` | ### Бизнес-процессы | Сущность | Путь | Операции | Скоуп | |----------|------|----------|-------| | [Шаблоны бизнес-процессов](/docs/entities/bizproc-templates) | `/v1/bizproc-templates` | `list` `create` `update` `delete` `fields` `search` | `bizproc` | | [Действия бизнес-процессов](/docs/entities/bizproc-activities) | `/v1/bizproc-activities` | `list` `create` `update` `delete` `fields` | `bizproc` | | [Роботы](/docs/entities/bizproc-robots) | `/v1/bizproc-robots` | `list` `create` `update` `delete` `fields` | `bizproc` | ### Открытые линии | Сущность | Путь | Операции | Скоуп | |----------|------|----------|-------| | [Конфигурации открытых линий](/docs/openlines/config) | `/v1/openline-configs` | `list` `get` `create` `update` `delete` `search` `fields` `aggregate` | `imopenlines` | ## Специализированные API Эти API имеют собственные эндпоинты, выходящие за рамки стандартного CRUD: | API | Путь | Скоуп | Описание | |-----|------|-------|----------| | Боты | `/v1/bots` | `imbot` | Платформа ботов (imbot.v2): регистрация, сообщения, чаты, команды, файлы | | Чаты | `/v1/chats` | `im` | IM Chat API: чаты CRM-сущностей, сообщения, групповые чаты | | Бизнес-процессы | `/v1/workflows` | `bizproc` | Запуск, список, завершение процессов, события | | [Уведомления](/docs/notifications) | `/v1/notifications` | `im` | Уведомления сотрудникам Битрикс24 | | [Телефония](/docs/telephony) | `/v1/calls`, `/v1/telephony-lines`, `/v1/voximplant-lines` | `telephony` | Регистрация внешних звонков в CRM, исходящие звонки, линии, статистика | | Триггеры | `/v1/triggers` | `crm` | Триггеры CRM-автоматизации: запуск триггера по сделке/лиду | | Лог таймлайна | `/v1/timeline-logs` | `crm` | Таймлайн CRM: действия, заметки, закрепление, привязка к сущностям | | Посты | `/v1/posts` | `log` | Живая лента: объявления, комментарии | | Пользовательские поля | `/v1/userfields` | `crm` | Пользовательские поля CRM: сделки, лиды, контакты, компании, предложения | | [История стадий](/docs/stage-history) | `/v1/stage-history` | `crm` | История переходов по стадиям CRM | | [Дубликаты](/docs/duplicates) | `/v1/duplicates/find` | `crm` | Поиск дубликатов по телефону/email | | [Scrum](/docs/scrum) | `/v1/scrum` | `task` | Эпики и скрам-размещение задач: создание/переименование эпиков, привязка задачи к эпику, авто-бэклог | | [Чат задачи](/docs/entities/tasks/chat) | `/v1/tasks/:taskId/chat/messages` | `task` | Чтение чата задачи от новых сообщений к старым, курсорная пагинация. Ключу нужен скоуп `im` | | [Расшифровки звонков CRM](/docs/entities/activities/transcript) | `/v1/activities/:activityId/transcript` | `crm` | Готовая AI-расшифровка звонка клиента по `activityId` дела-звонка | | Рабочий день | `/v1/workday` | `timeman` | Учёт рабочего времени: открытие/закрытие дня, статус, настройки | | Пакетные запросы | `/v1/batch` | `*` | До 50 вызовов сущностей в одном запросе (1 единица рейт-лимита) | ## Общие возможности Все эндпоинты сущностей поддерживают: - **[Фильтрация](/docs/filtering):** `?filter[stageId]=NEW` или `?filter[$gte][amount]=1000` (MongoDB-операторы) - **Сортировка:** `?sort=-createdAt` (префикс `-` для сортировки по убыванию) - **Пагинация:** `?limit=50&offset=100` (автопагинация при limit > 50) - **Выбор полей:** `?select=id,title,amount` - **Трансформация полей:** camelCase-имена автоматически конвертируются в имена полей Битрикс24 - **Метаданные полей:** `GET /v1/{entity}/fields` возвращает описание полей, включая пользовательские UF-поля с подписями. Для полей-перечислений возвращается массив `items` с доступными значениями - **Поиск:** `POST /v1/{entity}/search` — расширенный поиск с автоматическим разбиением по датам для больших наборов данных - **Агрегация:** `POST /v1/{entity}/aggregate` — подсчёт, сумма, среднее, минимум, максимум по полям - **Товарные позиции:** для CRM-сущностей с товарами (сделки, лиды, предложения, счета, элементы смарт-процессов) доступны маршруты `GET/POST/PUT/PATCH/DELETE /v1/{entity}/{id}/products` - **[Связанные данные (include)](/docs/includes):** `?include=company,contact` загружает связанные сущности в одном запросе --- # Связанные данные (include) Загрузка связанных сущностей вместе с основными записями в одном запросе. Вместо отдельных вызовов для получения контакта, компании или ответственного — передайте параметр `include`, и Вайбкод вернёт всё в поле `_included`. > Параметр `include` опциональный и работает в трёх местах: > - `GET /v1/{entity}/{id}?include=...` — получение одной записи > - `GET /v1/{entity}?include=...` — получение списка > - `POST /v1/{entity}/search` — поиск (`include` в теле запроса как массив строк) ## Как использовать Перечислите имена связей через запятую: ### curl ```bash curl "https://vibecode.bitrix24.tech/v1/deals/741?include=contact,company" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### JavaScript ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/741?include=contact,company', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() // data._included.contacts — массив контактов сделки // data._included.company — компания (объект или null) ``` Связанные данные появятся в поле `_included` каждой записи: ```json { "success": true, "data": { "id": 741, "title": "Поставка оборудования", "contactId": 71, "companyId": 15, "_included": { "contacts": [ { "id": 71, "name": "Иван", "lastName": "Петров", "phone": [{ "VALUE": "+79161234567" }], "isPrimary": true, "sort": 10 } ], "company": { "id": 15, "title": "ООО Ромашка", "industry": "IT" } } } } ``` ## Два типа связей ### Один-к-одному Сущность содержит поле-ссылку на связанный объект (например, `companyId` у контакта). Результат — один объект или `null`. ``` GET /v1/leads/50?include=contact ``` ```json { "data": { "id": 50, "title": "Заявка с сайта", "contactId": 71, "_included": { "contact": { "id": 71, "name": "Иван", "lastName": "Петров" } } } } ``` Если поле-ссылка пустое или равно 0, возвращается `null`: ```json { "_included": { "contact": null } } ``` ### Много-ко-многим Связь через промежуточную таблицу. Результат — массив объектов с дополнительными полями связи. ``` GET /v1/deals/741?include=contact ``` ```json { "_included": { "contacts": [ { "id": 71, "name": "Иван", "lastName": "Петров", "isPrimary": true, "sort": 10, "roleId": 0 }, { "id": 85, "name": "Мария", "lastName": "Сидорова", "isPrimary": false, "sort": 20, "roleId": 0 } ] } } ``` Обратите внимание: имя связи в запросе — `contact` (ед. число), а в ответе — `contacts` (мн. число). Вайбкод автоматически плюрализует имя для массивов. Дополнительные поля связи (`isPrimary`, `sort`, `roleId`) добавляются к каждому объекту — их значения приходят из промежуточной таблицы, а не из самой сущности. ## Использование в списках и поиске ### curl — список ```bash curl "https://vibecode.bitrix24.tech/v1/deals?limit=10&include=company" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### JavaScript — список ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals?limit=10&include=company', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data, meta } = await res.json() for (const deal of data) { console.log(deal.title, '—', deal._included.company?.title ?? 'без компании') } // meta.includeSkipped === true, если записей > 200 ``` Ответ: ```json { "success": true, "data": [ { "id": 741, "title": "Поставка оборудования", "companyId": 15, "_included": { "company": { "id": 15, "title": "ООО Ромашка" } } }, { "id": 742, "title": "Техподдержка", "companyId": 15, "_included": { "company": { "id": 15, "title": "ООО Ромашка" } } } ], "meta": { "total": 150, "hasMore": true } } ``` Вайбкод дедуплицирует запросы: если несколько записей ссылаются на одну компанию, она загружается один раз. ### curl — поиск В поиске `include` передаётся в теле запроса как массив. ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/deals/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "stageId": "NEW", "amount": { "$gte": 100000 } }, "include": ["contact", "company"], "limit": 50 }' ``` ### JavaScript — поиск ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { stageId: 'NEW', amount: { $gte: 100000 } }, include: ['contact', 'company'], limit: 50, }), }) const { data } = await res.json() ``` ## Несколько связей в одном запросе Можно запросить до 3 связей одновременно: ``` GET /v1/quotes/18?include=deal,contact,company ``` ```json { "_included": { "deal": { "id": 741, "title": "Поставка оборудования" }, "contact": { "id": 71, "name": "Иван", "lastName": "Петров" }, "company": { "id": 15, "title": "ООО Ромашка" } } } ``` ## Лимиты | Параметр | Значение | |----------|---------| | Максимум связей в запросе | 3 | | Максимум записей для include | 200 | Если в списке или поиске больше 200 записей, include **пропускается** и в `meta` добавляется флаг: ```json { "data": [ ... ], "meta": { "hasMore": true, "includeSkipped": true } } ``` Чтобы получить связанные данные для больших выборок — уменьшите `limit` до 200 или меньше. ## Доступные связи по сущностям Узнать доступные include для конкретной сущности можно через эндпоинт полей: ```bash curl "https://vibecode.bitrix24.tech/v1/deals/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` В ответе будет поле `include` со списком доступных связей: ```json { "success": true, "data": { "fields": { ... }, "include": ["contact", "company"] } } ``` Доступные связи зависят от сущности. Какие именно include поддерживает конкретная сущность — указано в документации каждого метода и в ответе `GET /v1/{entity}/fields` (поле `include`). ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INCLUDE_LIMIT_EXCEEDED` | Запрошено более 3 связей | | 400 | `INVALID_INCLUDE` | Связь не найдена. Ответ содержит список доступных связей | Если у сущности вообще нет связей (например, `departments`), любой `include` вернёт `INVALID_INCLUDE` с пустым списком `Available:`. Пример ошибки: ```json { "success": false, "error": { "code": "INVALID_INCLUDE", "message": "Unknown include 'manager'. Available: contact, company, quote" } } ``` ## Смотрите также - [Entity API](./entity-api.md) — CRUD-операции, пагинация, агрегация - [Фильтрация](./filtering.md) — три синтаксиса фильтров - [Batch API](./batch.md) — объединение вызовов - [Все сущности](./entities-index.md) — полный список сущностей - [Коды ошибок](./errors.md) — справочник ошибок платформы --- # AI Router Единый OpenAI-совместимый API для работы с языковыми моделями от разных провайдеров. Бесплатные модели Битрикс24 доступны сразу — для платных и для своих ключей провайдеров (BYOK) подключите учётные данные. **Это API, а не чат на портале.** Диалогового окна для общения с моделью на портале Вайбкод нет — искать его не нужно. Запрос (промпт) вводится в вашем AI-инструменте, агенте или коде (Cursor, IDE-агент, библиотека `openai`, собственное приложение), который обращается к этому API по адресу ниже. Бесплатные модели Битрикс24 работают так же, как платные и BYOK, — через тот же API. **Скоуп:** `vibe:ai` (добавляется автоматически ко всем API-ключам) | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** заголовок `X-Api-Key` или `Authorization: Bearer YOUR_API_KEY` ## Совместимость с OpenAI SDK Все ответы возвращаются в сыром OpenAI-формате. Подключите любой OpenAI-совместимый инструмент (Cursor, IDE-агенты, библиотека `openai`) через стандартные настройки: ``` Base URL: https://vibecode.bitrix24.tech/v1 API Key: ваш ключ vibe_api_... или vibe_app_... ``` SDK по умолчанию передаёт ключ в заголовке `Authorization: Bearer` — Вайбкод принимает оба варианта (`X-Api-Key` и `Authorization: Bearer`). Параметры запроса (`model`, `messages`, `temperature`, `tools`, `stream`, `response_format`) и поля ответа (`id`, `choices`, `usage`) соответствуют контракту `POST /v1/chat/completions` из OpenAI API. ## Разделы документации - [Чат-комплишены](/docs/ai/chat) — генерация ответов модели в синхронном или потоковом режиме (`Server-Sent Events`) - [Модели](/docs/ai/models) — список доступных моделей и детали отдельной модели - [Распознавание речи](/docs/ai/audio) — преобразование аудио в текст через Whisper Large v3 Turbo - [Эмбеддинги](/docs/ai/embeddings) — преобразование текста в векторные представления (формат OpenAI) - [Свои ключи (BYOK)](/docs/ai/credentials) — подключение собственных ключей провайдеров - [Расход и лимиты](/docs/ai/consumption) — статистика по ключу, месячная квота компании и выгодные часы - [Совместимость с OpenAI SDK](#совместимость-с-openai-sdk) — настройка Cursor, IDE-агентов и любых OpenAI-совместимых клиентов - [Жизненный цикл моделей](/docs/ai/models/lifecycle) — поведение `ACTIVE` / `DEPRECATED` / `DISABLED` и связанные заголовки - [Миграция со старых маршрутов](#миграция-со-старых-маршрутов) — для проектов, где остались вызовы `/v1/ai/chat/completions` и аналогичных --- ## Быстрый старт ### 1. Сгенерируйте ответ бесплатной моделью ```bash curl -X POST https://vibecode.bitrix24.tech/v1/chat/completions \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "bitrix/bitrixgpt-5.5", "messages": [{"role": "user", "content": "Что такое CRM?"}] }' ``` Ответ: ```json { "id": "chatcmpl-a1a73c6eb3f180fd", "object": "chat.completion", "created": 1777289339, "model": "bitrix/bitrixgpt-5.5", "choices": [ { "index": 0, "finish_reason": "stop", "message": { "role": "assistant", "content": "CRM — это система управления взаимоотношениями с клиентами." } } ], "usage": { "prompt_tokens": 12, "completion_tokens": 18, "total_tokens": 30 } } ``` ### 2. Посмотрите доступные модели ```bash curl -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/models ``` Возвращает только те модели, для которых у портала настроены учётные данные провайдера. Модели Битрикс24 (`bitrix/*`) доступны всем без отдельных BYOK-ключей. Большинство из них бесплатны. ### 3. Проверьте расход токенов ```bash curl -H "X-Api-Key: YOUR_API_KEY" \ "https://vibecode.bitrix24.tech/v1/ai/usage?days=7" ``` --- ## Типовые сценарии использования - **Классификация лидов:** запросите лиды через [`GET /v1/leads`](/docs/entities/leads/list), пропустите через [чат-комплишен](/docs/ai/chat/completions) с `response_format: json_object`, обновите CRM-поля через [`PATCH /v1/leads/:id`](/docs/entities/leads/update). - **Генерация контента:** прочитайте товары через [`GET /v1/products`](/docs/entity-api), сгенерируйте описания, обновите карточки в каталоге. - **Извлечение данных:** возьмите комментарии из [`GET /v1/timeline-logs`](/docs/timeline-logs), извлеките телефон / email / название компании, запишите в CRM. - **Чат-бот:** зарегистрируйте бота через [`POST /v1/bots`](/docs/bots/management/create), получайте события через [`GET /v1/bots/:botId/events`](/docs/bots/events), генерируйте ответ AI, отправляйте через [`POST /v1/bots/:botId/messages`](/docs/bots/messages). - **Отчёты:** соберите данные через [`POST /v1/batch`](/docs/batch), сгенерируйте сводку, отправьте уведомление. --- ## Полный пример: распознавание звонка → классификация → запись в таймлайн Сценарий: получить аудиозапись звонка, расшифровать через Whisper, классифицировать качество лида через `JSON`-ответ модели, записать результат в таймлайн сделки. ### Шаг 1. Распознавание речи ```bash curl -X POST https://vibecode.bitrix24.tech/v1/audio/transcriptions \ -H "X-Api-Key: YOUR_API_KEY" \ -F "file=@call-recording.mp3" \ -F "language=ru" \ -F "response_format=json" ``` Ответ: ```json { "text": "Здравствуйте, ООО Вектор. Хотим CRM на 50 пользователей, бюджет до 500 тысяч в месяц." } ``` ### Шаг 2. Классификация лида с гарантированным `JSON` ```bash curl -X POST https://vibecode.bitrix24.tech/v1/chat/completions \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "bitrix/bitrixgpt-5.5", "messages": [ { "role": "system", "content": "Классифицируй лид по тексту звонка. Верни JSON: {\"quality\": \"high|medium|low\", \"score\": 0-100, \"reason\": \"...\"}." }, { "role": "user", "content": "ООО Вектор. CRM на 50 пользователей, бюджет до 500 тысяч в месяц." } ], "response_format": {"type": "json_object"} }' ``` Ответ: ```json { "id": "chatcmpl-acdb112cf9cdf9f9", "object": "chat.completion", "model": "bitrix/bitrixgpt-5.5", "choices": [ { "index": 0, "finish_reason": "stop", "message": { "role": "assistant", "content": "{\"quality\":\"high\",\"score\":88,\"reason\":\"Юрлицо, конкретный объём (50 пользователей) и бюджет 500 тысяч в месяц.\"}" } } ], "usage": {"prompt_tokens": 92, "completion_tokens": 36, "total_tokens": 128} } ``` ### Шаг 3. Запись результата в таймлайн сделки Парсим `choices[0].message.content` как `JSON` и отправляем в таймлайн: ```bash curl -X POST https://vibecode.bitrix24.tech/v1/timeline-logs \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "entityType": "deal", "entityId": 1234, "title": "Классификация AI: high (88/100)", "text": "Юрлицо, конкретный объём (50 пользователей) и бюджет 500 тысяч в месяц." }' ``` Все три эндпоинта живут в одном API-ключе и одной авторизации — отдельных интеграций не требуется. --- ## Справочник эндпоинтов | Метод | Путь | Описание | |-------|------|----------| | POST | [`/v1/chat/completions`](/docs/ai/chat/completions) | Генерация ответа модели — синхронно или потоком | | GET | [`/v1/models`](/docs/ai/models/list) | Список доступных моделей | | GET | [`/v1/models/:modelId`](/docs/ai/models/get) | Детали конкретной модели | | POST | [`/v1/audio/transcriptions`](/docs/ai/audio/transcriptions) | Распознавание речи через Whisper | | POST | [`/v1/embeddings`](/docs/ai/embeddings) | Векторные эмбеддинги текста | | GET | [`/v1/ai/usage`](/docs/ai/consumption/usage) | Статистика использования AI по ключу | | GET | [`/v1/ai/quota`](/docs/ai/consumption/quota) | Процент месячной AI-квоты и разбивка по моделям | | GET | [`/v1/off-peak`](/docs/ai/consumption/off-peak) | Расписание выгодных часов AI-квоты | | GET | [`/v1/ai/providers`](/docs/ai/credentials/providers) | Список провайдеров для BYOK | | GET | [`/v1/ai/credentials`](/docs/ai/credentials/list) | Список собственных ключей провайдеров | | POST | [`/v1/ai/credentials`](/docs/ai/credentials/create) | Подключить ключ провайдера (с верификацией) | | PATCH | [`/v1/ai/credentials/:id`](/docs/ai/credentials/update) | Обновить ключ провайдера | | DELETE | [`/v1/ai/credentials/:id`](/docs/ai/credentials/delete) | Удалить ключ провайдера | | POST | [`/v1/ai/credentials/:id/test`](/docs/ai/credentials/test) | Проверить ключ провайдера | | GET | [`/v1/ai/credentials/:id/usage`](/docs/ai/credentials/usage) | Статистика использования по ключу | | POST | [`/v1/ai/credentials/:id/fetch-models`](/docs/ai/credentials/fetch-models) | Загрузить каталог моделей у Custom-провайдера | | GET | [`/v1/ai/credentials/:id/models`](/docs/ai/credentials/models-list) | Список моделей, привязанных к ключу | | POST | [`/v1/ai/credentials/:id/models`](/docs/ai/credentials/models-add) | Добавить модель к ключу вручную | | DELETE | [`/v1/ai/credentials/:credId/models/:modelRowId`](/docs/ai/credentials/models-delete) | Удалить модель, привязанную к ключу | --- ## Коды ошибок Эндпоинты делятся на две группы по формату ответа об ошибке: **Сырой OpenAI-формат** (`/v1/chat/completions`, `/v1/models`, `/v1/audio/transcriptions`): ```json { "error": { "message": "...", "type": "invalid_request_error", "code": "ai_model_not_found" } } ``` `type` принимает значения: `invalid_request_error` (4xx), `insufficient_quota` (402), `service_unavailable` (503), `server_error` (5xx). `code` всегда в нижнем регистре. **V1-формат** (`/v1/ai/usage`, `/v1/ai/credentials/*`, `/v1/ai/providers`): ```json { "success": false, "error": { "code": "not_found", "message": "Credential not found" } } ``` В V1-формате приходят штатные ошибки самих этих эндпоинтов. Непредвиденная ошибка сервера `5xx` на любом маршруте `/v1/ai/*` возвращается в сыром OpenAI-формате. В обратную сторону это тоже работает: отказы по квоте и темпу запросов (`402 ai_quota_exhausted`, `429 ai_pacing_limited`) на OpenAI-совместимых эндпоинтах приходят в конверте с `success: false`. Обработчик ошибок должен принимать оба конверта на любом из маршрутов. | Код | HTTP | Описание | |-----|------|----------| | `scope_missing` | 403 | API-ключу не хватает скоупа `vibe:ai` | | `invalid_request` | 400 | Некорректные параметры запроса | | `no_default_model` | 400 | У портала нет ни одной доступной для вызова модели | | `invalid_image_payload` | 400 | Некорректный `image_url` в массиве `content` | | `invalid_language` | 400 | Код языка не соответствует `ISO 639` | | `no_file` | 400 | Аудиофайл не передан | | `empty_file` | 400 | Файл в multipart присутствует, но тело — 0 байт. Типичная причина — `curl -F "file=path"` без `@` | | `ai_model_not_found` | 404 | Модель не найдена или отключена | | `not_found` | 404 | Сущность (BYOK-ключ, модель) не найдена | | `provider_not_found` | 404 | Провайдер не найден или отключён | | `ai_credentials_not_configured` | 402 | Для модели нет учётных данных провайдера — подключите `BYOK` | | `insufficient_balance` | 402 | Недостаточно средств для платной модели | | `credential_invalid` | 422 | Ключ провайдера не прошёл верификацию | | `already_exists` | 409 | Ключ для этого провайдера уже существует | | `base_url_invalid` | 400 | `baseUrl` Custom-провайдера должен использовать `http` или `https` | | `base_url_private` | 400 | `baseUrl` указывает на приватную сеть или не разрешается в IP-адрес через `DNS` | | `not_custom_provider` | 400 | Ручная регистрация моделей разрешена только для Custom-провайдера | | `provider_list_models_unavailable` | 200 | Custom-провайдер не поддерживает `GET /v1/models` — добавьте модели вручную | | `ai_provider_rejected` | 400 | Провайдер отклонил сам запрос (ответ `400` или `422`). Повторять его без изменений бесполезно | | `ai_provider_unavailable` | 502 | Внешний провайдер вернул `401`/`403`/`5xx` или сетевую ошибку | | `ai_provider_timeout` | 503 | Апстрим не ответил вовремя: таймаут Whisper (15 минут), бюджет не-потокового запроса или ответ провайдера `408` | | `ai_congested` | 429 | Пул AI-кластера перегружен. Запрос не выполнялся, списания нет, повторите его по заголовку `Retry-After` | | `ai_provider_cooldown` | 429 | Кластер моделей временно недоступен, платформа держит короткую паузу. Запрос не выполнялся, списания нет, повторите его по заголовку `Retry-After`. В отличие от соседних 429 у этого ответа нет ни `X-RateLimit-Scope`, ни `X-AI-Admission` | | `model_unavailable` | 503 | Модель отключена и резервной нет | > **Whisper / `/v1/audio/transcriptions`:** окно обработки — до 15 минут. Длинное / шумное аудио может занять несколько минут. Для аудио длиннее ~30 мин стоит делить на части. ### Системные ошибки Применимы к любому эндпоинту API Вайбкод, включая раздел AI Router: | Код | HTTP | Описание | |-----|------|----------| | `MISSING_API_KEY` | 401 | Не передан заголовок `X-Api-Key` или `Authorization: Bearer` | | `INVALID_API_KEY` | 401 | Ключ не существует или отозван | | `RATE_LIMITED` | 429 | Превышен общий лимит запросов V1-эндпоинта вне AI Router. Пауза перед повтором — в `Retry-After` | | `rate_limit_exceeded` | 429 | Превышен минутный лимит AI Router по API-ключу или пользователю. Уровень — в `error.scope` и заголовке `X-RateLimit-Scope`, пауза перед повтором — в `Retry-After` | | `INTERNAL_ERROR` | 500 | Внутренняя ошибка платформы. Повторите запрос, а если ошибка повторяется — отправьте [заявку](/docs/feedback) | Полный список общих ошибок API — [Ошибки](/docs/errors). --- ## Миграция со старых маршрутов Если в коде остались вызовы вида `/v1/ai/chat/completions`, `/v1/ai/models`, `/v1/ai/audio/transcriptions` — они продолжают работать в режиме обратной совместимости. В заголовках ответа приходит: ``` Deprecation: true X-Deprecated-Use: /v1/chat/completions ``` `X-Deprecated-Use` подсказывает канонический путь. Перенесите вызовы на канонические маршруты — это снимает заголовок `Deprecation` и убирает риск удаления старого пути в будущем. | Устаревший путь | Канонический путь | |-----------------|-------------------| | `POST /v1/ai/chat/completions` | [`POST /v1/chat/completions`](/docs/ai/chat/completions) | | `GET /v1/ai/models` | [`GET /v1/models`](/docs/ai/models/list) | | `GET /v1/ai/models/:modelId` | [`GET /v1/models/:modelId`](/docs/ai/models/get) | | `POST /v1/ai/audio/transcriptions` | [`POST /v1/audio/transcriptions`](/docs/ai/audio/transcriptions) | Маршруты `/v1/ai/usage`, `/v1/ai/credentials/*`, `/v1/ai/providers` устаревшего эквивалента не имеют — это канонические пути. --- ## Смотрите также - [Лимиты и оптимизация](/docs/optimization) - [Ключи и авторизация](/docs/keys-auth) - [Таймлайн CRM](/docs/timeline-logs) - [Бот-платформа](/docs/bots) --- # Web Search для AI REST-эндпоинты для веб-поиска от имени AI-агентов и приложений. Один запрос возвращает синтезированный ответ со ссылками на источники, потоковый режим — по мере готовности. Для глубокого исследования с многошаговым агентным циклом — отдельный эндпоинт [`POST /v1/research`](/docs/search/research). **Скоуп:** `vibe:search` (добавляется автоматически при создании ключа) | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` [Быстрый старт](#быстрый-старт) | [Справочник эндпоинтов](#справочник-эндпоинтов) | [Тарификация](#тарификация) | [Коды ошибок](#коды-ошибок) | [Рецепт RAG с LLM](/docs/recipes/web-search-with-llm) ## Разделы документации - [Поиск](/docs/search/run) — синхронный запрос и потоковая передача (SSE) через `POST /v1/search` - [Глубокий поиск](/docs/search/research) — многошаговое агентное исследование `POST /v1/research` - [Провайдеры](/docs/search/providers) — список поисковых движков и их возможностей - [Свои ключи (BYOK)](/docs/search/credentials) — добавление личных ключей для бесплатного поиска ## Какой ключ выбрать Web Search работает с двумя типами ключей. Выбор определяется тем, от чьего имени отправляется запрос. | Сценарий | Ключ | Заголовки запроса | |---------|------|-------------------| | Свой портал, личный скрипт или сервер | Личный API-ключ `vibe_api_…` | `X-Api-Key: vibe_api_…` | | Запрос от имени конечного пользователя в OAuth-приложении | Ключ авторизации `vibe_app_…` | `X-Api-Key: vibe_app_…` + `Authorization: Bearer ` | Подробнее о форматах ключей и получении `session_token` — [Ключи и авторизация](/docs/keys-auth). ## Провайдеры Платформа предоставляет платформенные движки с тарификацией в Вайбах и BYOK-провайдеры с оплатой напрямую у поставщика. Какие именно движки доступны на конкретном инстансе, какой из них платформенный и какова его цена — зависит от настроек инстанса. Актуальный список возвращает [`GET /v1/search/providers`](/docs/search/providers). | Провайдер | Назначение | Тарификация | |-----------|-----------|-----------| | `bitrix-search` | Платформенный веб-поиск. Конкретный движок и его возможности зависят от инстанса — см. [`GET /v1/search/providers`](/docs/search/providers) | платформенный, тариф в Вайбах — см. [`GET /v1/search/providers`](/docs/search/providers) | | `tavily` | Tavily — англоязычный поиск с фильтрами по доменам и времени, оценкой релевантности | 0 Ꝟ (BYOK) | | `brave` | Brave Search — приватный веб-поиск, опциональный суммаризатор в `advanced` | 0 Ꝟ (BYOK) | | `exa` | Exa — нейросетевой/семантический поиск с извлечением полного контента | 0 Ꝟ (BYOK) | | `you-com` | You.com — поиск с цитатами и уточняющими вопросами | 0 Ꝟ (BYOK) | | `linkup` | Linkup — обход веба в реальном времени с режимом deep research | 0 Ꝟ (BYOK) | | `perplexity` | Perplexity Sonar — модели Sonar для поиска и глубокого исследования | 0 Ꝟ (BYOK) | | `jina` | Jina DeepSearch — итеративный цикл «искать → читать → думать», только research | 0 Ꝟ (BYOK) | | `z-ai` | Z.AI Web Search — поиск без синтезированного ответа с датами публикации | 0 Ꝟ (BYOK) | Актуальный список с матрицей возможностей и ценами — [`GET /v1/search/providers`](/docs/search/providers). Какой провайдер платформенный, его цена и движок по умолчанию различаются от инстанса к инстансу. Для всех BYOK-провайдеров нужен ваш собственный ключ — добавляется через [Свои ключи (BYOK)](/docs/search/credentials). BYOK-провайдеры всегда стоят 0 Ꝟ на стороне платформы. ## Поддерживаемые возможности провайдеров Полная матрица возможностей доступна в [`GET /v1/search/providers`](/docs/search/providers) — `capabilities` у каждого провайдера. Ключевые срезы — ниже тремя таблицами по группам. ### Режимы и потоковая передача | Провайдер | `basic` | `advanced` | `research` | Поток | |-----------|:-------:|:----------:|:----------:|:------| | `bitrix-search` | ✓ | ✓ | зависит от инстанса | зависит от инстанса | | `tavily` | ✓ | ✓ | ✓ | буферизованный | | `brave` | ✓ | ✓ | ✗ | буферизованный | | `exa` | ✓ | ✓ | ✓ | буферизованный | | `you-com` | ✓ | ✓ | ✓ | буферизованный | | `linkup` | ✓ | ✓ | ✓ | буферизованный | | `perplexity` | ✓ | ✓ | ✓ | буферизованный | | `jina` | ✗ | ✗ | ✓ | буферизованный | | `z-ai` | ✓ | ✓ | ✗ | буферизованный | Прогрессивный поток отправляет промежуточные события `thinking` / `tool_call` / `answer_delta`. Буферизованный шлёт только `start` и `done`. ### Синтезированный ответ и оформление | Провайдер | `answer` | Цитаты `[N]` | `score` | `publishedDate` | Уточняющие вопросы | |-----------|:--------:|:------------:|:-------:|:----------------:|:-------------------:| | `bitrix-search` | ✓ | зависит от инстанса | зависит от инстанса | зависит от инстанса | ✗ | | `tavily` | ✓ | ✗ | ✓ | ✓ | ✗ | | `brave` | в `advanced` | ✗ | ✗ | ✓ | ✗ | | `exa` | ✓ | ✓ | ✓ | ✓ | ✗ | | `you-com` | ✓ | ✓ | ✗ | ✓ | ✓ | | `linkup` | ✓ | ✓ | ✗ | ✓ | ✗ | | `perplexity` | ✓ | ✓ | ✗ | ✗ | ✗ | | `jina` | ✓ | ✓ | ✗ | ✓ | ✗ | | `z-ai` | ✗ | ✗ | ✗ | ✓ | ✗ | У `brave` поле `answer` приходит только при `search_depth: "advanced"` через опциональный суммаризатор. В `basic` — `null`. ### Фильтры | Провайдер | `include_domains` | `exclude_domains` | `time_range` | |-----------|:-----------------:|:-----------------:|:------------:| | `bitrix-search` | зависит от инстанса | зависит от инстанса | зависит от инстанса | | `tavily` | ✓ | ✓ | ✓ | | `brave` | ✗ | ✗ | ✓ | | `exa` | ✓ | ✓ | ✗ | | `you-com` | ✗ | ✗ | ✗ | | `linkup` | ✗ | ✗ | ✗ | | `perplexity` | ✗ | ✗ | ✗ | | `jina` | ✓ | ✓ | ✗ | | `z-ai` | ✓ | ✗ | ✓ | Когда выбранный провайдер не поддерживает переданный фильтр, запрос завершается без ошибки — фильтр игнорируется. В ответе появляется заголовок `X-Search-Filters-Ignored` со списком пропущенных полей: ``` X-Search-Filters-Ignored: include_domains,time_range ``` Для `brave` при `include_answer: true` и `search_depth: "basic"` дополнительно приходит заголовок `X-Answer-Not-Supported: brave-search-does-not-synthesize-answers`, а поле `answer` в JSON — `null`. В режиме `advanced` тот же провайдер подмешивает суммаризатор и возвращает заполненный `answer`. ## Когда какой провайдер выбрать Короткие ориентиры: - **`bitrix-search`** — платформенный веб-поиск, не требует своего ключа (тарифицируется в Вайбах). Возвращает синтезированный `answer` с источниками — готовый RAG-вывод для AI-агентов без отдельной сборки результата. Конкретные возможности (режим `research`, прогрессивный поток SSE, фильтры) зависят от инстанса — точная матрица в [`GET /v1/search/providers`](/docs/search/providers). - **`tavily`** — фильтры по доменам (`include_domains` / `exclude_domains`), окно времени публикации (`time_range`), числовая оценка релевантности (`score`). Универсальный выбор для англоязычных задач. - **`brave`** — веб-поиск без синтеза `answer` по умолчанию, синтезатор включается на `advanced`. Подходит для англоязычной выдачи и приватных запросов. - **`exa`** — нейросетевой/семантический поиск. Подходит для исследовательских задач, где нужны связанные по смыслу страницы, а не точное совпадение ключевых слов. - **`you-com`** — единственный провайдер с уточняющими вопросами в режиме research. - **`linkup`** — обход веба в реальном времени (`liveData: true`), подходит для запросов про события последних часов. - **`perplexity`** — модели Sonar, OpenAI-совместимый формат, глубокое исследование с цитатами. - **`jina`** — только режим research, итеративный цикл «искать → читать → думать». Через [`POST /v1/search`](/docs/search/run) недоступен. - **`z-ai`** — поиск без синтезированного ответа, отдаёт результаты с датами публикации. ## Быстрый старт Минимальный вызов [`POST /v1/search`](/docs/search/run): текст вопроса в поле `query` и режим `advanced` для агентного поиска с цитированием источников. В ответ приходит синтезированный `answer` с маркерами `[N]` и массив `results` с найденными страницами. ```bash curl -X POST https://vibecode.bitrix24.tech/v1/search \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "query": "что нового в Cursor IDE", "search_depth": "advanced", "max_results": 5 }' ``` Ответ: ```json { "query": "что нового в Cursor IDE", "provider": "bitrix-search", "search_depth": "advanced", "answer": "Cursor 3 — переработка интерфейса IDE [1]. Появилось окно агентов [2].", "results": [ { "id": 1, "url": "https://cursor.com/blog/cursor-3", "title": "Meet the new Cursor", "content": "...", "score": null, "publishedDate": null }, { "id": 2, "url": "https://cursor.com/changelog", "title": "Changelog", "content": "...", "score": null, "publishedDate": null } ], "search_id": "ws_20260430113025_a1b2c3d4", "upstream_search_id": "AG_xyz", "cost_vibes": 5, "duration_ms": 8523 } ``` Маркеры `[1]`, `[2]` в поле `answer` соответствуют значениям `results[].id`. Значение `provider` в ответе (здесь `bitrix-search`) зависит от инстанса — без явного `provider` запрос идёт через движок по умолчанию, настроенный на инстансе. Текущий дефолт показывает поле `defaultProvider` в [`GET /v1/me`](/docs/keys-auth). ## Полный сценарий: RAG с LLM Связка `/v1/search` + `/v1/ai/chat/completions` для ответов LLM, опирающихся на свежие источники с маркерами цитирования `[N]` — готовый рецепт интеграции: → [Веб-поиск + LLM (RAG)](/docs/recipes/web-search-with-llm) ## Тарификация Стоимость указывается в виртуальной валюте платформы — Вайбы (Ꝟ). Списание происходит после успешного ответа провайдера, при ошибке провайдера баланс не меняется. Тариф платформенного провайдера различается от инстанса к инстансу — какой движок платформенный и сколько Ꝟ стоят его режимы `basic` / `advanced` / `research`, возвращает [`GET /v1/search/providers`](/docs/search/providers) в поле `pricing`. BYOK-провайдеры (`tavily`, `brave`, `exa`, `you-com`, `linkup`, `perplexity`, `jina`, `z-ai`) всегда стоят 0 Ꝟ на стороне платформы — вы оплачиваете запросы напрямую у поставщика по его тарифу. Поле `cost_vibes` в ответе показывает фактически списанную сумму. История запросов с разбивкой по провайдерам, расход Вайбов по периодам и средняя длительность доступны в кабинете на странице `/search`. Там же можно добавить, проверить и удалить BYOK-ключи через визуальный интерфейс. Кнопка «Использовать» рядом с каждым провайдером открывает диалог с готовыми сниппетами на cURL, JavaScript, Python, TypeScript SDK и текстовым промптом для AI-ассистентов. ## Лимит частоты - 60 запросов в минуту на портал для [`POST /v1/search`](/docs/search/run). - 20 запросов в минуту на портал для [`POST /v1/research`](/docs/search/research) — глубокое исследование длится в десятки раз дольше обычного поиска. Лимит общий для всех API-ключей портала — они делят его между собой. Распределение нагрузки по нескольким ключам портала предел не поднимает. При превышении возвращается `429 RATE_LIMITED`. ## Справочник эндпоинтов | Метод | Путь | Описание | |-------|------|----------| | POST | [`/v1/search`](/docs/search/run) | Синхронный запрос или потоковая передача | | POST | [`/v1/research`](/docs/search/research) | Глубокое исследование с многошаговым агентным циклом, только SSE | | GET | [`/v1/search/providers`](/docs/search/providers) | Список провайдеров с матрицей возможностей и тарифами | | GET | [`/v1/search/credentials`](/docs/search/credentials/list) | Список своих BYOK-ключей | | POST | [`/v1/search/credentials`](/docs/search/credentials/create) | Добавить BYOK-ключ выбранного провайдера | | DELETE | [`/v1/search/credentials/:id`](/docs/search/credentials/delete) | Удалить BYOK-ключ | | POST | [`/v1/search/credentials/:id/test`](/docs/search/credentials/test) | Проверить BYOK-ключ | ## Каскад выбора ключа Когда в запросе [`POST /v1/search`](/docs/search/run) не передан `provider`, платформа подбирает его в порядке: ключ пользователя (USER BYOK) → ключ портала (PORTAL BYOK) → движок по умолчанию, настроенный на инстансе (его показывает поле `defaultProvider` в [`GET /v1/me`](/docs/keys-auth)). Для [`POST /v1/research`](/docs/search/research) каскад работает иначе. Если поле `provider` опущено, сервер сразу подставляет research-движок по умолчанию, настроенный на инстансе, — USER/PORTAL-дефолт по другому провайдеру (например, `exa`) здесь не учитывается. Если для этого движка нет ни USER, ни PORTAL, ни PLATFORM-ключа, возвращается `404 CREDENTIAL_NOT_FOUND`. Каскад USER → PORTAL → PLATFORM применяется уже **внутри** выбранного провайдера. Чтобы пойти через другой research-провайдер, передавайте `provider` явно. После добавления своего BYOK-ключа с `isDefault: true` платформа использует его автоматически — параметр `provider` можно не указывать. ## Миграция с Tavily Схема запроса повторяет Tavily Search API. Различия: - Адрес: `https://api.tavily.com/search` → `https://vibecode.bitrix24.tech/v1/search`. - Авторизация: поле `api_key` в теле → заголовок `X-Api-Key: YOUR_API_KEY`. - Добавлено опциональное поле `provider` — выбор движка из списка доступных. - Добавлены опциональные поля `topic` (`general` или `news`) и `include_images` — запрос изображений. У Tavily есть эти возможности, у других движков — нет. Неподдерживаемые поля игнорируются и попадают в `ignored_filters`. При наличии своего ключа Tavily добавьте его через [`POST /v1/search/credentials`](/docs/search/credentials/create) и используйте `provider: "tavily"` или сделайте ключ дефолтным. Остальные поля запроса работают идентично. ## Коды ошибок ### Ошибки веб-поиска | Код | HTTP | Описание | |-----|------|---------| | `INVALID_REQUEST` | 400 | Не пройдена валидация — пустой `query`, `query` длиннее лимита, неизвестное значение `provider`, `search_depth`, `topic`, `lang` или `time_range`, превышены лимиты `include_domains` / `exclude_domains` | | `INSUFFICIENT_BALANCE` | 402 | На балансе портала недостаточно Ꝟ для выбранного режима. Переключитесь на BYOK или пополните баланс | | `BILLING_FROZEN` | 402 | Биллинг-аккаунт заморожен — пополните баланс и снимите блокировку в кабинете | | `PROVIDER_NOT_FOUND` | 404 | Передан `provider`, которого нет в системе или он недоступен | | `CREDENTIAL_NOT_FOUND` | 404 | Для запрошенного провайдера у пользователя или портала нет BYOK-ключа, а платформенного ключа нет | | `PROVIDER_DOES_NOT_SUPPORT_SEARCH` | 404 | Запрошен `provider: "jina"` в [`POST /v1/search`](/docs/search/run) — Jina работает только в [`POST /v1/research`](/docs/search/research) | | `PROVIDER_DOES_NOT_SUPPORT_RESEARCH` | 404 | Запрошен `brave` или `z-ai` — либо `bitrix-search`, когда у движка инстанса нет режима research — в [`POST /v1/research`](/docs/search/research). Эти провайдеры работают только в [`POST /v1/search`](/docs/search/run). На инстансе, где `bitrix-search` привязан к движку с research, `/v1/research` его принимает | | `RATE_LIMITED` | 429 | Превышен лимит запросов в минуту на портал | | `UPSTREAM_ERROR` | 401/403/429/502 | Провайдер вернул ошибку, списания нет; поле `upstream_status` в ответе несёт исходный статус провайдера. Для BYOK-ключа ответы провайдера `401` и `403` приходят с тем же статусом — провайдер отверг ваш ключ, повтор без его замены не поможет. Ответ провайдера `429` сохраняет статус для любого ключа и несёт заголовок `Retry-After` — повторите позже. Остальные ошибки провайдера, включая отказ ключа платформенного движка, приходят как `502` — повторите запрос | | `FEATURE_NOT_ENABLED` | 503 | Web Search или глубокое исследование недоступно на этой платформе | | `UPSTREAM_TIMEOUT` | 503 | Провайдер превысил время ожидания запроса. Ответ содержит заголовок `Retry-After: 30` — повторите запрос через указанное в нём время | ### Ошибки BYOK-ключей | Код | HTTP | Описание | |-----|------|---------| | `INVALID_CREDENTIAL` | 400 | При создании BYOK-ключа провайдер отклонил его на этапе предварительной проверки. Запись не сохранена | | `INVALID_REQUEST` | 400 | Не указан `apiKey`, неверный `provider`, имя длиннее 64 символов | ### Системные ошибки | Код | HTTP | Описание | |-----|------|---------| | `MISSING_API_KEY` | 401 | Отсутствует заголовок `X-Api-Key` | | `INVALID_API_KEY` | 401 | Неверный API-ключ | | `KEY_INACTIVE` | 401 | API-ключ деактивирован, заблокирован или истёк | | `SCOPE_DENIED` | 403 | Ключу не хватает скоупа `vibe:search` | | `INTERNAL_ERROR` | 500 | Внутренняя ошибка сервера | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Структура ответа об ошибке ```json { "error": { "code": "INSUFFICIENT_BALANCE", "message": "Insufficient vibes for this search.", "userMessage": "Недостаточно vibes — пополните баланс или добавьте свой BYOK-ключ (см. GET /v1/search/providers).", "hint": "Add a BYOK key to search for free — see GET /v1/search/providers", "required": 5 } } ``` Поля `userMessage` и `required` приходят при биллинговых ошибках `INSUFFICIENT_BALANCE` и `BILLING_FROZEN`. Поле `required` — сумма в Ꝟ, необходимая для запроса. Поле `hint` приходит при этих же биллинговых ошибках, а также при `CREDENTIAL_NOT_FOUND` — там оно подсказывает, как добавить свой BYOK-ключ для выбранного провайдера. ## Смотрите также - [Поиск (POST /v1/search)](/docs/search/run) - [Глубокий поиск (POST /v1/research)](/docs/search/research) - [Провайдеры](/docs/search/providers) - [Свои ключи (BYOK)](/docs/search/credentials) - [Веб-поиск + LLM (RAG)](/docs/recipes/web-search-with-llm) - [Ключи и авторизация](/docs/keys-auth) - [AI Router](/docs/ai) - [Лимиты и оптимизация](/docs/optimization) - [Ошибки](/docs/errors) --- # Поиск дубликатов `POST /v1/duplicates/find` Находит в CRM лиды, контакты и компании, у которых телефон или адрес электронной почты совпадает с переданными значениями. Применяется перед созданием новой записи, чтобы не плодить дубли, при импорте данных из внешних источников и когда запись нужно найти по номеру телефона. Битрикс24 API: `crm.duplicate.findbycomm` Скоуп: `crm` ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|----------| | `type` | string | да | Тип значения для поиска: `phone` или `email` | | `values` | array | да | Список значений для проверки — телефоны или адреса электронной почты. Максимум 20 значений за запрос | | `entityType` | string | нет | Ограничить поиск одним типом: `lead`, `contact` или `company`. Без параметра поиск идёт по всем трём типам | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/duplicates/find \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "type": "phone", "values": ["+79991234567"] }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/duplicates/find \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "type": "phone", "values": ["+79991234567"] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/duplicates/find', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ type: 'phone', values: ['+79991234567'], }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/duplicates/find', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ type: 'phone', values: ['+79991234567'], }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data` | object \| array | Найденные совпадения, сгруппированные по типу сущности. Пустой массив `[]`, если совпадений нет | | `data.lead` | array | ID лидов с совпадающим контактом. Карточки: `GET /v1/leads` | | `data.contact` | array | ID контактов с совпадающим контактом. Карточки: `GET /v1/contacts` | | `data.company` | array | ID компаний с совпадающим контактом. Карточки: `GET /v1/companies` | ## Пример ответа Найдены совпадения — `data` содержит ключи по типам сущностей: ```json { "success": true, "data": { "lead": [105], "contact": [42] } } ``` Совпадений нет — `data` приходит пустым массивом: ```json { "success": true, "data": [] } ``` ## Пример ответа при ошибке 400 — не переданы обязательные параметры: ```json { "success": false, "error": { "code": "MISSING_PARAMS", "message": "Required: type (\"PHONE\" or \"EMAIL\"), values (string array, max 20)" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `MISSING_PARAMS` | Не передан `type` или `values`, либо `values` — пустой массив | | 400 | `TOO_MANY_VALUES` | В `values` больше 20 значений | | 422 | `BITRIX_ERROR` | Недопустимый `type` — текст ошибки приходит в поле `message` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `crm` | | 401 | `TOKEN_MISSING` | У ключа не настроены токены доступа | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Номер находится в любом написании и по любому из номеров записи.** Значения `+7 (999) 123-45-67`, `+79991234567` и `89991234567` найдут одну и ту же запись, как бы номер ни был сохранён на портале. Если у контакта записаны рабочий и мобильный телефоны, метод найдёт его по каждому из них. Поэтому запись по номеру ищут этим методом, а не фильтром `filter.phone` в списке или поиске: тот сравнивает строку с сохранённым значением целиком и видит только первый номер записи — [Фильтр по телефону и почте](/docs/filtering#фильтр-по-телефону-и-почте). Номер передаётся целиком: без кода страны или без ведущей «8» он не опознаётся. **Тип `data` зависит от результата.** При совпадениях это объект с ключами по типам сущностей, при их отсутствии — пустой массив `[]`. Перед обработкой проверяйте тип: `Array.isArray(data)` означает «совпадений нет». **Одно значение может совпасть сразу в нескольких типах.** Если телефон или адрес электронной почты есть и у лида, и у контакта, в ответе придут оба ключа со своими ID. Без `entityType` проверяйте все вернувшиеся группы, а не только первую. ## Смотрите также - [Синтаксис фильтрации](/docs/filtering) - [Контакты](/docs/entities/contacts) - [Лиды](/docs/entities/leads) - [Компании](/docs/entities/companies) - [Справочник сущностей](/docs/entity-api) - [Ошибки](/docs/errors) --- # Почта Почта портала Битрикс24: получение и отправка писем, управление ящиками и преобразование входящих сообщений в задачи, события, чаты и посты. **Скоуп:** `mail` · **Базовый URL:** `https://vibecode.bitrix24.tech/v1` · **Авторизация:** заголовок `X-Api-Key` ## Разделы документации - [Почтовые ящики](/docs/mail/mailboxes) — список, получение, отправители (3 эндпоинта) - [Письма](/docs/mail/messages) — список, чтение, цепочка, отправка, ответ, пересылка, перемещение (7 эндпоинтов) - [Создание объектов из письма](/docs/mail/conversions) — задача, событие, чат, пост, привязка к CRM и её удаление (6 эндпоинтов) - [Получатели](/docs/mail/recipients) — поиск контактов и сотрудников (2 эндпоинта) ## Быстрый старт Два вызова, чтобы убедиться, что API работает: получить список почтовых ящиков и первые письма. ### curl ```bash # Список почтовых ящиков curl "https://vibecode.bitrix24.tech/v1/mail/mailboxes" \ -H "X-Api-Key: YOUR_API_KEY" # Письма указанного ящика curl "https://vibecode.bitrix24.tech/v1/mail/messages?mailboxId=5" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### JavaScript ```javascript const BASE = 'https://vibecode.bitrix24.tech/v1' const headers = { 'X-Api-Key': 'YOUR_API_KEY' } const mbRes = await fetch(`${BASE}/mail/mailboxes`, { headers }) const { data: mailboxes } = await mbRes.json() const mailboxId = mailboxes[0].id const msgsRes = await fetch(`${BASE}/mail/messages?mailboxId=${mailboxId}`, { headers }) const { data } = await msgsRes.json() console.log(`Писем в ящике: ${data.items.length}`) ``` ## Полный пример Сценарий на JavaScript — семь шагов: получить список ящиков, узнать адрес для отправки, отправить письмо, прочитать его, ответить и создать задачу. ```javascript const BASE = 'https://vibecode.bitrix24.tech/v1' const HEADERS = { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' } async function api(method, path, body = null) { const opts = { method, headers: HEADERS } if (body) opts.body = JSON.stringify(body) return (await fetch(`${BASE}${path}`, opts)).json() } // 1. Список почтовых ящиков → mailboxId const { data: mailboxes } = await api('GET', '/mail/mailboxes') const mailboxId = mailboxes[0].id // 2. Адреса отправителя ящика → строка from const { data: sendersData } = await api('GET', `/mail/mailboxes/${mailboxId}/senders`) const from = sendersData.items[0].sender // "Имя " // 3. Отправить письмо const sendRes = await api('POST', '/mail/messages', { from, to: ['colleague@example.com'], subject: 'Запрос по интеграции', body: 'Добрый день, прошу уточнить детали.', }) // → { success: true, data: { success: true, to: ["colleague@example.com"] } } console.log('Отправлено:', sendRes.data.to) // 4. Найти письмо в ящике → id const { data: msgsData } = await api('GET', `/mail/messages?mailboxId=${mailboxId}&limit=5`) const messageId = msgsData.items[0].id // 5. Получить полный текст письма (поле data.item) const { data: msgData } = await api('GET', `/mail/messages/${messageId}`) console.log('Тема:', msgData.item.subject, '| Текст:', msgData.item.body) // 6. Ответить на письмо — письмо задаётся путём const replyRes = await api('POST', `/mail/messages/${messageId}/reply`, { from, to: ['colleague@example.com'], subject: `Re: ${msgData.item.subject}`, body: 'Спасибо, уточнение принято.', }) // → { success: true, data: { success: true, to: ["colleague@example.com"] } } console.log('Ответ отправлен:', replyRes.data.to) // 7. Создать задачу из письма const taskRes = await api('POST', `/mail/messages/${messageId}/task`, { title: 'Обработать входящий запрос', }) // → { success: true, data: { success: true, taskId: 100, messageId: 1000 } } console.log('Задача создана, id:', taskRes.data.taskId) ``` ## Справочник эндпоинтов **Почтовые ящики:** | Метод | Путь | Bitrix24 метод | Описание | |-------|------|----------------|----------| | GET | [`/v1/mail/mailboxes`](/docs/mail/mailboxes/list) | mail.mailbox.list | Список почтовых ящиков | | GET | [`/v1/mail/mailboxes/:id`](/docs/mail/mailboxes/get) | mail.mailbox.get | Получить почтовый ящик | | GET | [`/v1/mail/mailboxes/:id/senders`](/docs/mail/mailboxes/senders) | mail.mailbox.senders | Адреса отправителя ящика | **Письма:** | Метод | Путь | Bitrix24 метод | Описание | |-------|------|----------------|----------| | GET | [`/v1/mail/messages`](/docs/mail/messages/list) | mail.message.list | Список писем | | GET | [`/v1/mail/messages/:id`](/docs/mail/messages/get) | mail.message.get | Получить письмо | | GET | [`/v1/mail/messages/:id/thread`](/docs/mail/messages/thread) | mail.message.thread | Цепочка переписки | | POST | [`/v1/mail/messages`](/docs/mail/messages/send) | mail.message.send | Отправить письмо | | POST | [`/v1/mail/messages/:id/reply`](/docs/mail/messages/reply) | mail.message.reply | Ответить на письмо | | POST | [`/v1/mail/messages/:id/forward`](/docs/mail/messages/forward) | mail.message.forward | Переслать письмо | | POST | [`/v1/mail/messages/move`](/docs/mail/messages/move) | mail.message.movetofolder | Переместить письма | **Создание объектов из письма:** | Метод | Путь | Bitrix24 метод | Описание | |-------|------|----------------|----------| | POST | [`/v1/mail/messages/:id/task`](/docs/mail/conversions/task) | mail.message.createtask | Создать задачу из письма | | POST | [`/v1/mail/messages/:id/calendar-event`](/docs/mail/conversions/calendar-event) | mail.message.createcalendarevent | Создать событие из письма | | POST | [`/v1/mail/messages/:id/chat`](/docs/mail/conversions/chat) | mail.message.createchat | Создать чат из письма | | POST | [`/v1/mail/messages/:id/feed-post`](/docs/mail/conversions/feed-post) | mail.message.createfeedpost | Создать пост Живой ленты | | POST | [`/v1/mail/messages/:id/crm-activity`](/docs/mail/conversions/crm-activity-create) | mail.message.createcrmactivity | Привязать письмо к CRM | | DELETE | [`/v1/mail/messages/:id/crm-activity`](/docs/mail/conversions/crm-activity-delete) | mail.message.removecrmactivity | Удалить дело CRM из письма | **Получатели:** | Метод | Путь | Bitrix24 метод | Описание | |-------|------|----------------|----------| | POST | [`/v1/mail/recipients/contacts`](/docs/mail/recipients/contacts) | mail.recipient.listcontacts | Поиск контактов CRM | | POST | [`/v1/mail/recipients/employees`](/docs/mail/recipients/employees) | mail.recipient.listemployees | Поиск сотрудников портала | ## Коды ошибок ### Ошибки почты | Код | HTTP | Описание | |-----|------|----------| | `SCOPE_DENIED` | 403 | У ключа нет скоупа `mail` | | `TOKEN_MISSING` | 401 | У ключа не настроены токены Битрикс24 | | `INVALID_PARAMS` | 400 | `:id` или `:mailboxId` не является положительным целым числом | | `INVALID_PARAMS` | 400 | Битрикс24 отклонил валидацию параметров запроса | | `NOT_FOUND` | 404 | Неизвестное действие (только для action-эндпоинтов) | | `ENTITY_NOT_FOUND` | 404 | Письмо или ящик не найдены в Битрикс24 | | `BITRIX_ACCESS_DENIED` | 403 | Нет прав на доступ к ящику или сообщению в Битрикс24 | | `RATE_LIMITED` | 429 | Превышен лимит запросов (заголовок `Retry-After: 2`) | | `BITRIX_UNAVAILABLE` | 502 | Битрикс24 вернул ошибку 5xx | | `BITRIX_ERROR` | 422 | Прочие ошибки Битрикс24 | ### Системные ошибки | Код | HTTP | Описание | |-----|------|----------| | `MISSING_API_KEY` | 401 | Не передан заголовок `X-Api-Key` | | `INVALID_API_KEY` | 401 | Неверный или просроченный API-ключ | | `KEY_INACTIVE` | 401 | Ключ деактивирован | | `KEY_EXPIRED` | 401 | Ключ истёк | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Ключи и авторизация](/docs/keys-auth) - [Конвенции Entity API](/docs/entity-api) - [Ошибки](/docs/errors) --- # Открытые линии Открытые линии Битрикс24 (модуль `imopenlines`) — входящие обращения из мессенджеров и социальных сетей, распределение по операторам, интеграция с CRM и оценка качества обслуживания. Раздел покрывает две грани модуля: управление настройками линий и статистику дашборда руководителя контакт-центра. - **Базовый URL:** `https://vibecode.bitrix24.tech` - **Аутентификация:** заголовок `X-Api-Key` (личный ключ) или `X-Api-Key` + `Authorization: Bearer` (OAuth-приложение) - **Скоуп ключа:** `imopenlines` [Быстрый старт](#быстрый-старт) | [Полный пример](#полный-пример) | [Справочник эндпоинтов](#справочник-эндпоинтов) | [Коды ошибок](#коды-ошибок) ## Что входит в раздел | Грань | Назначение | Документация | |---|---|---| | Конфигурация линий | CRUD настроек линии: очередь операторов, рабочее время, интеграция с CRM, приветствие, оценка | [Конфигурация линий](/docs/openlines/config) | | Статистика (дашборд) | Только чтение: агрегаты, сессии, операторы, CSAT, переназначения | ниже в этом разделе | ## Идентификаторы | Идентификатор | Что это | Где взять | |---|---|---| | `configId` | Открытая линия | [`GET /v1/openline-configs`](/docs/openlines/config/list) | | `sessionId` | Сессия (диалог) Открытой линии | [`POST /v1/openlines/sessions/search`](/docs/openlines/sessions) | | `chatId` | IM-чат, привязанный к сессии | поле `chatId` в ответе `sessions/search` | ## Конфигурация линий Управление настройками открытых линий — создание, список, получение, изменение, удаление, поиск. Общедоступно, раскатки обновления не требует. Здесь же живут два действия оператора над диалогом — принять (`answer`) и завершить (`finish`). Полная документация: [Конфигурация линий](/docs/openlines/config). ## Статистика (дашборд) > **Методы статистики в процессе раскатки — выходят в обновлении `imopenlines 26.700.0`.** Доступны не на всех порталах Битрикс24. Если на вашем портале методы ещё не доступны, API вернёт `422 METHOD_NOT_YET_AVAILABLE` — это не ошибка интеграции, а признак того, что обновление пока не приехало на портал. Список обращений с метриками, нагрузка операторов в реальном времени, агрегаты по линии, оценки клиентов (CSAT) и история переназначений. Все методы — только чтение. Данные видны в пределах прав пользователя, от имени которого работает ключ: если у него нет доступа ни к одной линии, метод возвращает пустой результат (или нулевые агрегаты), а не ошибку. Методам нужен доступ к статистике Открытых линий — право `report_open_lines`. Без него запрос вернёт `403 B24_TARIFF_RESTRICTION`. | Эндпоинт | Назначение | |---|---| | [`POST /v1/openlines/stats`](/docs/openlines/stats) | Агрегаты по линии за период | | [`GET /v1/openlines/operators`](/docs/openlines/operators) | Операторы: статус и нагрузка в реальном времени | | [`POST /v1/openlines/sessions/search`](/docs/openlines/sessions) | Список сессий с фильтрами | | [`POST /v1/openlines/sessions/stats`](/docs/openlines/sessions/stats) | Метрики по конкретным сессиям, до 100 за вызов | | [`POST /v1/openlines/ratings/search`](/docs/openlines/ratings) | Сессии с оценкой клиента за период | | [`POST /v1/openlines/sessions/transfers`](/docs/openlines/sessions/transfers) | История переназначений, до 50 сессий за вызов | Все шесть методов выходят в обновлении `imopenlines 26.700.0`. Имена методов Битрикс24 для сверки с документацией Битрикс24 — в [Справочнике эндпоинтов](#справочник-эндпоинтов). ## Типичные сценарии | Сценарий | Эндпоинты | |---|---| | Исторический отчёт по обращениям за период | [POST /v1/openlines/sessions/search](/docs/openlines/sessions) | | Монитор очереди и нагрузки операторов в реальном времени | [GET /v1/openlines/operators](/docs/openlines/operators) | | Дашборд с оценками клиентов (CSAT) | [POST /v1/openlines/ratings/search](/docs/openlines/ratings), [POST /v1/openlines/stats](/docs/openlines/stats) | | Сводный KPI по линии (по часам и каналам) | [POST /v1/openlines/stats](/docs/openlines/stats) | | Карточка сессии для разбора жалоб | [POST /v1/openlines/sessions/stats](/docs/openlines/sessions/stats) | | Анализ переназначений между операторами | [POST /v1/openlines/sessions/transfers](/docs/openlines/sessions/transfers) | ## Рекомендации - Для сводных показателей используйте `stats` — он считает агрегаты на стороне Битрикс24. Не собирайте те же цифры клиентской агрегацией через `sessions/search`: это упирается в лимит запросов REST Битрикс24. - `operators` отдаёт данные почти в реальном времени (статус и счётчик активных чатов читаются раздельно). Для виджета мониторинга опрашивайте метод не чаще одного раза в 30 секунд. - `stats` — тяжёлый метод: запрашивайте его не чаще одного раза в 30–60 секунд и кэшируйте результат на своей стороне. - Статистика звонков живёт отдельно — `GET /v1/calls/statistics`. Статистика Открытых линий использует POST-формы, потому что несёт богатые фильтры. ## Быстрый старт Агрегаты по линии за июнь: ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/openlines/stats" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "dateFrom": "2026-06-01T00:00:00+03:00", "dateTo": "2026-06-30T23:59:59+03:00", "configId": 3 }' ``` ```json { "success": true, "data": { "totalSessions": 340, "closedSessions": 318, "spamSessions": 4, "avgWaitAnswer": 42.7, "avgSessionDuration": 612.3, "likeCount": 210, "dislikeCount": 15, "votedSessions": 225, "positiveRate": 0.9333, "kpiFirstAnswerOk": 300, "kpiFirstAnswerFail": 18, "sessionsBySource": [{ "source": "livechat", "count": 200 }, { "source": "whatsapp", "count": 140 }], "sessionsByHour": [0,0,0,0,0,0,2,10,25,40,38,30,28,22,20,25,30,20,15,10,8,5,3,1], "sessionsByOperator": [{ "operatorId": 42, "count": 120, "avgWaitAnswer": 38.1, "positiveRate": 0.95 }] } } ``` ## Полный пример Отчёт «обращения за месяц с разбором проблемных сессий»: 1. `POST /v1/openlines/stats` c `dateFrom`/`dateTo` — сводные показатели по линии. 2. `POST /v1/openlines/sessions/search` c тем же периодом и `limit: 50` — первая страница списка сессий. Пагинация по страницам: увеличивайте `offset` на `limit`, пока `data.hasNextPage` равно `true`. 3. `POST /v1/openlines/sessions/stats` c массивом `sessionId` (до 100) — детальные метрики выбранных сессий. Для стабильной постраничной выгрузки фиксируйте верхнюю границу периода: возьмите `dateCreateTo` равным моменту старта выгрузки. Без фиксированной границы новые сессии, пришедшие во время листания, сдвигают страницы, и записи на стыках могут повториться или пропасть. ## Справочник эндпоинтов Все 16 эндпоинтов раздела: | Метод | Путь | Bitrix24 метод | Описание | |-------|------|---------------|---------| | POST | [/v1/openline-configs](/docs/openlines/config/create) | imopenlines.config.add | Создать конфигурацию линии | | GET | [/v1/openline-configs](/docs/openlines/config/list) | imopenlines.config.list.get | Список конфигураций | | GET | [/v1/openline-configs/:id](/docs/openlines/config/get) | imopenlines.config.get | Конфигурация по идентификатору, с очередью операторов | | PATCH | [/v1/openline-configs/:id](/docs/openlines/config/update) | imopenlines.config.update | Обновить конфигурацию | | DELETE | [/v1/openline-configs/:id](/docs/openlines/config/delete) | imopenlines.config.delete | Удалить конфигурацию | | POST | [/v1/openline-configs/search](/docs/openlines/config/search) | imopenlines.config.list.get | Поиск конфигураций по фильтру | | GET | [/v1/openline-configs/fields](/docs/openlines/config/fields) | — | Схема полей конфигурации | | POST | [/v1/openline-configs/aggregate](/docs/openlines/config/aggregate) | imopenlines.config.list.get | Агрегация по конфигурациям | | POST | [/v1/openlines/operator/answer](/docs/openlines/config) | imopenlines.operator.answer | Принять диалог оператором | | POST | [/v1/openlines/operator/finish](/docs/openlines/config) | imopenlines.operator.finish | Завершить диалог оператором | | POST | [/v1/openlines/stats](/docs/openlines/stats) | imopenlines.v2.Stat.get | Агрегаты по линии за период | | GET | [/v1/openlines/operators](/docs/openlines/operators) | imopenlines.v2.Operator.list | Операторы: статус и нагрузка в реальном времени | | POST | [/v1/openlines/sessions/search](/docs/openlines/sessions) | imopenlines.v2.Session.list | Список сессий с фильтрами | | POST | [/v1/openlines/sessions/stats](/docs/openlines/sessions/stats) | imopenlines.v2.Session.Stat.get | Метрики выбранных сессий, до 100 за вызов | | POST | [/v1/openlines/ratings/search](/docs/openlines/ratings) | imopenlines.v2.Session.Rating.list | Сессии с оценкой клиента за период | | POST | [/v1/openlines/sessions/transfers](/docs/openlines/sessions/transfers) | imopenlines.v2.Session.Transfer.list | История переназначений, до 50 сессий за вызов | Конфигурация линий и действия оператора работают на любом портале. Шесть методов статистики выходят в обновлении `imopenlines 26.700.0` — до его доезда на портал они отвечают `422`, см. [Статистика (дашборд)](#статистика-дашборд). У `GET /v1/openline-configs/fields` вызова Битрикс24 нет — схему полей отдаёт Вайбкод. ## Коды ошибок ### Ошибки Открытых линий | HTTP | Код | Когда | |---|---|---| | 403 | `B24_TARIFF_RESTRICTION` | Тариф портала не включает статистику Открытых линий (право `report_open_lines`) | | 422 | `METHOD_NOT_YET_AVAILABLE` | Обновление `imopenlines 26.700.0` ещё не приехало на портал. Ответ содержит поле `error.release` со значением `imopenlines 26.700.0` — [разбор кода](/docs/errors#method_not_yet_available-422). После доезда обновления метод начинает работать. Если тариф не включает статистику, код при вызове сменится на `403 B24_TARIFF_RESTRICTION` | | 400 | `INVALID_JSON_BODY` | Тело запроса не разобралось как JSON. Приходит на всех пяти методах с телом — `stats`, `sessions/search`, `ratings/search`, `sessions/stats`, `sessions/transfers`. Проверка идёт до валидации полей, поэтому про отсутствующие параметры ответ ничего не говорит | | 400 | `MISSING_PARAMS` | Не переданы обязательные параметры (период у `stats`/`ratings`, `sessionId` у батч-методов) | | 400 | `INVALID_PARAMS` | Тело запроса не объект, либо нечисловые/некорректные значения там, где ожидаются числа | | 400 | `BATCH_LIMIT_EXCEEDED` | Массив `sessionId` превышает лимит метода (100 для `sessions/stats`, 50 для `sessions/transfers`) | При отказе Битрикс24 ответ приходит как `422 BITRIX_ERROR`, а сырой код Битрикс24 дублируется в поле `error.b24Code`: | `error.b24Code` | Когда | |---|---| | `PERIOD_REQUIRED` | Период не распознан Битрикс24 (например, дата в неизвестном формате) | | `PERIOD_TOO_LARGE` | Период превышает 1 год | | `INVALID_FILTER` | Недопустимое значение фильтра или формат даты | | `OFFSET_TOO_LARGE` | `offset` превышает максимум — сузьте период или фильтры | ### Системные ошибки Общие коды (`SCOPE_DENIED`, `TOKEN_MISSING`, `RATE_LIMITED` и другие) — на странице [Ошибки API](/docs/errors). ## Смотрите также - [Конфигурация линий](/docs/openlines/config) - [Чаты и сообщения](/docs/chats) - [Журнал изменений API](/docs/changelog) --- # Bot: Chats # Чаты Создавайте групповые чаты от имени бота, настраивайте их, добавляйте и удаляйте участников, назначайте менеджеров и владельца. **Скоуп:** `imbot` | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` ## Операции - [Создать чат](./chats/create.md) — `POST /v1/bots/:botId/chats` - [Получить чат](./chats/get.md) — `GET /v1/bots/:botId/chats/:dialogId` - [Обновить чат](./chats/update.md) — `PATCH /v1/bots/:botId/chats/:dialogId` - [Покинуть чат](./chats/leave.md) — `POST /v1/bots/:botId/chats/:dialogId/leave` - [Назначить владельца](./chats/set-owner.md) — `POST /v1/bots/:botId/chats/:dialogId/owner` - [Добавить участников](./chats/user-add.md) — `POST /v1/bots/:botId/chats/:dialogId/users` - [Удалить участника](./chats/user-delete.md) — `DELETE /v1/bots/:botId/chats/:dialogId/users` - [Список участников](./chats/user-list.md) — `GET /v1/bots/:botId/chats/:dialogId/users` - [Добавить менеджеров](./chats/manager-add.md) — `POST /v1/bots/:botId/chats/:dialogId/managers` - [Удалить менеджеров](./chats/manager-delete.md) — `DELETE /v1/bots/:botId/chats/:dialogId/managers` --- # Bot: Create ## Создать чат `POST /v1/bots/:botId/chats` Создаёт новый групповой чат от имени бота. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `fields.title` | string | нет | Название чата | | `fields.description` | string | нет | Описание чата | | `fields.color` | string | нет | Цвет чата (16 именованных цветов). Некорректные значения назначаются автоматически | | `fields.avatar` | string | нет | URL аватара чата | | `fields.userIds` | number[] | нет | Массив ID пользователей для добавления | | `fields.ownerId` | number | нет | ID владельца. Если не указан — владельцем становится бот | | `fields.message` | string | нет | Первое сообщение в чате | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/chats \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "fields": { "title": "Чат поддержки", "description": "Канал технической поддержки", "userIds": [1, 5, 12], "color": "AZURE" } }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/chats \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "fields": { "title": "Чат поддержки", "description": "Канал технической поддержки", "userIds": [1, 5, 12], "color": "AZURE" } }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/chats', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ fields: { title: 'Чат поддержки', description: 'Канал технической поддержки', userIds: [1, 5, 12], color: 'AZURE', }, }), }) const { success, data } = await res.json() console.log('Chat ID:', data.chat.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/chats', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ fields: { title: 'Чат поддержки', description: 'Канал технической поддержки', userIds: [1, 5, 12], color: 'AZURE', }, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `chat.id` | number | ID созданного чата | | `chat.dialogId` | string | ID диалога (`chatXXX`) | | `chat.name` | string | Название чата | | `chat.owner` | number | ID владельца | | `chat.type` | string | Тип чата | | `chat.color` | string | Цвет чата | | `chat.dateCreate` | string | Дата создания (ISO 8601) | | `chat.permissions` | object | Права в чате | | `users` | array | Массив участников чата | ## Пример ответа ```json { "success": true, "data": { "chat": { "id": 3555, "dialogId": "chat3555", "name": "Чат поддержки", "type": "chat", "owner": 42, "color": "#4ba984", "description": "", "dateCreate": "2026-04-13T17:12:03+03:00", "permissions": { "manageUsersAdd": "member", "manageUsersDelete": "manager", "manageSettings": "owner", "canPost": "member" } }, "users": [ { "id": 42, "name": "Техподдержка", "active": true, "bot": true } ] } } ``` ## Пример ответа при ошибке 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-ключу | | 422 | `BITRIX_ERROR` | Ошибка Битрикс24 при создании чата | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Владелец по умолчанию:** если `ownerId` не указан, владельцем чата становится бот. **Некорректные цвета:** если передать несуществующий цвет, Битрикс24 назначит цвет автоматически. ## Смотрите также - [Получить чат](/docs/bots/chats/get) - [Добавить участников](/docs/bots/chats/user-add) - [Сообщения](/docs/bots/messages) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Get ## Получить чат `GET /v1/bots/:botId/chats/:dialogId` Возвращает информацию о чате. Бот должен быть участником чата. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `botId` (path) | number | да | ID бота | | `dialogId` (path) | string | да | ID диалога: `chatXXX` для групповых, числовой ID пользователя для личных | ## Примеры ### curl — личный ключ ```bash curl https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456 \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456 \ -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/chats/chat456', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Чат:', data.name) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID чата | | `dialogId` | string | ID диалога (`chatXXX`) | | `type` | string | Тип чата | | `name` | string | Название чата | | `description` | string | Описание | | `owner` | number | ID владельца | | `avatar` | string | URL аватара | | `color` | string | Цвет чата | | `entityType` | string | Тип связанной сущности | | `entityId` | string | ID связанной сущности | | `dateCreate` | string | Дата создания (ISO 8601) | ## Пример ответа ```json { "success": true, "data": { "id": 456, "dialogId": "chat456", "type": "chat", "name": "Чат поддержки", "description": "Канал технической поддержки", "owner": 42, "avatar": "", "color": "AZURE", "entityType": "", "entityId": "", "dateCreate": "2026-03-31T10:30:00+03:00" } } ``` ## Пример ответа при ошибке 403 — бот не является участником чата: ```json { "success": false, "error": { "code": "BITRIX_ACCESS_DENIED", "message": "Access denied" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_BOT_ID` | `botId` не является числом | | 404 | `BOT_NOT_FOUND` | Бот с таким ID не найден | | 403 | `BOT_ACCESS_DENIED` | Бот принадлежит другому API-ключу | | 403 | `BITRIX_ACCESS_DENIED` | Бот не является участником чата | | 422 | `BITRIX_ERROR` | Другая ошибка Битрикс24, текст в `message` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Обновить чат](/docs/bots/chats/update) - [Список участников](/docs/bots/chats/user-list) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Leave ## Покинуть чат `POST /v1/bots/:botId/chats/:dialogId/leave` Бот покидает групповой чат. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `botId` (path) | number | да | ID бота | | `dialogId` (path) | string | да | ID диалога (`chatXXX`) | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/leave \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/leave \ -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/chats/chat456/leave', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/leave', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.result` | boolean | `true` при успешном выходе | ## Пример ответа ```json { "success": true, "data": { "result": true } } ``` ## Пример ответа при ошибке 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-ключу | | 422 | `BITRIX_ERROR` | Ошибка Битрикс24 (текст ошибки в `message`) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать чат](/docs/bots/chats/create) - [Удалить участника](/docs/bots/chats/user-delete) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Manager Add ## Добавить менеджеров `POST /v1/bots/:botId/chats/:dialogId/managers` Назначает пользователей менеджерами чата. Менеджеры имеют расширенные права: управление участниками и настройками. Бот должен быть владельцем чата. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `userIds` | number[] | да | Массив ID пользователей для назначения менеджерами | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/managers \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "userIds": [5, 12] }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/managers \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "userIds": [5, 12] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/managers', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ userIds: [5, 12] }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/managers', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ userIds: [5, 12] }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.result` | boolean | `true` при успешном назначении | ## Пример ответа ```json { "success": true, "data": { "result": true } } ``` ## Пример ответа при ошибке 403 — у бота нет прав на управление чатом: ```json { "success": false, "error": { "code": "BITRIX_ACCESS_DENIED", "message": "Access denied" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_BOT_ID` | `botId` не является числом | | 404 | `BOT_NOT_FOUND` | Бот с таким ID не найден | | 403 | `BOT_ACCESS_DENIED` | Бот принадлежит другому API-ключу | | 403 | `BITRIX_ACCESS_DENIED` | Бот не является участником чата или не имеет прав, требуется роль владельца | | 422 | `BITRIX_ERROR` | Другая ошибка Битрикс24, текст в `message` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Только владелец:** добавить менеджеров может только владелец чата, не менеджер и не обычный участник. **Аддитивная операция:** новые менеджеры добавляются к существующим, а не заменяют их. **Пользователи не в чате игнорируются:** если в `userIds` есть ID пользователей, не являющихся участниками чата, они пропускаются без ошибки. ## Смотрите также - [Удалить менеджеров](/docs/bots/chats/manager-delete) - [Список участников](/docs/bots/chats/user-list) - [Назначить владельца](/docs/bots/chats/set-owner) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Manager Delete ## Удалить менеджеров `DELETE /v1/bots/:botId/chats/:dialogId/managers` Снимает роль менеджера с указанных пользователей. Бот должен быть владельцем чата. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `userIds` | number[] | да | Массив ID пользователей для снятия роли менеджера | ## Примеры ### curl — личный ключ ```bash curl -X DELETE https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/managers \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "userIds": [5] }' ``` ### curl — OAuth-приложение ```bash curl -X DELETE https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/managers \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "userIds": [5] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/managers', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ userIds: [5] }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/managers', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ userIds: [5] }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.result` | boolean | `true` при успешном удалении роли | ## Пример ответа ```json { "success": true, "data": { "result": true } } ``` ## Пример ответа при ошибке 403 — у бота нет прав на управление чатом: ```json { "success": false, "error": { "code": "BITRIX_ACCESS_DENIED", "message": "Access denied" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_BOT_ID` | `botId` не является числом | | 404 | `BOT_NOT_FOUND` | Бот с таким ID не найден | | 403 | `BOT_ACCESS_DENIED` | Бот принадлежит другому API-ключу | | 403 | `BITRIX_ACCESS_DENIED` | Бот не является участником чата или не имеет прав, требуется роль владельца | | 422 | `BITRIX_ERROR` | Другая ошибка Битрикс24, текст в `message` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Только владелец:** снять роль менеджера может только владелец чата. ## Смотрите также - [Добавить менеджеров](/docs/bots/chats/manager-add) - [Список участников](/docs/bots/chats/user-list) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Set Owner ## Назначить владельца `POST /v1/bots/:botId/chats/:dialogId/owner` Передаёт права владельца чата другому пользователю. Бот должен быть текущим владельцем чата. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `userId` | number | да | ID нового владельца | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/owner \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "userId": 5 }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/owner \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "userId": 5 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/owner', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ userId: 5 }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/owner', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ userId: 5 }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.result` | boolean | `true` при успешной смене владельца | ## Пример ответа ```json { "success": true, "data": { "result": true } } ``` ## Пример ответа при ошибке 403 — бот не является владельцем чата: ```json { "success": false, "error": { "code": "BITRIX_ACCESS_DENIED", "message": "Access denied" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_BOT_ID` | `botId` не является числом | | 404 | `BOT_NOT_FOUND` | Бот с таким ID не найден | | 403 | `BOT_ACCESS_DENIED` | Бот принадлежит другому API-ключу | | 403 | `BITRIX_ACCESS_DENIED` | Бот не является участником чата или не является его владельцем | | 422 | `BITRIX_ERROR` | Другая ошибка Битрикс24, текст в `message` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Только владелец:** передать права может только текущий владелец чата. Менеджеры и обычные участники не могут. ## Смотрите также - [Добавить менеджеров](/docs/bots/chats/manager-add) - [Получить чат](/docs/bots/chats/get) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Update ## Обновить чат `PATCH /v1/bots/:botId/chats/:dialogId` Обновляет настройки чата. Бот должен быть участником чата. Обновляются только переданные поля. > **Две формы тела запроса — обе корректны.** Платформа принимает плоскую запись (`{ title, description, ... }`) и формат Битрикс24 с обёрткой `fields`. Если в теле есть `fields`, запрос передаётся в Битрикс24 без изменений. Иначе известные поля верхнего уровня автоматически разворачиваются в `fields.*`. ## Поля запроса (body) | Параметр (плоский) | Параметр (формат Битрикс24) | Тип | Описание | |---|---|-----|---------| | `title` | `fields.title` | string | Новое название чата | | `description` | `fields.description` | string | Новое описание | | `color` | `fields.color` | string | Новый цвет | | `avatar` | `fields.avatar` | string | Новый URL аватара | ## Примеры ### curl — личный ключ ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456 \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "fields": { "title": "Новое название чата", "description": "Обновлённое описание" } }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "fields": { "title": "Новое название чата", "description": "Обновлённое описание" } }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ fields: { title: 'Новое название чата', description: 'Обновлённое описание', }, }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ fields: { title: 'Новое название чата', description: 'Обновлённое описание', }, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.result` | boolean | `true` при успешном обновлении | ## Пример ответа ```json { "success": true, "data": { "result": true } } ``` ## Пример ответа при ошибке 403 — бот принадлежит другому ключу: ```json { "success": false, "error": { "code": "BOT_ACCESS_DENIED", "message": "This bot belongs to a different API key" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_BOT_ID` | `botId` не является числом | | 404 | `BOT_NOT_FOUND` | Бот с таким ID не найден | | 403 | `BOT_ACCESS_DENIED` | Бот принадлежит другому API-ключу | | 422 | `BITRIX_ERROR` | Ошибка Битрикс24 (текст ошибки в `message`) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить чат](/docs/bots/chats/get) - [Создать чат](/docs/bots/chats/create) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: User Add ## Добавить участников `POST /v1/bots/:botId/chats/:dialogId/users` Добавляет пользователей в чат. После добавления Вайбкод по возможности сверяет состав чата с запрошенным списком и перечисляет недобавленных в поле `warning` успешного ответа. Сверка не гарантирована: когда она не отрабатывает, ответ приходит без `warning`. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `userIds` | number[] | да | Массив ID пользователей для добавления | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/users \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "userIds": [5, 12] }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/users \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "userIds": [5, 12] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/users', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ userIds: [5, 12] }), }) const { success, data, warning } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/users', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ userIds: [5, 12] }), }) const { success, data, warning } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.result` | boolean | Ответ Битрикс24 о приёме запроса. Равен `true` и тогда, когда в чат не попал никто — фактический результат показывает `warning` | | `warning` | object | Приходит, когда сверка отработала и нашла, что в чат не попал хотя бы один из запрошенных — вплоть до того, что не попал никто. Отсутствие поля не доказывает, что добавились все | | `warning.code` | string | Всегда `USERS_NOT_ADDED` | | `warning.message` | string | Пояснение, почему добавление могло не пройти | | `warning.notAdded` | number[] | Идентификаторы из `userIds`, которых нет в составе чата | | `warning.addedAtLeast` | number | Сколько пользователей из запрошенных добавлено | ## Пример ответа ```json { "success": true, "data": { "result": true } } ``` Запрошен неактивный сотрудник `27` — Битрикс24 отчитался об успехе, в чат сотрудник не попал, в ответе появился `warning`: ```json { "success": true, "data": { "result": true }, "warning": { "code": "USERS_NOT_ADDED", "message": "Bitrix24 returned success but 1 of 1 requested user(s) were not added to the chat — likely missing permissions, extranet restriction, or user not on portal.", "notAdded": [27], "addedAtLeast": 0 } } ``` ## Пример ответа при ошибке 403 — бот принадлежит другому ключу: ```json { "success": false, "error": { "code": "BOT_ACCESS_DENIED", "message": "This bot belongs to a different API key" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_BOT_ID` | `botId` не является числом | | 404 | `BOT_NOT_FOUND` | Бот с таким ID не найден | | 403 | `BOT_ACCESS_DENIED` | Бот принадлежит другому API-ключу | | 422 | `BITRIX_ERROR` | Ошибка Битрикс24 (текст ошибки в `message`) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Добавление участников зависит от прав бота в чате.** Бот должен состоять в чате и подходить под его настройку `manageUsersAdd`, которая принимает значения `owner`, `manager` и `member`. Текущее значение приходит в ответе [`GET /v1/chats/:dialogId`](/docs/chats/discovery/get). Бот, создавший чат через [`POST /v1/bots/:botId/chats`](/docs/bots/chats/create) без поля `ownerId`, становится владельцем — этих прав достаточно при любом значении настройки. Расширить свои права в чужом чате бот не может: назначать менеджеров вправе только владелец чата — [Добавить менеджеров](/docs/bots/chats/manager-add). **Ответ остаётся успешным, когда добавлены не все.** В чат не попадают: неактивный сотрудник и несуществующий идентификатор. Причиной бывают также нехватка прав и ограничение экстранета. HTTP-статус в этом случае остаётся успешным, а `data.result` равен `true` — недобавленные перечислены в `warning.notAdded`. Проверяйте наличие `warning` в ответе, а не только `success`. **Признак `active` не предсказывает результат добавления.** Значение `active: true` в [`GET /v1/users`](/docs/entities/users/list) говорит только о том, что сотрудник не деактивирован. Битрикс24 пропускает участника молча и по другим причинам, поэтому фактический результат добавления читают из `warning.notAdded`. Заранее отсеять можно внешних пользователей — у них поле `userType` равно `"extranet"`. **Сверка состава выполняется по возможности.** Список участников запрашивается отдельным вызовом уже после добавления. Когда этот вызов не отрабатывает, ответ приходит обычным успехом без `warning` — то есть отсутствие `warning` не доказывает, что в чат попали все. Когда состав важен, запросите его явно: [Список участников](/docs/bots/chats/user-list). ## Смотрите также - [Удалить участника](/docs/bots/chats/user-delete) - [Список участников](/docs/bots/chats/user-list) - [Добавить менеджеров](/docs/bots/chats/manager-add) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: User Delete ## Удалить участника `DELETE /v1/bots/:botId/chats/:dialogId/users` Удаляет пользователя из чата. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `userId` | number | да | ID пользователя для удаления | ## Примеры ### curl — личный ключ ```bash curl -X DELETE https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/users \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "userId": 12 }' ``` ### curl — OAuth-приложение ```bash curl -X DELETE https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/users \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "userId": 12 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/users', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ userId: 12 }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/users', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ userId: 12 }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.result` | boolean | `true` при успешном удалении | ## Пример ответа ```json { "success": true, "data": { "result": true } } ``` ## Пример ответа при ошибке 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-ключу | | 422 | `BITRIX_ERROR` | Ошибка Битрикс24 (текст ошибки в `message`) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Идемпотентность:** метод возвращает `true` даже если пользователь уже не в чате. **Один пользователь:** эндпоинт принимает `userId` (число), а не массив. Для удаления нескольких участников вызывайте эндпоинт для каждого. ## Смотрите также - [Добавить участников](/docs/bots/chats/user-add) - [Список участников](/docs/bots/chats/user-list) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: User List ## Список участников `GET /v1/bots/:botId/chats/:dialogId/users` Возвращает список участников чата. Бот должен быть участником чата. ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `botId` (path) | number | да | — | ID бота | | `dialogId` (path) | string | да | — | ID диалога (`chatXXX`) | | `limit` (query) | number | нет | `50` | Количество записей (1-200) | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/users?limit=100" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/users?limit=100" \ -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/chats/chat456/users?limit=100', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Участников:', data.length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/users?limit=100', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив участников | | `data[].id` | number | ID пользователя | | `data[].name` | string | Полное имя | | `data[].firstName` | string | Имя | | `data[].lastName` | string | Фамилия | | `data[].workPosition` | string | Должность | | `data[].color` | string | Цвет аватара | | `data[].avatar` | string | URL аватара | | `data[].gender` | string | Пол | | `data[].active` | boolean | Активен ли аккаунт | | `data[].bot` | boolean | Является ли ботом | | `data[].status` | string | Статус пользователя | ## Пример ответа ```json { "success": true, "data": [ { "id": 1, "name": "Иван Петров", "firstName": "Иван", "lastName": "Петров", "workPosition": "Менеджер", "color": "AZURE", "avatar": "", "gender": "M", "active": true, "bot": false, "status": "online" }, { "id": 42, "name": "Техподдержка", "firstName": "Техподдержка", "lastName": "", "workPosition": "Помощник", "color": "AZURE", "avatar": "", "gender": "", "active": true, "bot": true, "status": "online" } ] } ``` ## Пример ответа при ошибке 403 — бот не является участником чата: ```json { "success": false, "error": { "code": "BITRIX_ACCESS_DENIED", "message": "Access denied" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_BOT_ID` | `botId` не является числом | | 404 | `BOT_NOT_FOUND` | Бот с таким ID не найден | | 403 | `BOT_ACCESS_DENIED` | Бот принадлежит другому API-ключу | | 403 | `BITRIX_ACCESS_DENIED` | Бот не является участником чата | | 422 | `BITRIX_ERROR` | Другая ошибка Битрикс24, текст в `message` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Добавить участников](/docs/bots/chats/user-add) - [Удалить участника](/docs/bots/chats/user-delete) - [Добавить менеджеров](/docs/bots/chats/manager-add) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Commands # Команды Регистрируйте slash-команды бота, обновляйте и удаляйте их, отвечайте на вызовы. Пользователи вызывают команды через `/` в чате. Команды также срабатывают через поле `COMMAND` в кнопках [клавиатуры](/docs/bots/messages/keyboard) — оба способа генерируют одно событие `ONIMBOTV2COMMANDADD`. **Скоуп:** `imbot` | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` ## Операции - [Зарегистрировать команду](./commands/register.md) — `POST /v1/bots/:botId/commands` - [Список команд](./commands/list.md) — `GET /v1/bots/:botId/commands` - [Обновить команду](./commands/update.md) — `PATCH /v1/bots/:botId/commands/:commandId` - [Удалить команду](./commands/delete.md) — `DELETE /v1/bots/:botId/commands/:commandId` - [Ответить на команду](./commands/answer.md) — `POST /v1/bots/:botId/commands/:commandId/answer` ## Возможная задержка между записью и чтением Чтение списка команд (`GET /v1/bots/:botId/commands`) не кешируется на стороне платформы Вайбкод. Однако сам Битрикс24 кеширует список: после регистрации, обновления или удаления команды `GET` может несколько секунд (иногда минут) возвращать прежние значения. Подробности — в [Список команд](./commands/list.md). --- # Bot: Answer ## Ответить на команду `POST /v1/bots/:botId/commands/:commandId/answer` Отправляет ответ на вызов slash-команды. Вызывайте из обработчика события `ONIMBOTV2COMMANDADD`. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `messageId` | number | да | ID сообщения с вызовом команды (из события) | | `dialogId` | string | да | ID диалога. Для группового чата — `chat{chatId}`, для личного — `{userId}`. Берите из события `ONIMBOTV2COMMANDADD` (`PARAMS.DIALOG_ID`) | | `fields` | object | нет | Поля ответного сообщения | | `fields.message` | string | нет | Текст ответа. Поддерживает [BB-коды](/docs/bots/messages/formatting) | | `fields.keyboard` | array | нет | Интерактивная [клавиатура](/docs/bots/messages/keyboard) | | `fields.attach` | array/object | нет | [ATTACH-блоки](/docs/bots/messages/attach) | | `fields.system` | boolean | нет | Системное сообщение. По умолчанию `false` | | `fields.urlPreview` | boolean | нет | Показывать превью ссылок. По умолчанию `true` | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/commands/7/answer \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "messageId": 1510, "dialogId": "chat123", "fields": { "message": "[b]Справка по задачам[/b]\n\nДоступные действия:\n[SEND=/status]Проверить статус[/SEND]\n[SEND=/create]Создать задачу[/SEND]" } }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/commands/7/answer \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "messageId": 1510, "dialogId": "chat123", "fields": { "message": "[b]Справка по задачам[/b]\n\nДоступные действия:\n[SEND=/status]Проверить статус[/SEND]\n[SEND=/create]Создать задачу[/SEND]" } }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/commands/7/answer', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ messageId: 1510, dialogId: 'chat123', fields: { message: '[b]Справка по задачам[/b]\n\nДоступные действия:\n[SEND=/status]Проверить статус[/SEND]', }, }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/commands/7/answer', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ messageId: 1510, dialogId: 'chat123', fields: { message: '[b]Справка по задачам[/b]\n\nДоступные действия:\n[SEND=/status]Проверить статус[/SEND]', }, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.result` | boolean | `true` при успешной отправке ответа | ## Пример ответа ```json { "success": true, "data": { "result": true } } ``` ## Пример ответа при ошибке 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-ключу | | 422 | `BITRIX_ERROR` | Ошибка Битрикс24 (текст ошибки в `message`) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Не требует членства в чате:** бот может ответить на команду даже если не является участником чата. Доступ предоставляется временно через связку `messageId` + `commandId`. Если бот не участник — ответ отправляется как системное сообщение с именем бота. ## Смотрите также - [Зарегистрировать команду](/docs/bots/commands/register) - [События](/docs/bots/events) - [Форматирование текста](/docs/bots/messages/formatting) - [Клавиатура](/docs/bots/messages/keyboard) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Delete ## Удалить команду `DELETE /v1/bots/:botId/commands/:commandId` Удаляет зарегистрированную команду бота. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `botId` (path) | number | да | ID бота | | `commandId` (path) | number | да | ID команды | ## Примеры ### curl — личный ключ ```bash curl -X DELETE https://vibecode.bitrix24.tech/v1/bots/42/commands/7 \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE https://vibecode.bitrix24.tech/v1/bots/42/commands/7 \ -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/commands/7', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/commands/7', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.result` | boolean | `true` при успешном удалении | ## Пример ответа ```json { "success": true, "data": { "result": true } } ``` ## Пример ответа при ошибке 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-ключу | | 422 | `BITRIX_ERROR` | Ошибка Битрикс24 (команда не найдена) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Зарегистрировать команду](/docs/bots/commands/register) - [Список команд](/docs/bots/commands/list) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: List ## Список команд `GET /v1/bots/:botId/commands` Возвращает все зарегистрированные команды бота. ## ⚠️ Возможная задержка после мутаций Вайбкод не кеширует этот ответ. Однако сам Битрикс24 **держит свой кеш** списка команд и не всегда обновляет его сразу после регистрации, обновления или удаления команды. В течение нескольких секунд (иногда минут) после успешной мутации `GET` может возвращать: - удалённые команды (их id ещё видны в списке) - старые значения `title` / `params` / `common` / `hidden` для только что обновлённой команды - отсутствие только что зарегистрированной команды. При этом сама команда уже **действует** на стороне Битрикс24 (на неё реагирует событие `ONIMBOTV2COMMANDADD`, бот её обрабатывает) — расхождение видно только в этом `GET`. ### Что делать - **Не использовать `GET /commands` как единственный источник правды сразу после мутации.** Опирайтесь на ответ самой мутации: `POST` возвращает данные с новым id, `PATCH` — обновлённую команду, `DELETE` — признак успеха. - **Если нужна синхронизация со списком** (например для сверки интерфейса с реальным состоянием), запросите `GET` повторно через 10–30 секунд. - **Если расхождение сохраняется дольше минуты**, это уже не штатная задержка. Приложите к обращению в поддержку `botId`, время мутации и то, что именно ожидалось и что получено. Принудительно сбросить этот кеш на стороне Битрикс24 нельзя. Если список не обновился — повторите `GET` через несколько секунд. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `botId` (path) | number | да | ID бота | ## Примеры ### curl — личный ключ ```bash curl https://vibecode.bitrix24.tech/v1/bots/42/commands \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl https://vibecode.bitrix24.tech/v1/bots/42/commands \ -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/commands', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Команды:', data) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/commands', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив команд | | `data[].id` | number | ID команды | | `data[].command` | string | Текст команды | | `data[].title` | string | Заголовок (локализованный) | | `data[].params` | string | Описание параметров (локализованное) | | `data[].common` | boolean | Доступна во всех чатах | | `data[].hidden` | boolean | Скрыта из списка | | `data[].extranetSupport` | boolean | Доступна экстранет-пользователям | ## Пример ответа ```json { "success": true, "data": [ { "id": 7, "command": "help", "title": "Помощь", "params": "тема", "common": true, "hidden": false, "extranetSupport": false }, { "id": 8, "command": "status", "title": "Статус", "params": "", "common": false, "hidden": false, "extranetSupport": false } ] } ``` ## Пример ответа при ошибке 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-ключу | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Зарегистрировать команду](/docs/bots/commands/register) - [Обновить команду](/docs/bots/commands/update) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Register ## Зарегистрировать команду `POST /v1/bots/:botId/commands` Регистрирует новую slash-команду бота. Вайбкод принимает плоский формат и автоматически оборачивает в `fields` для Битрикс24. ## Поля запроса (body) | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `command` | string | да | — | Текст команды без `/` (например, `help`) | | `title` | string/object | нет | — | Заголовок. Строка или мультиязычный объект `{ "ru": "Помощь", "en": "Help" }` | | `params` | string/object | нет | — | Описание параметров. Строка или объект `{ "ru": "тема", "en": "topic" }` | | `common` | string | нет | `"N"` | `"Y"` — доступна во всех чатах, `"N"` — только в личном диалоге с ботом и чатах с ботом | | `hidden` | string | нет | `"N"` | `"Y"` — скрыть из списка команд | | `extranetSupport` | string | нет | `"N"` | `"Y"` — доступна для экстранет-пользователей | Таблица перечисляет все принимаемые поля. Поле с другим именем отбрасывается, запрос при этом завершается успешно: в ответ добавляется объект `warning` с кодом `UNSUPPORTED_FIELDS_DROPPED` и списком отброшенных имён. Описательный текст команды передавайте в `title`, подсказку по аргументам — в `params`. ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/commands \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "command": "help", "title": { "ru": "Помощь", "en": "Help" }, "params": { "ru": "тема", "en": "topic" }, "common": "Y" }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/commands \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "command": "help", "title": { "ru": "Помощь", "en": "Help" }, "params": { "ru": "тема", "en": "topic" }, "common": "Y" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/commands', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ command: 'help', title: { ru: 'Помощь', en: 'Help' }, params: { ru: 'тема', en: 'topic' }, common: 'Y', }), }) const { success, data } = await res.json() console.log('Command ID:', data.command.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/commands', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ command: 'help', title: { ru: 'Помощь', en: 'Help' }, params: { ru: 'тема', en: 'topic' }, common: 'Y', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.command.id` | number | ID зарегистрированной команды | | `data.command.botId` | number | ID бота | | `data.command.command` | string | Текст команды (с `/`) | | `data.command.common` | boolean | Доступна во всех чатах | | `data.command.hidden` | boolean | Скрыта из списка | | `data.command.extranetSupport` | boolean | Доступна экстранет-пользователям | | `warning.code` | string | `UNSUPPORTED_FIELDS_DROPPED`. Приходит, когда в теле запроса было поле вне таблицы «Поля запроса» | | `warning.message` | string | Текст с перечислением отброшенных полей | | `warning.droppedFields` | array | Имена отброшенных полей | ## Пример ответа Тело запроса содержало только принимаемые поля: ```json { "success": true, "data": { "command": { "id": 117, "botId": 1327, "command": "/help", "common": true, "hidden": false, "extranetSupport": false } } } ``` В теле запроса было поле `description` — команда зарегистрирована, поле отброшено: ```json { "success": true, "data": { "command": { "id": 117, "botId": 1327, "command": "/help", "common": true, "hidden": false, "extranetSupport": false } }, "warning": { "code": "UNSUPPORTED_FIELDS_DROPPED", "message": "Bitrix24 imbot.v2.Command.register does not accept these fields; they were dropped: description.", "droppedFields": ["description"] } } ``` ## Пример ответа при ошибке 422 — ошибка Битрикс24: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Command 'help' already registered" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_BOT_ID` | `botId` не является числом | | 404 | `BOT_NOT_FOUND` | Бот с таким ID не найден | | 403 | `BOT_ACCESS_DENIED` | Бот принадлежит другому API-ключу | | 422 | `BITRIX_ERROR` | Ошибка Битрикс24 (текст ошибки в `message`) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Идемпотентность:** повторный вызов с тем же `command` для того же бота возвращает существующую команду без изменений. Для обновления используйте `PATCH`. **Мультиязычность:** `title` и `params` принимают строку или объект с языковыми ключами, например `ru`, `en`, `de`. Строка сохраняется как английский перевод, поэтому русский текст задавайте объектом: `{ "ru": "Помощь", "en": "Help" }`. **Событие:** при вызове команды пользователем срабатывает событие `ONIMBOTV2COMMANDADD`. ## Смотрите также - [Список команд](/docs/bots/commands/list) - [Ответить на команду](/docs/bots/commands/answer) - [События](/docs/bots/events) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Update ## Обновить команду `PATCH /v1/bots/:botId/commands/:commandId` Обновляет параметры существующей команды. Вайбкод принимает плоский формат и автоматически оборачивает в `fields` для Битрикс24. ## Поля запроса (body) | Параметр | Тип | Описание | |----------|-----|---------| | `command` | string | Новый текст команды без `/` | | `title` | string/object | Новый заголовок. Строка сохраняется как английский перевод, русский текст задавайте объектом `{ "ru": "...", "en": "..." }`. Передача `null` для ключа удаляет перевод: `{ "en": null }` | | `params` | string/object | Новое описание параметров. Строка или объект, правила те же, что для `title` | | `common` | string | `"Y"` / `"N"` | | `hidden` | string | `"Y"` / `"N"` | | `extranetSupport` | string | `"Y"` / `"N"` | Таблица перечисляет все принимаемые поля. Поле с другим именем отбрасывается, запрос при этом завершается успешно: в ответ добавляется объект `warning` с кодом `UNSUPPORTED_FIELDS_DROPPED` и списком отброшенных имён. Описательный текст команды передавайте в `title`, подсказку по аргументам — в `params`. ## Примеры ### curl — личный ключ ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/bots/42/commands/7 \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": { "ru": "Обновлённая справка", "en": "Updated help" }, "common": "Y" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/bots/42/commands/7 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": { "ru": "Обновлённая справка", "en": "Updated help" }, "common": "Y" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/commands/7', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: { ru: 'Обновлённая справка', en: 'Updated help' }, common: 'Y', }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/commands/7', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: { ru: 'Обновлённая справка', en: 'Updated help' }, common: 'Y', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.command.id` | number | ID команды | | `data.command.botId` | number | ID бота | | `data.command.command` | string | Имя команды с префиксом `/` | | `data.command.common` | boolean | Доступна во всех чатах, а не только в диалоге с ботом | | `data.command.hidden` | boolean | Скрыта из подсказки автодополнения | | `data.command.extranetSupport` | boolean | Доступна экстранет-пользователям | | `warning.code` | string | `UNSUPPORTED_FIELDS_DROPPED`. Приходит, когда в теле запроса было поле вне таблицы «Поля запроса» | | `warning.message` | string | Текст с перечислением отброшенных полей | | `warning.droppedFields` | array | Имена отброшенных полей | ## Пример ответа Тело запроса содержало только принимаемые поля: ```json { "success": true, "data": { "command": { "id": 189, "botId": 42, "command": "/help", "common": true, "hidden": false, "extranetSupport": false } } } ``` В теле запроса было поле `description` — команда обновлена, поле отброшено: ```json { "success": true, "data": { "command": { "id": 189, "botId": 42, "command": "/help", "common": true, "hidden": false, "extranetSupport": false } }, "warning": { "code": "UNSUPPORTED_FIELDS_DROPPED", "message": "Bitrix24 imbot.v2.Command.update does not accept these fields; they were dropped: description.", "droppedFields": ["description"] } } ``` ## Пример ответа при ошибке 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-ключу | | 422 | `BITRIX_ERROR` | Ошибка Битрикс24 (текст ошибки в `message`) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Удаление перевода:** передайте `null` для языкового ключа: `{ "title": { "en": null } }` — удалит английский перевод, оставив остальные. **Строковые флаги:** `common`, `hidden`, `extranetSupport` принимают строки `"Y"` / `"N"` (не boolean). ## Смотрите также - [Зарегистрировать команду](/docs/bots/commands/register) - [Удалить команду](/docs/bots/commands/delete) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Events # События Получайте входящие события бота методом опроса и обрабатывайте их: новые сообщения, команды, реакции и добавление бота в чат. **Скоуп:** `imbot` | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` ## Операции - [Получить события опросом](./events/polling.md) — `GET /v1/bots/:botId/events` - [Bot-события (ONIMBOTV2*)](./events/bot-events.md) — `GET ONIMBOTV2*` - [User-события (ONIMV2*)](./events/user-events.md) — `GET ONIMV2*` --- # Bot: Bot Events ## Bot-события (ONIMBOTV2*) Приходят автоматически для всех ботов с `eventMode: "fetch"`. Получаются через [polling](/docs/bots/events/polling). Каждое событие имеет структуру: ```json { "eventId": 29, "type": "ONIMBOTV2JOINCHAT", "date": "2026-04-13T17:12:00+03:00", "data": { "dialogId": "chat3553", "bot": { ... }, "chat": { ... }, "user": { ... }, "language": "ru" } } ``` | Поле | Тип | Описание | |------|-----|---------| | `eventId` | number | ID события — передайте как `offset` в следующем запросе polling | | `type` | string | Код типа события | | `date` | string | Дата и время (ISO 8601) | | `data` | object | Данные события (структура зависит от типа) | ## Список событий | Тип | Описание | |-----|---------| | [ONIMBOTV2MESSAGEADD](#onimbotv2messageadd) | Новое сообщение боту | | [ONIMBOTV2MESSAGEUPDATE](#onimbotv2messageupdate) | Сообщение отредактировано | | [ONIMBOTV2MESSAGEDELETE](#onimbotv2messagedelete) | Сообщение удалено | | [ONIMBOTV2JOINCHAT](#onimbotv2joinchat) | Бот добавлен в чат | | [ONIMBOTV2COMMANDADD](#onimbotv2commandadd) | Вызвана slash-команда | | [ONIMBOTV2REACTIONCHANGE](#onimbotv2reactionchange) | Реакция на сообщение бота | | [ONIMBOTV2DELETE](#onimbotv2delete) | Бот удалён с портала | | [ONIMBOTV2CONTEXTGET](#onimbotv2contextget) | Запрошен контекст диалога | --- ## Как обрабатывать события Цикл опроса описан на странице [Получить события](/docs/bots/events/polling). Получив массив `events`, маршрутизируйте каждое событие по полю `type`. Отвечать боту нужно в диалог `event.data.dialogId` (для групп — `chatXXX`, для личных — id пользователя, тот же, что `event.data.chat.dialogId`). **Перед обработкой сообщения отфильтруйте лишнее:** - `message.isSystem === true` — служебное сообщение (вход в чат, смена настроек). Пропускайте. - `message.authorId === event.data.bot.id` — собственное сообщение бота. Боты типа `personal` и `supervisor` получают все сообщения чата, включая свои ответы, — без этой проверки обработчик зациклится. Бот типа `bot` получает только личные сообщения и `@упоминания` и свои сообщения обратно не получает, но проверка не повредит. **Диспетчер событий:** ```javascript async function handleEvent(event) { const { type, data } = event const dialogId = data.dialogId switch (type) { case 'ONIMBOTV2MESSAGEADD': { const m = data.message if (m.isSystem || m.authorId === data.bot.id) return // пропустить служебные и свои // Ответить: POST /v1/bots/:botId/messages с { dialogId, fields: { message } } break } case 'ONIMBOTV2COMMANDADD': // Ответить на команду: POST /v1/bots/:botId/commands/:commandId/answer // commandId = data.command.id, messageId = data.message.id break case 'ONIMBOTV2JOINCHAT': // Бот добавлен в чат — можно отправить приветствие в dialogId break case 'ONIMBOTV2REACTIONCHANGE': // data.reaction (код реакции) + data.action ('add' | 'delete') break case 'ONIMBOTV2CONTEXTGET': // Диалог открыт по ссылке с контекстом — данные в data.context break case 'ONIMBOTV2MESSAGEUPDATE': // Сообщение отредактировано — data.message с новым текстом break case 'ONIMBOTV2MESSAGEDELETE': // Сообщение удалено — data.messageId (число) break case 'ONIMBOTV2DELETE': // Бот удалён с портала — освободите ресурсы, прекратите опрос break } } ``` Ответ в диалог — всегда [`POST /v1/bots/:botId/messages`](/docs/bots/messages/send) с `dialogId = event.data.dialogId`. --- ## ONIMBOTV2MESSAGEADD Новое сообщение боту (личное или @упоминание в групповом чате). ```json { "eventId": 35, "type": "ONIMBOTV2MESSAGEADD", "date": "2026-04-13T17:15:00+03:00", "data": { "dialogId": "chat123", "bot": { "id": 42, "code": "support_bot", "type": "bot", "isHidden": false, "isReactionsEnabled": true, "eventMode": "fetch" }, "message": { "id": 1501, "chatId": 123, "authorId": 1, "date": "2026-04-13T17:15:00+03:00", "text": "Привет, бот! Подскажи по задаче #42", "isSystem": false, "uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "forward": null, "params": { "FILE_ID": ["15423"], "REPLY_ID": "1498" }, "viewedByOthers": false }, "chat": { "id": 123, "dialogId": "chat123", "type": "chat", "name": "Рабочий чат", "owner": 1, "color": "#64a513", "entityType": "", "entityId": "", "permissions": { "manageUsersAdd": "member", "manageUsersDelete": "manager", "manageSettings": "owner", "manageMessages": "member", "canPost": "member" } }, "user": { "id": 1, "active": true, "name": "Иван Петров", "firstName": "Иван", "lastName": "Петров", "workPosition": "Менеджер", "color": "#1eb4aa", "gender": "M", "extranet": false, "bot": false, "status": "online", "departments": [1, 5], "type": "employee" }, "language": "ru" } } ``` **Поля data:** | Поле | Тип | Описание | |------|-----|---------| | `dialogId` | string | ID диалога для ответа (`chatXXX` или id пользователя) | | `message.id` | number | ID сообщения — для цитирования через [replyId](/docs/bots/messages/send) | | `message.text` | string | Текст сообщения | | `message.authorId` | number | ID автора. Сравните с `bot.id`, чтобы пропустить собственные сообщения | | `message.isSystem` | boolean | `true` для служебных сообщений — пропускайте их | | `message.params.FILE_ID` | string[] | ID прикреплённых файлов. Скачать: [GET /files/:fileId](/docs/bots/files/download) | | `message.params.REPLY_ID` | string | Ответ на сообщение: ID процитированного сообщения. Прочитать исходное: [GET /messages/:messageId](/docs/bots/messages/get) для ботов `personal`/`supervisor`, иначе — [GET /chats/:dialogId/messages](/docs/chats/messages/list) | | `message.forward` | object \| null | Объект пересланного сообщения или `null` | | `bot` | object | Объект бота (`id`, `code`, `type`, `eventMode`) | | `chat.entityType` | string | Тип привязки: `LINES` (открытая линия), `CRM`, пустая строка (обычный чат) | | `chat.permissions` | object | Права в чате (`manageUsersAdd`, `manageSettings` и др.) | | `user` | object | Автор сообщения (`id`, `name`, `departments`, `status` и др.) | | `language` | string | Язык интерфейса пользователя | ### Обработка голосовых и файловых сообщений Голосовые сообщения и файлы-вложения попадают в `ONIMBOTV2MESSAGEADD` со следующими особенностями: - У голосового сообщения `message.text` пуст или содержит только пояснение (`"Голосовое сообщение"`). - Массив `message.params.FILE_ID` — **авторитативный источник** информации о вложениях, появляется сразу в теле события. - `GET /v1/chats/:dialogId/messages` **не гарантирует**, что то же сообщение вернётся сразу — disk-индекс Битрикс24 иногда догоняет событие с задержкой в 1–2 секунды. Не ждите его через polling. **Корректный паттерн:** ```javascript const FILE_FETCH_TIMEOUT_MS = 10_000 async function handleMessageAdd(event) { const { message } = event.data const fileIds = message.params?.FILE_ID ?? [] // Обычное текстовое сообщение if (fileIds.length === 0) { return handleText(message) } // Есть вложение — читаем метаданные через disk API for (const fileId of fileIds) { let meta = null for (let attempt = 0; attempt < 2; attempt++) { // encodeURIComponent защищает от future-regressions если fileId когда-то // окажется не чисто-числовым (например, B24 поменяет формат ID или // этот паттерн расширят на user-provided ID из другого источника). const url = `https://vibecode.bitrix24.tech/v1/files/${encodeURIComponent(fileId)}` // AbortController защищает handler от зависания, если B24 или наш proxy // отвечают медленно. Без timeout одно «залипшее» событие может заблокировать poll-loop. const controller = new AbortController() const timer = setTimeout(() => controller.abort(), FILE_FETCH_TIMEOUT_MS) let res try { res = await fetch(url, { headers: { 'X-Api-Key': process.env.VIBE_KEY }, signal: controller.signal, }) } catch (err) { clearTimeout(timer) if (err.name === 'AbortError') { console.warn(`File ${fileId} fetch timed out after ${FILE_FETCH_TIMEOUT_MS}ms, retrying`) continue } throw err } clearTimeout(timer) if (res.ok) { meta = await res.json() break } // 403 BITRIX_ACCESS_DENIED или 404 сразу после события — типично: // disk ещё не проиндексировал файл. Ждём 1.5 секунды и ретраим. if (res.status === 403 || res.status === 404) { await sleep(1500) continue } throw new Error(`Failed to read file ${fileId}: HTTP ${res.status}`) } if (!meta) { // Файл всё ещё недоступен — логируем и продолжаем без attachment console.warn(`File ${fileId} not available after retry, skipping`) continue } await processAttachment(meta.data) } } const sleep = (ms) => new Promise((r) => setTimeout(r, ms)) ``` **Требуемые скоупы у API-ключа:** `imbot` (получение событий) + **`disk`** (вызов `/v1/files/:id`). Без скоупа `disk` запрос `GET /v1/files/:id` возвращает `SCOPE_DENIED` 403. Скоуп `im` нужен дополнительно, если вы вызываете методы `im.*` напрямую (для этого паттерна не требуется). **Модель прав в Битрикс24:** - Бот-пользователь (от чьего имени работает API-ключ) должен быть **участником чата**, в котором пришло сообщение. Для групповых ботов участие добавляется автоматически при установке. Для ботов типа `personal` и `supervisor` требуется настройка в интерфейсе портала (см. [Зарегистрировать бота](/docs/bots/management/create)). - Файл-вложение доступно только в пределах срока хранения файлов в Битрикс24, который зависит от тарифа портала. После удаления файла запрос возвращает `BITRIX_ACCESS_DENIED` даже с корректным скоупом. - Скоуп `disk` у ключа **необходим, но недостаточен** — он открывает эндпоинт `/v1/files/:id`, но права на конкретный файл Битрикс24 проверяет отдельно по участию бота в чате. **Расшифровка голосового сообщения.** Получив `fileId` из `message.params.FILE_ID`, скачайте байты файла и отправьте их на распознавание. Полная цепочка: событие → `fileId` → скачать содержимое → расшифровать. ```javascript async function transcribeVoice(fileId) { // 1. Скачать байты файла (бинарный ответ) const fileRes = await fetch( `https://vibecode.bitrix24.tech/v1/files/${encodeURIComponent(fileId)}/download`, { headers: { 'X-Api-Key': process.env.VIBE_KEY } }, ) const audio = await fileRes.blob() // 2. Отправить аудио на расшифровку (Whisper, тарифицируется по длительности в AI-квоте портала; скоуп `vibe:ai`) const form = new FormData() form.append('file', audio, 'voice.ogg') const trRes = await fetch('https://vibecode.bitrix24.tech/v1/audio/transcriptions', { method: 'POST', headers: { 'X-Api-Key': process.env.VIBE_KEY }, body: form, }) const { text } = await trRes.json() return text } ``` Контракт распознавания (форматы, лимиты, коды ошибок `empty_file` / `AI_PROVIDER_TIMEOUT`) — [Расшифровка аудио](/docs/ai/audio). Скоуп `vibe:ai` добавляется к ключу автоматически. --- ## ONIMBOTV2MESSAGEUPDATE Сообщение отредактировано. Структура `data` совпадает с `ONIMBOTV2MESSAGEADD`: объект `message` содержит обновлённый `text` и те же поля `id`, `authorId`, `params.FILE_ID`, `params.REPLY_ID`. Находите исходное сообщение по `message.id`. --- ## ONIMBOTV2MESSAGEDELETE Сообщение удалено. Вместо объекта `message` содержит `messageId` (число). ```json { "eventId": 37, "type": "ONIMBOTV2MESSAGEDELETE", "date": "2026-04-13T17:16:00+03:00", "data": { "dialogId": "chat123", "bot": { "id": 42, "code": "support_bot", "type": "bot" }, "messageId": 1501, "chat": { "id": 123, "dialogId": "chat123", "type": "chat", "name": "Рабочий чат" }, "user": { "id": 1, "name": "Иван Петров" } } } ``` --- ## ONIMBOTV2JOINCHAT Бот добавлен в чат. `user` — кто добавил бота. ```json { "eventId": 29, "type": "ONIMBOTV2JOINCHAT", "date": "2026-04-13T17:12:00+03:00", "data": { "dialogId": "chat3553", "bot": { "id": 42, "code": "support_bot", "type": "bot", "eventMode": "fetch" }, "chat": { "id": 3553, "dialogId": "chat3553", "type": "chat", "name": "Отдел продаж", "owner": 42, "color": "#64a513", "permissions": { "manageUsersAdd": "member", "manageSettings": "owner" } }, "user": { "id": 3, "name": "Мария Сидорова", "workPosition": "Руководитель" }, "language": "ru" } } ``` --- ## ONIMBOTV2COMMANDADD Вызвана slash-команда бота. Содержит дополнительный объект `command`. ```json { "eventId": 40, "type": "ONIMBOTV2COMMANDADD", "date": "2026-04-13T17:18:00+03:00", "data": { "dialogId": "chat123", "bot": { "id": 42, "code": "support_bot", "type": "bot" }, "message": { "id": 1510, "text": "/help задачи" }, "chat": { "id": 123, "dialogId": "chat123" }, "user": { "id": 1, "name": "Иван Петров" }, "command": { "id": 7, "command": "help", "params": "задачи", "context": "textarea" } } } ``` **Поля command:** | Поле | Описание | |------|---------| | `id` | ID команды | | `command` | Текст команды без `/` | | `params` | Параметры, введённые после команды | | `context` | Откуда вызвана: `textarea` (поле ввода), `keyboard` (кнопка), `menu` (контекстное меню) | Для ответа используйте [POST /commands/:commandId/answer](/docs/bots/commands/answer) с `messageId` из `message.id`. --- ## ONIMBOTV2REACTIONCHANGE Реакция добавлена или удалена на сообщение бота. ```json { "eventId": 42, "type": "ONIMBOTV2REACTIONCHANGE", "date": "2026-04-13T17:19:00+03:00", "data": { "dialogId": "chat123", "bot": { "id": 42, "code": "support_bot", "type": "bot" }, "reaction": "like", "action": "add", "message": { "id": 1502, "text": "Привет! Чем могу помочь?" }, "chat": { "id": 123, "dialogId": "chat123" }, "user": { "id": 1, "name": "Иван Петров" } } } ``` | Поле | Описание | |------|---------| | `reaction` | Код реакции (см. [коды реакций](/docs/bots/ui/reactions)) | | `action` | `"add"` — добавлена, `"delete"` — удалена | --- ## ONIMBOTV2DELETE Бот удалён с портала. Содержит только объект `bot` — без `chat` и `user`. ```json { "eventId": 50, "type": "ONIMBOTV2DELETE", "date": "2026-04-13T17:25:00+03:00", "data": { "bot": { "id": 42, "code": "support_bot", "type": "bot" } } } ``` --- ## ONIMBOTV2CONTEXTGET Пользователь открыл диалог с ботом по ссылке, в которую вложен контекст. В поле `context` приходят произвольные данные из этой ссылки — бот может сразу ответить с их учётом. ```json { "eventId": 45, "type": "ONIMBOTV2CONTEXTGET", "date": "2026-04-13T17:20:00+03:00", "data": { "dialogId": "5", "bot": { "id": 42, "code": "support_bot", "type": "bot" }, "context": { "action": "openTask", "taskId": "456" }, "chat": { "id": 789, "dialogId": "5", "type": "private" }, "user": { "id": 5, "name": "Алексей Козлов" } } } ``` | Поле | Описание | |------|---------| | `context` | Произвольные данные из ссылки, по которой открыли диалог. Приходит строкой или объектом. Битрикс24 передаёт значения строками — число `456` придёт как `"456"` | Событие приходит для личного диалога с ботом, поэтому `dialogId` — это id пользователя, открывшего ссылку. **Как боту передают контекст.** Диалог с ботом открывают по ссылке с параметром `BOT_CONTEXT` — в него кладут произвольный JSON в URL-кодировке: ``` https:///online/?IM_DIALOG=&BOT_CONTEXT= ``` `` — домен портала, `` — идентификатор диалога с ботом. Значение `BOT_CONTEXT` приходит боту в поле `context` этого события без изменений. --- ## Общие объекты в событиях Все события (кроме `ONIMBOTV2DELETE`) содержат объекты `bot`, `chat`, `user` с одинаковой структурой. Полные объекты показаны в примере `ONIMBOTV2MESSAGEADD` выше. В сокращённых примерах показаны только ключевые поля. ## Смотрите также - [Получить события](/docs/bots/events/polling) - [User-события](/docs/bots/events/user-events) - [Отправить сообщение](/docs/bots/messages/send) - [Ответить на команду](/docs/bots/commands/answer) - [Коды реакций](/docs/bots/ui/reactions) - [Бот-платформа](/docs/bots) --- # Bot: Polling ## Получить события (polling) `GET /v1/bots/:botId/events` Основной механизм получения входящих сообщений и команд. Бот периодически запрашивает новые события. Вайбкод хранит `lastOffset` в базе данных — при первом запросе без `offset` используется сохранённое значение. Это позволяет боту продолжить с места остановки после перезапуска. ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `botId` (path) | number | да | — | ID бота | | `offset` (query) | number | нет | из БД | Начальная позиция. Без параметра — сохранённое в БД значение. `offset=0` — начать с начала | | `limit` (query) | number | нет | `100` | Максимальное количество событий (1-1000) | | `withUserEvents` (query) | boolean | нет | `false` | Включить [user-события](/docs/bots/events/user-events) (ONIMV2*). Требует предварительной подписки — порядок настройки описан на странице User-события. Без подписки запрос вернёт `422 BITRIX_ERROR: User is not subscribed` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/bots/42/events?limit=50" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash 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 | Массив событий (см. [типы событий](/docs/bots/events/bot-events)) | | `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 | Текущее сохранённое смещение в БД | | `persisted` | boolean | `true` если `lastOffset` в БД продвинулся (доставлено хотя бы одно событие). `false` — ответ пустой, курсор не изменился | | `nextPollAfterMs` | number | Сколько миллисекунд подождать перед следующим запросом. Приходит только боту, которому события доставляются вебхуком (`eventMode` равен `webhook`) — очередь `Event.get` у такого бота пуста по устройству Битрикс24. Боту в режиме `fetch` поле не приходит: отсутствие означает «опрашивайте с прежней частотой», поэтому пустым или нулевым оно не бывает. Если `hasMore` равен `true`, дочитайте очередь не дожидаясь паузы — она относится к следующему пустому опросу | | `hint` | string | Диагностическое сообщение при устойчиво пустой очереди — указывает на состояние установки на стороне Битрикс24. Счётчик пустых ответов обновляется периодически, а не на каждый запрос, поэтому подсказка появляется после нескольких периодов пустоты, а не строго на пятом запросе (при рекомендованном интервале опроса 2–5 секунд — спустя примерно пару минут непрерывно пустого опроса). Число N в тексте — количество зафиксированных периодов пустоты, а не точное число сделанных запросов. Для ветвления в коде опирайтесь на `persisted` и наличие событий, а `hint` трактуйте как подсказку | ## Пример ответа Есть новые события (`persisted: true`): ```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": 35, "persisted": true } } ``` Устойчиво пустая очередь событий (появляется поле `hint`, число в тексте — количество зафиксированных периодов пустоты, а не сделанных запросов): ```json { "success": true, "data": { "events": [], "nextOffset": 36, "hasMore": false, "storedOffset": 36, "persisted": false, "hint": "Events queue has stayed empty across 7 consecutive checks (the empty-poll counter is sampled periodically, not once per request, so this reflects sustained emptiness rather than the exact number of polls). Bot config: eventMode='fetch', code='support_bot'. If the bot is alive on B24 (chats receive messages, im.bot.list lists it) the most common cause is B24-side event-subscription decay — run POST /v1/bots/42/resubscribe first (lightweight, preserves openline / WELCOME_BOT bindings). If that does not help, verify: (1) eventMode is 'fetch' (current: 'fetch'); (2) your OAuth app's INSTALL event handler responded 200 to Bitrix24; (3) the bot was added to a chat where messages are being sent (it must be a participant for chat-message events); (4) only if all of the above are confirmed — try POST /v1/bots to re-register (destroys openline bindings; last resort)." } } ``` ## Пример ответа при ошибке 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-ключу | | 422 | `BITRIX_ERROR` | Ошибка Битрикс24 (текст ошибки в `message`) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Какой токен использовать.** Для личного ключа `vibe_api_…` достаточно заголовка `X-Api-Key`. Для ключа авторизации `vibe_app_…` обязательно добавлять `Authorization: Bearer ` — без Bearer запрос вернёт `401 TOKEN_MISSING`. Получение `session_token` для OAuth-приложения — см. [Ключи и авторизация](/docs/keys-auth). **Серверное хранение offset:** Вайбкод хранит `lastOffset` в базе. При первом запросе без `offset` — используется сохранённое значение. После получения событий `lastOffset` обновляется автоматически, не дожидаясь результата записи. **offset=0:** явная передача `offset=0` начинает с начала истории — для отладки или первичной загрузки. **offset=N (конкретное значение):** само событие с указанным ID попадает в ответ. Чтобы не получить дубли, всегда передавайте `nextOffset` из предыдущего ответа, а не `eventId` последнего обработанного события. **Цепочка запросов:** ``` GET /events → { nextOffset: 42, hasMore: true } GET /events?offset=42 → { nextOffset: 55, hasMore: false } GET /events?offset=55 → { events: [], hasMore: false } ``` **Рекомендуемый интервал polling:** 2-5 секунд между запросами — если платформа не прислала `nextPollAfterMs`. Прислала — ждите столько, сколько там указано: значение может меняться между релизами платформы, поэтому зажимайте его своими границами, а не полагайтесь на конкретное число. **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) } // Платформа может попросить опрашивать реже (`nextPollAfterMs`); поля нет — свой интервал. await new Promise(r => setTimeout(r, Math.min(data?.nextPollAfterMs ?? 3000, 3600000))) } } 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.chat.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({ dialogId: data.chat.dialogId, messageId: data.message.id, fields: { message: `Команда /${data.command.command}: ${data.command.params}` }, }), }) break } } pollEvents() ``` ## Смотрите также - [Диагностика проблем](/docs/bots/troubleshooting) - [Bot-события](/docs/bots/events/bot-events) - [User-события](/docs/bots/events/user-events) - [Отправить сообщение](/docs/bots/messages/send) - [Ответить на команду](/docs/bots/commands/answer) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: User Events ## User-события (ONIMV2*) Общий первый шаг — подписка: [`POST /v1/chats/events/subscribe`](/docs/chats/events/subscribe) (скоуп `im`, не `imbot`). Без активной подписки Битрикс24 не регистрирует пользовательские события. Дальше события забирают одним из двух способов: 1. **Вместе с bot-событиями** — передать `withUserEvents=true` в [polling бота](/docs/bots/events/polling). Bot-события (`ONIMBOTV2*`) и user-события (`ONIMV2*`) приходят в одном массиве `events`. 2. **Отдельным опросом от имени пользователя** — [`GET /v1/chats/events`](/docs/chats/events/poll). Не требует зарегистрированного бота, подходит для агентов, работающих от имени пользователя. ## Список событий | Событие | Описание | |---------|---------| | [ONIMV2MESSAGEADD](#onimv2messageadd) | Новое сообщение в подписанном чате | | `ONIMV2MESSAGEUPDATE` | Сообщение отредактировано | | `ONIMV2MESSAGEDELETE` | Сообщение удалено | | `ONIMV2JOINCHAT` | Участник зашёл в чат | | `ONIMV2REACTIONCHANGE` | Реакция изменена | ## ONIMV2MESSAGEADD Новое сообщение в подписанном чате. Объект `message` совпадает по составу с событиями ботов, но ключи внутри `params` — в camelCase. ```json { "eventId": 46, "type": "ONIMV2MESSAGEADD", "date": "2026-04-13T17:15:14+03:00", "data": { "message": { "id": 1520, "chatId": 123, "authorId": 17, "text": "Да, согласен", "isSystem": false, "forward": null, "params": { "replyId": "1518" } }, "chat": { "id": 123, "dialogId": "chat123", "type": "chat", "name": "Рабочий чат" }, "user": { "id": 17, "name": "Иван Петров", "type": "user" }, "language": "ru" } } ``` **Поля data:** | Поле | Тип | Описание | |------|-----|---------| | `message.id` | number | ID сообщения | | `message.text` | string | Текст сообщения | | `message.authorId` | number | ID автора | | `message.params.replyId` | string | Ответ на сообщение: ID процитированного сообщения | | `chat.dialogId` | string | ID диалога | | `user` | object | Автор сообщения (`id`, `name` и др.) | | `language` | string | Язык интерфейса пользователя | ## Известные особенности **Отдельный скоуп:** [подписка](/docs/chats/events/subscribe) и [отписка](/docs/chats/events/unsubscribe) требуют скоуп `im`, а не `imbot`. ## Смотрите также - [Получить события](/docs/bots/events/polling) - [Получить пользовательские события](/docs/chats/events/poll) - [Bot-события](/docs/bots/events/bot-events) - [Бот-платформа](/docs/bots) --- # Bot: Files # Файлы Загружайте файлы в чат от имени бота и скачивайте файлы, которые присылают пользователи. **Скоуп:** `imbot` | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` ## Операции - [Загрузить файл](./files/upload.md) — `POST /v1/bots/:botId/files` - [Скачать файл](./files/download.md) — `GET /v1/bots/:botId/files/:fileId` --- # Bot: Download ## Скачать файл `GET /v1/bots/:botId/files/:fileId` Возвращает информацию о файле и одноразовую ссылку для скачивания. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `botId` (path) | number | да | ID бота | | `fileId` (path) | number | да | ID файла | ## Примеры ### curl — личный ключ ```bash curl https://vibecode.bitrix24.tech/v1/bots/42/files/789 \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl https://vibecode.bitrix24.tech/v1/bots/42/files/789 \ -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/files/789', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Download URL:', data.downloadUrl) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/files/789', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID файла | | `name` | string | Имя файла | | `size` | number | Размер в байтах | | `downloadUrl` | string | Одноразовая ссылка для скачивания | ## Пример ответа ```json { "success": true, "data": { "id": 789, "name": "report.pdf", "size": 2048576, "downloadUrl": "https://portal.bitrix24.ru/rest/download.json?token=abc123..." } } ``` ## Пример ответа при ошибке 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-ключу | | 422 | `BITRIX_ERROR` | Ошибка Битрикс24 (текст ошибки в `message`) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Одноразовая ссылка:** `downloadUrl` — временная ссылка. Для повторного скачивания нужен новый вызов метода. ## Смотрите также - [Загрузить файл](/docs/bots/files/upload) - [Отправить сообщение](/docs/bots/messages/send) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Upload ## Загрузить файл `POST /v1/bots/:botId/files` Загружает файл в чат от имени бота. Содержимое передаётся в base64 внутри тела запроса, поэтому размер ограничивает тело: 40 МиБ, то есть чуть меньше 30 МиБ исходного файла. Тело сверх лимита отклоняется с кодом `PAYLOAD_TOO_LARGE`. Битрикс24 на своей стороне может принимать больше — этот потолок наш. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `dialogId` | string | да | ID диалога: числовой ID пользователя для личных, `chatXXX` для групповых | | `file.name` | string | да | Имя файла с расширением | | `file.content` | string | да | Содержимое файла в base64 | | `message` | string | нет | Текст сообщения, прикреплённый к файлу | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/files \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "dialogId": "chat123", "file": { "name": "report.pdf", "content": "JVBERi0xLjQKJcOkw7zDtsOfCjEgMCBv..." }, "message": "Вот запрошенный отчёт" }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/files \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "dialogId": "chat123", "file": { "name": "report.pdf", "content": "JVBERi0xLjQKJcOkw7zDtsOfCjEgMCBv..." }, "message": "Вот запрошенный отчёт" }' ``` ### JavaScript — личный ключ ```javascript import { readFileSync } from 'fs' const base64 = readFileSync('./report.pdf').toString('base64') const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/files', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ dialogId: 'chat123', file: { name: 'report.pdf', content: base64 }, message: 'Вот запрошенный отчёт', }), }) const { success, data } = await res.json() console.log('File ID:', data.file.id) ``` ### JavaScript — OAuth-приложение ```javascript import { readFileSync } from 'fs' const base64 = readFileSync('./report.pdf').toString('base64') const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/files', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ dialogId: 'chat123', file: { name: 'report.pdf', content: base64 }, message: 'Вот запрошенный отчёт', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `file` | object | Данные загруженного файла | | `file.id` | number | ID загруженного файла (используйте его для `GET /v1/bots/:botId/files/:fileId`) | | `file.chatId` | number | Числовой ID чата | | `file.name` | string | Имя файла | | `file.extension` | string | Расширение файла | | `file.size` | number | Размер файла в байтах | | `messageId` | number | ID созданного сообщения с файлом | | `chatId` | number | Числовой ID чата | | `dialogId` | string | ID диалога | ## Пример ответа ```json { "success": true, "data": { "file": { "id": 789, "chatId": 5, "name": "report.pdf", "extension": "pdf", "size": 35341 }, "messageId": 1520, "chatId": 5, "dialogId": "chat123" } } ``` ## Пример ответа при ошибке 422 — ошибка Битрикс24: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "File size exceeds limit" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_BOT_ID` | `botId` не является числом | | 404 | `BOT_NOT_FOUND` | Бот с таким ID не найден | | 403 | `BOT_ACCESS_DENIED` | Бот принадлежит другому API-ключу | | 422 | `BITRIX_ERROR` | Ошибка Битрикс24 при загрузке | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Base64:** содержимое файла передаётся целиком в base64. Для больших файлов это увеличивает размер body на ~33%. **Сообщение с файлом:** параметр `message` прикрепляет текст к тому же сообщению, что и файл — отдельного вызова для отправки текста не нужно. ## Смотрите также - [Скачать файл](/docs/bots/files/download) - [Отправить сообщение](/docs/bots/messages/send) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Management # Управление ботами Зарегистрируйте бота на портале Битрикс24, получайте и обновляйте его данные, восстанавливайте доступ при сбоях авторизации и удаляйте бота, когда он больше не нужен. **Скоуп:** `imbot` | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` ## Операции - [Зарегистрировать бота](./management/create.md) — `POST /v1/bots` - [Список ботов](./management/list.md) — `GET /v1/bots` - [Получить бота](./management/get.md) — `GET /v1/bots/:botId` - [Обновить бота](./management/update.md) — `PATCH /v1/bots/:botId` - [Удалить бота](./management/delete.md) — `DELETE /v1/bots/:botId` - [Повторная авторизация](./management/reauth.md) — `POST /v1/bots/:botId/reauth` - [Перепривязка подписки на события](./management/resubscribe.md) — `POST /v1/bots/:botId/resubscribe` - [Перенос владения ботом](./management/transfer.md) — `POST /v1/bots/:botId/transfer` - [Ревизия бот-платформы](./management/revision.md) — `GET /v1/bots/revision` ## Смотрите также - [Восстановление доступа к боту](/docs/bots/ownership-recovery) - [Диагностика проблем](/docs/bots/troubleshooting) - [Бот-платформа](/docs/bots) --- # Bot: Create ## Зарегистрировать бота `POST /v1/bots` Регистрирует нового бота на портале Битрикс24. Операция идемпотентна по `code` — повторный вызов с тем же кодом вернёт `409 BOT_ALREADY_EXISTS` с данными существующего бота. ## Поля запроса (body) | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `code` | string | да | — | Уникальный код бота (латиница, цифры, подчёркивание) | | `name` | string | да | — | Отображаемое имя бота | | `type` | string | нет | `bot` | [Тип бота](#типы-ботов): `bot`, `personal`, `supervisor`, `openline`. Нельзя изменить после регистрации. От типа зависит доступ к [чтению сообщений](/docs/bots/messages) | | `eventMode` | string | нет | `fetch` | Режим событий: `fetch` (опрос) или `webhook` (доставка на ваш адрес) | | `webhookUrl` | string | нет | — | URL для доставки событий (только при `eventMode: "webhook"`) | | `lastName` | string | нет | — | Фамилия бота | | `workPosition` | string | нет | — | Должность бота (отображается под именем) | | `color` | string | нет | — | Цвет аватара: `RED`, `GREEN`, `MINT`, `LIGHT_BLUE`, `DARK_BLUE`, `PURPLE`, `AQUA`, `PINK`, `LIME`, `BROWN`, `AZURE`, `KHAKI`, `SAND`, `MARENGO`, `GRAY`, `GRAPHITE` | | `gender` | string | нет | — | Пол: `M` или `F` | | `avatar` | string | нет | — | Аватар бота: PNG или JPEG как base64-строка без префикса `data:image/...;base64,`, до ~50 КБ. См. «Формат аватара» в «Известных особенностях» | | `isHidden` | boolean | нет | `false` | Скрыть бота из списка контактов | | `isReactionsEnabled` | boolean | нет | `true` | Разрешить реакции на сообщения бота | | `backgroundId` | string | нет | — | Фон чата: `azure`, `mint`, `steel`, `slate`, `teal`, `cornflower`, `sky`, `peach`, `frost` | | `isSupportOpenline` | boolean | нет | `false` | Поддержка открытых линий (только для `type: "openline"`) | ## Типы ботов | Тип | Описание | |-----|---------| | `bot` | Стандартный бот — реагирует на @упоминание и личные сообщения | | `personal` | AI-ассистент — получает все сообщения без @упоминания. Доступны [`GET /v1/bots/:botId/messages/:messageId`](/docs/bots/messages/get) и [`GET /v1/bots/:botId/messages/:messageId/context`](/docs/bots/messages/context) | | `supervisor` | Системный наблюдатель — получает все сообщения в чатах, где состоит | | `openline` | Бот для открытых линий. Требует `isSupportOpenline: true` | > ⚠ **`personal` и `supervisor` — привилегированные типы:** они получают все сообщения в чатах, где состоят, даже без @упоминания бота. Используйте их осознанно. Регистрация бота выполняется от лица администратора портала Битрикс24 — независимо от типа. Владельцу ключа без этой роли Битрикс24 отвечает отказом в доступе, даже когда скоуп `imbot` у ключа есть. ## Доступные цвета Используются в параметре `color` при создании и обновлении бота: ``` RED, GREEN, MINT, LIGHT_BLUE, DARK_BLUE, PURPLE, AQUA, PINK, LIME, BROWN, AZURE, KHAKI, SAND, MARENGO, GRAY, GRAPHITE ``` ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "code": "support_bot", "name": "Техподдержка", "type": "bot", "eventMode": "fetch", "color": "AZURE", "workPosition": "Помощник по техническим вопросам" }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "code": "support_bot", "name": "Техподдержка", "type": "bot", "eventMode": "fetch", "color": "AZURE", "workPosition": "Помощник по техническим вопросам" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ code: 'support_bot', name: 'Техподдержка', type: 'bot', eventMode: 'fetch', color: 'AZURE', workPosition: 'Помощник по техническим вопросам', }), }) const { success, data } = await res.json() // `data.botId` зеркалит ответ 409 BOT_ALREADY_EXISTS — один и тот же путь для // success и conflict. `data.bot.id` оставлен для обратной совместимости. console.log('Bot ID:', data.botId) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ code: 'support_bot', name: 'Техподдержка', type: 'bot', eventMode: 'fetch', color: 'AZURE', workPosition: 'Помощник по техническим вопросам', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `botId` | number | ID бота на портале Битрикс24. Зеркалит `data.botId` из 409-ответа — один и тот же путь при успехе и при конфликте | | `bot.id` | number | Дубликат `botId` для обратной совместимости. ID бота на портале Битрикс24 | | `bot.code` | string | Уникальный код бота | | `bot.type` | string | Тип бота | | `bot.eventMode` | string | Режим событий: `fetch` или `webhook` | | `bot.isHidden` | boolean | Скрыт из списка контактов | | `bot.isReactionsEnabled` | boolean | Разрешены реакции | | `users` | array | Массив пользователей Битрикс24, созданных для бота | | `users[].id` | number | Идентификатор пользователя-бота на портале. Совпадает с `botId` | | `users[].name` | string | Отображаемое имя бота — то, что видят участники чата | | `users[].workPosition` | string | Должность под именем бота | | `users[].active` | boolean | Активен ли пользователь-бот | | `users[].bot` | boolean | Признак бота, всегда `true` | ## Пример ответа ```json { "success": true, "data": { "botId": 42, "bot": { "id": 42, "code": "support_bot", "type": "bot", "eventMode": "fetch", "isHidden": false, "isReactionsEnabled": true }, "users": [ { "id": 42, "name": "Техподдержка", "active": true, "bot": true } ] } } ``` ## Пример ответа при ошибке 409 — бот с таким кодом уже существует: ```json { "success": false, "error": { "code": "BOT_ALREADY_EXISTS", "message": "Bot with this code already exists" }, "data": { "botId": 42, "code": "support_bot", "name": "Техподдержка" } } ``` В поле `data` возвращаются `botId`, `code` и `name` уже зарегистрированного бота — это идемпотентный путь восстановления записи в базе Вайбкод после рассинхронизации. Если бота с этим `botId` нет в `GET /v1/bots` вашим ключом, он зарегистрирован другим ключом портала: порядок возврата управления — [Восстановление доступа к боту](/docs/bots/ownership-recovery). ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `CODE_REQUIRED` | Не передан параметр `code` | | 400 | `NAME_REQUIRED` | Не передан параметр `name` | | 409 | `BOT_ALREADY_EXISTS` | Бот с таким `code` уже зарегистрирован. Ответ содержит `data` с `botId` | | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку при регистрации (текст ошибки в `message`) | | 502 | `REGISTRATION_FAILED` | Битрикс24 не вернул ID бота | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ в режиме «только чтение» | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Восстановление при рассинхронизации:** если бот существует на портале Битрикс24, но отсутствует в базе Вайбкод (после сбоя), повторный `POST` с тем же `code` восстановит запись в базе. **Формат тела запроса отличается от PATCH:** при создании поля передаются плоско (`code`, `name`, `color`). При обновлении — вложенная структура `{ fields: { properties: { name, color } } }`. **Формат аватара.** Поле `avatar` принимает изображение PNG или JPEG в виде base64-строки **без** префикса `data:image/...;base64,` — передавайте только сами base64-данные. URL изображения или строка с префиксом `data:` приводят к ответу `422 BITRIX_ERROR`. Размер — до ~50 КБ: при превышении запрос завершается успешно, но аватар не сохраняется и остаётся пустым. **Идемпотентность по `code`:** повторный запрос безопасен, когда бот с таким кодом уже есть и в базе Вайбкод, и на портале Битрикс24. Подходит для перезапуска скриптов и проверки факта регистрации без раздельной обработки успеха и конфликта. **Жизненный цикл бота.** Бот существует ровно столько, сколько существует локальное приложение, через которое он зарегистрирован. Удаление приложения с портала удаляет и бота. **Операции с ботом — тем же ключом.** Бот привязан к API-ключу, которым зарегистрирован. Получение событий, отправка сообщений и обновление выполняются тем же ключом — запрос с другого ключа вернёт `403 BOT_ACCESS_DENIED`. Если рабочим остался другой ключ — [Восстановление доступа к боту](/docs/bots/ownership-recovery). **Режим `webhook` требует публичного `webhookUrl`.** При `eventMode: "webhook"` Битрикс24 отправляет события напрямую на `webhookUrl`, поэтому адрес должен быть публично достижим. Если `webhookUrl` ведёт на сервер Black Hole с личным ключом `vibe_api_…`, событие принимает только политика доступа `PUBLIC` — при `OWNER_ONLY` (по умолчанию), `NAMED_USERS`, `DEPARTMENT`, `PORTAL` и `AUTHENTICATED` оно до приложения не доходит, и такому серверу подойдёт `eventMode: "fetch"`. Сервер, ключ которого привязан к OAuth-приложению, принимает события при любой политике. Подробности и решения — в разделе [Диагностика проблем](/docs/bots/troubleshooting). ## Смотрите также - [Диагностика проблем](/docs/bots/troubleshooting) - [События](/docs/bots/events) - [Сообщения](/docs/bots/messages) - [Обновить бота](/docs/bots/management/update) - [Перенос владения ботом](/docs/bots/management/transfer) - [Восстановление доступа к боту](/docs/bots/ownership-recovery) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Delete ## Удалить бота `DELETE /v1/bots/:botId` Удаляет бота из Битрикс24 и из базы Вайбкод. Действие необратимо. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `botId` | number | да | ID бота (path-параметр) | | `force` (query) | boolean | нет | `true` — удалить запись из базы Вайбкод, даже если Битрикс24 отклонил отмену регистрации. По умолчанию при ошибке Битрикс24 запись сохраняется и возвращается `502 BOT_DELETE_PARTIAL` | ## Примеры ### curl — личный ключ ```bash curl -X DELETE https://vibecode.bitrix24.tech/v1/bots/42 \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE https://vibecode.bitrix24.tech/v1/bots/42 \ -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', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() console.log(data) // { deleted: true } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.deleted` | boolean | `true` при успешном удалении | | `data.alreadyAbsentOnB24` | boolean | Присутствует, когда Битрикс24 уже не знал этого бота: запись удалена из базы Вайбкод, на стороне Битрикс24 чисто | | `data.forced` | boolean | Присутствует при `?force=true`, когда Битрикс24 отклонил отмену регистрации: запись удалена из базы Вайбкод, бот остался на стороне Битрикс24 | | `data.b24UnregisterError` | string | Присутствует вместе с `forced`. Текст ошибки Битрикс24, из-за которой отмена регистрации не удалась | ## Пример ответа ```json { "success": true, "data": { "deleted": true } } ``` ## Пример ответа при ошибке 404 — бот не найден: ```json { "success": false, "error": { "code": "BOT_NOT_FOUND", "message": "Bot 42 not found. Register it first via POST /v1/bots." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_BOT_ID` | `botId` не является числом | | 404 | `BOT_NOT_FOUND` | Бот не найден | | 403 | `BOT_ACCESS_DENIED` | Бот принадлежит другому API-ключу | | 502 | `BOT_DELETE_PARTIAL` | Битрикс24 отклонил отмену регистрации, и снятие бота подтвердить не удалось — запись в базе Вайбкод сохранена. Текст ответа отдельно сообщает, бот точно на месте или проверить не получилось. Текст ошибки — в `error.b24UnregisterError`, шестизначный код обращения в поддержку — в `error.incidentCode`. Повторите после `POST /v1/bots/:botId/reauth` или удалите принудительно через `?force=true` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Каскадное удаление:** при удалении бота также удаляются связанные записи AI-агента или управляемого бота, если они были привязаны к этому боту. **Необратимость:** бот удаляется и из Битрикс24, и из базы Вайбкод. Для повторного использования нужна новая регистрация через `POST /v1/bots`. **Повторный вызов безопасен:** если Битрикс24 отвечает, что такого бота у него нет, удаление считается успешным — запись в базе Вайбкод удаляется, ответ `200` содержит `alreadyAbsentOnB24: true`. `?force=true` для этого не нужен. Так же обрабатывается случай, когда Битрикс24 отклонил отмену регистрации, но бота у себя всё-таки снял: Вайбкод дополнительно проверяет, есть ли бот на портале, и при его отсутствии тоже отвечает успехом. Если сама проверка не прошла (например, истёк токен), это не считается подтверждением — возвращается `502`. **Частичное удаление и `?force=true`:** если Битрикс24 отклонил отмену регистрации и снятие бота подтвердить не удалось, возвращается `502 BOT_DELETE_PARTIAL`, запись в базе Вайбкод сохраняется — повторите после `POST /v1/bots/:botId/reauth` или удалите принудительно через `?force=true`. С `?force=true` запись удаляется из базы Вайбкод даже при ошибке Битрикс24, бот остаётся на стороне Битрикс24 до ручной очистки, а ответ содержит `forced: true` и `b24UnregisterError`. Исключение — если Битрикс24 ответил, что бота у него нет: тогда сироты не возникает, и ответ содержит `alreadyAbsentOnB24: true` вместо `forced`. ## Смотрите также - [События](/docs/bots/events) - [Сообщения](/docs/bots/messages) - [Бот-платформа](/docs/bots) --- # Bot: Get ## Получить бота `GET /v1/bots/:botId` Получает актуальные данные о боте из Битрикс24 (живой запрос, не из кэша). ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `botId` | number | да | ID бота (path-параметр) | ## Примеры ### curl — личный ключ ```bash curl https://vibecode.bitrix24.tech/v1/bots/42 \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl https://vibecode.bitrix24.tech/v1/bots/42 \ -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', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() console.log('Бот:', data) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() ``` ## Поля ответа Ответ содержит два объекта: `data.bot` — параметры бота, `data.users` — массив пользователей Битрикс24, представляющих бота. В массиве один элемент — учётная запись бота-пользователя. | Поле | Тип | Описание | |------|-----|---------| | `data.bot.id` | number | ID бота на портале Битрикс24 | | `data.bot.code` | string | Уникальный код бота | | `data.bot.type` | string | Тип бота: `bot`, `personal`, `supervisor`, `openline` | | `data.bot.isHidden` | boolean | Скрыт из списка контактов | | `data.bot.isSupportOpenline` | boolean | Поддержка открытых линий | | `data.bot.isReactionsEnabled` | boolean | Разрешены реакции на сообщения | | `data.bot.backgroundId` | string | Фон чата. Приходит `null`, когда не задан | | `data.bot.language` | string | Язык бота, например `ru` | | `data.bot.moduleId` | string | Модуль, зарегистрировавший бота, например `rest` | | `data.bot.eventMode` | string | Режим событий: `fetch` или `webhook` | | `data.bot.countMessage` | number | Счётчик сообщений | | `data.bot.countCommand` | number | Счётчик команд | | `data.bot.countChat` | number | Счётчик чатов | | `data.bot.countUser` | number | Счётчик пользователей | | `data.users[].id` | number | ID пользователя-бота. Совпадает с `data.bot.id` | | `data.users[].name` | string | Полное имя | | `data.users[].firstName` | string | Имя | | `data.users[].lastName` | string | Фамилия. Пустая строка, если не задана | | `data.users[].workPosition` | string | Должность | | `data.users[].color` | string | Цвет аватара в формате HEX, например `#29619b` | | `data.users[].avatar` | string | URL аватара. Пустая строка, если не задан | | `data.users[].gender` | string | Пол: `M` или `F` | | `data.users[].active` | boolean | Активен ли пользователь | | `data.users[].bot` | boolean | Признак бота | | `data.users[].departments` | array | Подразделения. Пустой массив, если их нет | | `data.users[].lastActivityDate` | string \| null | Время последней активности. `null`, если активности не было | Массив `data.users` несёт и другие стандартные поля пользователя Битрикс24 — `birthday`, `phones`, `website`, `email`, `status`, `mobileLastDate`, `desktopLastDate`. О том, как кодируются незаполненные значения, — в разделе «Известные особенности». ## Пример ответа ```json { "success": true, "data": { "bot": { "id": 42, "code": "support_bot", "type": "bot", "isHidden": false, "isSupportOpenline": false, "isReactionsEnabled": true, "backgroundId": null, "language": "ru", "moduleId": "rest", "eventMode": "fetch", "countMessage": 0, "countCommand": 0, "countChat": 0, "countUser": 0 }, "users": [ { "id": 42, "active": true, "name": "Техподдержка", "firstName": "Техподдержка", "lastName": "", "workPosition": "Помощник по техническим вопросам", "color": "#29619b", "avatar": "", "gender": "M", "bot": true, "departments": [], "lastActivityDate": null, "phones": [] } ] } } ``` ## Пример ответа при ошибке 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` | Бот не найден — зарегистрируйте через `POST /v1/bots` | | 403 | `BOT_ACCESS_DENIED` | Бот принадлежит другому API-ключу. Вернуть управление — [Восстановление доступа к боту](/docs/bots/ownership-recovery) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Незаполненные значения приходят в предсказуемой форме.** Пустые даты `lastActivityDate`, `mobileLastDate` и `desktopLastDate` платформа приводит к `null`, а незаполненный список `phones` — к пустому массиву, поэтому `phones.map(...)` работает без предварительной проверки. Пустые строковые поля `lastName`, `avatar`, `birthday`, `website`, `email` приходят пустой строкой, `departments` — пустым массивом, а незаданный `backgroundId` в `data.bot` — `null`. **Цвет аватара возвращается в HEX.** При записи `color` принимает имя из палитры (`AZURE`, `MINT`, …), но в ответе `data.users[].color` приходит уже как HEX-строка, например `#29619b`. Прочитать обратно записанное имя из палитры нельзя. ## Смотрите также - [Список ботов](/docs/bots/management/list) - [Обновить бота](/docs/bots/management/update) - [Восстановление доступа к боту](/docs/bots/ownership-recovery) - [События](/docs/bots/events) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: List ## Список ботов `GET /v1/bots` Возвращает список ботов, зарегистрированных текущим API-ключом на портале. Запрос **не идёт** в Битрикс24 — возвращаются записи из базы Вайбкод, отфильтрованные по вашему API-ключу. Автоматически отключённые боты (`PORTAL_DELETED` / `AUTH_FAILURES`) в список не попадают — чтобы увидеть их, переключите статус вручную через `PATCH /v1/bots/:botId { disabled: false }`. Из-за фильтрации по ключу бот, зарегистрированный другим ключом того же портала, в списке не появится, хотя его `code` остаётся занятым и повторная регистрация вернёт `409 BOT_ALREADY_EXISTS`. Как вернуть управление таким ботом — [Восстановление доступа к боту](/docs/bots/ownership-recovery). ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `limit` | number | нет | Максимальное количество ботов в ответе. По умолчанию 50, максимум 200 | | `offset` | number | нет | Смещение для пагинации. По умолчанию 0 | | `type` | string | нет | Фильтр по типу бота: `bot`, `personal`, `supervisor`, `openline` | ## Примеры ### curl — личный ключ ```bash curl https://vibecode.bitrix24.tech/v1/bots \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl https://vibecode.bitrix24.tech/v1/bots \ -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', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() console.log('Мои боты:', data.bots) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `bots` | array | Массив объектов ботов | | `bots[].id` | number | ID бота на Битрикс24-портале | | `bots[].code` | string | Уникальный код бота | | `bots[].name` | string | Отображаемое имя бота в чате | | `bots[].type` | string | Тип: `bot`, `personal`, `supervisor`, `openline` | | `bots[].eventMode` | string | Режим событий: `fetch` или `webhook` | | `users` | array | Всегда пустой массив. Сохранён для обратной совместимости — чтобы получить пользователей Битрикс24, используйте `GET /v1/users` | | `hasNextPage` | boolean | `true`, если ещё есть записи за пределами текущей страницы — увеличьте `offset` | ## Пример ответа ```json { "success": true, "data": { "bots": [ { "id": 42, "code": "support_bot", "name": "Техподдержка", "type": "bot", "eventMode": "fetch" }, { "id": 58, "code": "analytics_bot", "name": "Аналитик", "type": "openline", "eventMode": "webhook" } ], "users": [], "hasNextPage": false } } ``` ## Пример ответа при ошибке 403 — нет скоупа `imbot`: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'imbot' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить бота](/docs/bots/management/get) - [Зарегистрировать бота](/docs/bots/management/create) - [Восстановление доступа к боту](/docs/bots/ownership-recovery) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Reauth ## Повторная авторизация бота `POST /v1/bots/:botId/reauth` Проверяет учётные данные бота и при необходимости обновляет токен доступа. Снимает автоматическое отключение, если доступ снова действителен. Тело запроса не требуется. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `botId` | number | да | ID бота (path-параметр) | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/reauth \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/reauth \ -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/reauth', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() console.log(data) // { validated: true, refreshed: false } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/reauth', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.validated` | boolean | `true`, если учётные данные бота действительны | | `data.refreshed` | boolean | `true`, если токен доступа был обновлён в ходе проверки | ## Пример ответа ```json { "success": true, "data": { "validated": true, "refreshed": false } } ``` ## Пример ответа при ошибке 410 — учётные данные недействительны и не восстанавливаются автоматически: ```json { "success": false, "error": { "code": "REAUTH_REQUIRED", "message": "Bot credentials are invalid. This key authorizes through a Bitrix24 inbound webhook, so there is no OAuth flow to re-run — the webhook itself is dead, most often deleted on the Bitrix24 side. Repair it from the VibeCode cabinet: an ordinary personal key is re-minted on the Keys page (the key id and string are preserved, so linked bots keep working), and an agent-owned key is repaired from the agent card, which the platform routes to POST /api/agents/:id/recover-key. This API key cannot perform either action itself — both are session-authenticated cabinet routes.", "details": { "statusCode": 401, "bitrixErrorCode": "INVALID_CREDENTIALS", "credentialKind": "webhook" } } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_BOT_ID` | `botId` не является числом | | 404 | `BOT_NOT_FOUND` | Бот не найден | | 403 | `BOT_ACCESS_DENIED` | Бот принадлежит другому API-ключу. Вернуть управление — [Восстановление доступа к боту](/docs/bots/ownership-recovery) | | 410 | `REAUTH_REQUIRED` | Доступ недействителен и не восстанавливается автоматически. Что делать — зависит от `error.details.credentialKind` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ в режиме «только чтение» | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Когда применять.** Бот отключён со статусом `BOT_DISABLED` по причине `AUTH_FAILURES`. Проверка подтверждает доступ и снимает отключение — после успешного ответа бот снова принимает события и отправляет сообщения. **Поле `refreshed`.** Принимает `true` только для ключа авторизации с истёкшим токеном доступа: проверка попутно обновляет токен. Для личного ключа `refreshed` всегда `false`. **Ответ `410` и поле `credentialKind`.** Автоматическое восстановление невозможно, но лекарство зависит от того, чем ключ авторизуется в Битрикс24. Класс приходит в `error.details.credentialKind`: | `credentialKind` | Что это значит | Что делать | |------------------|----------------|-----------| | `webhook` | Ключ ходит через входящий вебхук Битрикс24. Никакого потока авторизации и токена обновления у него нет — мёртв сам вебхук, чаще всего он удалён на стороне Битрикс24 | Перевыпустить вебхук в кабинете Вайбкода. У обычного личного ключа это делается на странице ключей: идентификатор и строка ключа сохраняются, поэтому привязанные боты продолжают работать. Ключ агента чинится с карточки агента | | `oauth` | У ключа есть поток авторизации, но токен обновления тоже недействителен | Авторизовать ключ заново через `POST /v1/oauth/authorize` либо пересоздать личный ключ | Оба действия выполняются в кабинете и требуют сессии — самим API-ключом их вызвать нельзя. ## Смотрите также - [Диагностика проблем](/docs/bots/troubleshooting) - [Восстановление доступа к боту](/docs/bots/ownership-recovery) - [Перепривязка подписки на события](/docs/bots/management/resubscribe) - [Бот-платформа](/docs/bots) --- # Bot: Resubscribe ## Перепривязка подписки на события `POST /v1/bots/:botId/resubscribe` Восстанавливает подписку бота на события Битрикс24. Применяется, когда бот активен, но `GET /v1/bots/:botId/events` перестал возвращать события. Тело запроса не требуется. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `botId` | number | да | ID бота (path-параметр) | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/resubscribe \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/resubscribe \ -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/resubscribe', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() console.log(data) // { resubscribed: true, eventMode: 'fetch' } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/resubscribe', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.resubscribed` | boolean | `true` при успешной перепривязке | | `data.eventMode` | string | Режим доставки событий бота: `fetch` или `webhook` | ## Пример ответа ```json { "success": true, "data": { "resubscribed": true, "eventMode": "fetch" } } ``` ## Пример ответа при ошибке 404 — бот не найден: ```json { "success": false, "error": { "code": "BOT_NOT_FOUND", "message": "Bot 42 not found. Register it first via POST /v1/bots." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_BOT_ID` | `botId` не является числом | | 404 | `BOT_NOT_FOUND` | Бот не найден | | 403 | `BOT_ACCESS_DENIED` | Бот принадлежит другому API-ключу | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Когда применять.** Бот зарегистрирован и активен — в чаты приходят сообщения, бот есть в списке `GET /v1/bots` — но очередь событий пуста несколько опросов подряд, и в ответе `GET /v1/bots/:botId/events` появилось поле `hint`. Перепривязка восстанавливает доставку и сохраняет привязки открытых линий и приветственного бота, в отличие от повторной регистрации через `POST /v1/bots`. **Повторный вызов безопасен.** Каждый запрос заново отправляет режим доставки бота в Битрикс24, поэтому перепривязку можно вызывать несколько раз подряд. **Режим `webhook`.** Для бота с `eventMode: "webhook"` перепривязка также повторно отправляет сохранённый адрес вебхука. ## Смотрите также - [События](/docs/bots/events) - [Диагностика проблем](/docs/bots/troubleshooting) - [Повторная авторизация бота](/docs/bots/management/reauth) --- # Bot: Revision ## Ревизия бот-платформы `GET /v1/bots/revision` Возвращает номера ревизий бот-платформы Битрикс24 по типам клиентов. Не требует ID бота. Тело запроса не требуется. ## Примеры ### curl — личный ключ ```bash curl https://vibecode.bitrix24.tech/v1/bots/revision \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl https://vibecode.bitrix24.tech/v1/bots/revision \ -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/revision', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() console.log(data) // { rest: 35, web: 130, mobile: 25, desktop: 6 } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/revision', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.rest` | number | Ревизия REST-возможностей бот-платформы | | `data.web` | number | Ревизия веб-клиента | | `data.mobile` | number | Ревизия мобильного клиента | | `data.desktop` | number | Ревизия десктоп-клиента | ## Пример ответа ```json { "success": true, "data": { "rest": 35, "web": 130, "mobile": 25, "desktop": 6 } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'imbot' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Назначение поля `rest`.** Значение растёт, когда Битрикс24 выпускает новые возможности REST бот-платформы. Сравнение сохранённого значения с текущим показывает, что на портале появились новые методы и события бот-платформы. ## Смотрите также - [Управление ботами](/docs/bots/management) - [Бот-платформа](/docs/bots) --- # Bot: Transfer ## Перенос владения ботом `POST /v1/bots/:botId/transfer` Переносит владение ботом на другой API-ключ того же портала Битрикс24 и того же пользователя, либо перенос выполняет администратор портала. Решает ситуацию, когда ключ-владелец отозван и бот перестал работать. Перенос меняет только привязку ключа — `botId`, история чатов и подписки сохраняются. Обращения к Битрикс24 при переносе не происходит, поэтому доступ нового ключа проверяется отдельным вызовом [`POST /v1/bots/:botId/reauth`](/docs/bots/management/reauth). ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `botId` (path) | number | да | ID бота. Список: [`GET /v1/bots`](/docs/bots/management/list). Если бота там нет, его ID приходит в поле `data.botId` ответа `409 BOT_ALREADY_EXISTS` — см. [Восстановление доступа к боту](/docs/bots/ownership-recovery) | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `targetApiKeyId` | string | да | Идентификатор записи целевого ключа, поле `id` в ответе [`GET /v1/keys`](/docs/management-keys). Не строка ключа | Целевой ключ должен быть активным ключом общего назначения того же портала, со скоупом `imbot` и незакончившимся сроком действия, и принадлежать тому же пользователю Вайбкод, который выполняет перенос. Администратор портала переносит бота на ключ любого пользователя того же портала. Ключ, не прошедший проверку, отклоняется с `400 TARGET_KEY_INVALID`, конкретная причина приходит в поле `reason` — расшифровка причин в таблице [Ошибки](#ошибки). ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/transfer \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "targetApiKeyId": "3f9a1c20-5e6b-4d18-9a77-0c2b8e4f1d33" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/transfer', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ targetApiKeyId: '3f9a1c20-5e6b-4d18-9a77-0c2b8e4f1d33' }), }) const { data } = await res.json() console.log(data) // { transferred: true, botId: 42, fromApiKeyId: '...', toApiKeyId: '...' } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.transferred` | boolean | `true`, если привязка изменилась. `false` — если ключ уже был владельцем и повторный вызов ничего не изменил | | `data.botId` | number | ID бота | | `data.fromApiKeyId` | string | ID прежнего ключа-владельца. При `transferred: false` равен `toApiKeyId` | | `data.toApiKeyId` | string | ID нового ключа-владельца | ## Пример ответа ```json { "success": true, "data": { "transferred": true, "botId": 42, "fromApiKeyId": "8c41d5e7-2b90-4a63-b1f5-6d7e9a0c4b12", "toApiKeyId": "3f9a1c20-5e6b-4d18-9a77-0c2b8e4f1d33" } } ``` ## Пример ответа при ошибке 400 — целевой ключ не подходит (с уточнением в поле `reason`): ```json { "success": false, "error": { "code": "TARGET_KEY_INVALID", "message": "Target API key is not eligible to own this bot.", "reason": "wrong_user" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_BOT_ID` | `botId` не является числом | | 400 | `INVALID_PARAMS` | `targetApiKeyId` не передан, не строка или пустая строка | | 400 | `TARGET_KEY_INVALID` | Целевой ключ не подходит. `reason`: `not_active` · `wrong_portal` · `wrong_user` · `missing_scope` · `expired` · `system_key` (служебный платформенный ключ) | | 403 | `NOT_BOT_OWNER` | Вызывающий не владеет ботом (нужен тот же пользователь, что у ключа-владельца, или администратор портала) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ в режиме «только чтение» | | 404 | `BOT_NOT_FOUND` | Бот не найден на портале | | 404 | `TARGET_KEY_NOT_FOUND` | Целевой ключ не найден | | 409 | `BOT_TRANSFER_NOT_ALLOWED` | Бот управляется агентом или управляемым ботом — переносите через соответствующий ресурс, а не напрямую | | 409 | `BOT_TRANSFER_CONFLICT` | Владение изменилось параллельным запросом — перечитайте текущего владельца и повторите при необходимости | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Работа бота не зависит от приложения-регистратора.** Перенос на активный личный ключ `vibe_api_*` того же портала восстанавливает работу бота независимо от того, каким приложением он был зарегистрирован. Полный порядок с поиском `botId` и идентификатора целевого ключа — [Восстановление доступа к боту](/docs/bots/ownership-recovery). **Авторизация по пользователю, а не по ключу.** Перенос разрешён владельцу бота, то есть пользователю Вайбкод, которому принадлежит текущий ключ-владелец, даже если этот ключ уже отозван. Выполнить перенос может и администратор портала. Держать ключ-владелец не требуется, именно поэтому перенос работает после отзыва исходного ключа. **Идемпотентность.** Перенос на текущий ключ-владелец, в том числе отозванный, безопасен: привязка не меняется, запись в журнал не создаётся. ## Смотрите также - [Восстановление доступа к боту](/docs/bots/ownership-recovery) - [Повторная авторизация бота](/docs/bots/management/reauth) - [Диагностика проблем](/docs/bots/troubleshooting) - [Бот-платформа](/docs/bots) --- # Bot: Update ## Обновить бота `PATCH /v1/bots/:botId` Обновляет свойства бота. Передавайте только те поля, которые хотите изменить. > **Две формы тела запроса — обе корректны.** Платформа принимает как **плоскую** запись (та же, что у `POST /v1/bots`), так и формат Битрикс24 с обёрткой `fields`. Если в теле есть `fields`, запрос передаётся в Битрикс24 без изменений. Иначе известные поля верхнего уровня автоматически разворачиваются в `fields.properties.*` / `fields.*`. Поведение обеих форм идентично. ## Поля запроса (body) | Параметр (плоский) | Параметр (формат Битрикс24) | Тип | Описание | |---|---|-----|---------| | `name` | `fields.properties.name` | string | Новое имя бота | | `lastName` | `fields.properties.lastName` | string | Новая фамилия | | `workPosition` | `fields.properties.workPosition` | string | Новая должность | | `color` | `fields.properties.color` | string | Новый цвет аватара | | `gender` | `fields.properties.gender` | string | Пол: `M` или `F` | | `avatar` | `fields.properties.avatar` | string | Аватар бота: PNG или JPEG как base64-строка без префикса `data:image/...;base64,`, до ~50 КБ. См. «Известные особенности» | | `eventMode` | `fields.eventMode` | string | Режим событий: `fetch` или `webhook` | | `webhookUrl` | `fields.webhookUrl` | string | URL для push-уведомлений | | `isHidden` | `fields.isHidden` | boolean | Скрыть из списка контактов | | `isReactionsEnabled` | `fields.isReactionsEnabled` | boolean | Разрешить реакции | | `backgroundId` | `fields.backgroundId` | string | Фон чата: `azure`, `mint`, `steel`, `slate`, `teal`, `cornflower`, `sky`, `peach`, `frost` | | `isSupportOpenline` | `fields.isSupportOpenline` | boolean | Поддержка открытых линий (только для `type: "openline"`) | ## Примеры ### curl — личный ключ ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/bots/42 \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "fields": { "properties": { "name": "Новое имя", "color": "MINT" }, "eventMode": "fetch" } }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/bots/42 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "fields": { "properties": { "name": "Новое имя", "color": "MINT" }, "eventMode": "fetch" } }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ fields: { properties: { name: 'Новое имя', color: 'MINT' }, eventMode: 'fetch', }, }), }) const { data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ fields: { properties: { name: 'Новое имя', color: 'MINT' }, eventMode: 'fetch', }, }), }) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.bot` | object | Обновлённый бот. Набор полей совпадает с ответом [регистрации](/docs/bots/management/create) | | `data.bot.id` | number | ID бота на портале Битрикс24 | | `data.bot.code` | string | Системный код бота | | `data.bot.type` | string | Тип бота: `bot`, `personal` или `supervisor` | | `data.bot.eventMode` | string | Режим доставки событий: `fetch` или `webhook` | | `data.users` | array | Карточка бота как пользователя портала | ## Пример ответа Показаны основные поля. Полный набор полей бота — в ответе [регистрации](/docs/bots/management/create). ```json { "success": true, "data": { "bot": { "id": 42, "code": "my_helper_bot", "type": "bot", "eventMode": "fetch", "isHidden": false, "isReactionsEnabled": true, "language": "ru" }, "users": [] } } ``` ## Пример ответа при ошибке 403 — бот принадлежит другому ключу: ```json { "success": false, "error": { "code": "BOT_ACCESS_DENIED", "message": "This bot belongs to a different API key" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_BOT_ID` | `botId` не является числом | | 404 | `BOT_NOT_FOUND` | Бот не найден | | 403 | `BOT_ACCESS_DENIED` | Бот принадлежит другому API-ключу | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Симметрия с регистрацией.** PATCH принимает как плоское тело (`{ name, eventMode, ... }`), так и формат Битрикс24 с обёрткой `fields` — так же, как `POST /v1/bots`. Если в теле есть ключ `fields`, платформа передаёт его в Битрикс24 без изменений. Иначе нормализует плоские поля сама. **`type` нельзя изменить:** поле `type` не принимается при обновлении. **Формат аватара.** Поле `avatar` принимает изображение PNG или JPEG в виде base64-строки **без** префикса `data:image/...;base64,` — передавайте только сами base64-данные. Строка с префиксом `data:` приводит к ответу 422. Размер — до ~50 КБ: при превышении запрос завершается успешно (`success: true`), но аватар не сохраняется и в боте остаётся пустым. Эндпоинт принимает только JSON — загрузка файла через `multipart/form-data` не поддерживается (ответ 415). Передавайте значение как `avatar` (плоская форма) либо как `fields.properties.avatar` (форма с `fields`) — результат одинаковый. ## Смотрите также - [Получить бота](/docs/bots/management) - [Зарегистрировать бота](/docs/bots/management) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Messages # Сообщения Отправляйте сообщения от имени бота, редактируйте и удаляйте их, читайте отдельные сообщения и отмечайте переписку прочитанной. **Скоуп:** `imbot` | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` ## Операции - [Отправить сообщение](./messages/send.md) — `POST /v1/bots/:botId/messages` - [Обновить сообщение](./messages/update.md) — `PATCH /v1/bots/:botId/messages/:messageId` - [Удалить сообщение](./messages/delete.md) — `DELETE /v1/bots/:botId/messages/:messageId` - [Прочитать сообщения](./messages/read.md) — `POST /v1/bots/:botId/chats/:dialogId/read` - [Получить сообщение](./messages/get.md) — `GET /v1/bots/:botId/messages/:messageId` - [Контекст сообщения](./messages/context.md) — `GET /v1/bots/:botId/messages/:messageId/context` ## Ограничение по типу бота Получить сообщение (`GET /v1/bots/:botId/messages/:messageId`) и его контекст (`GET /v1/bots/:botId/messages/:messageId/context`) доступны только ботам с `type` ∈ {`personal`, `supervisor`}. Для остальных типов — `bot` и `openline` — ответ 422 с кодом `BITRIX_ERROR`, в поле `error.b24Code` приходит `BOT_TYPE_NOT_ALLOWED`. Тип задаётся при регистрации через [POST /v1/bots](/docs/bots/management/create) и не меняется без перерегистрации. --- # Bot: Attach ## ATTACH-блоки Расширенное форматирование сообщений через поле `fields.attach`. Максимальный размер — 60 000 символов после сериализации. ## Два формата передачи **Полный формат** (с метаданными): ```json { "fields": { "attach": { "ID": 1, "COLOR_TOKEN": "primary", "COLOR": "#29619b", "BLOCKS": [ { "MESSAGE": [{ "MESSAGE": "Текст блока", "STYLE": "bold" }] }, { "DELIMITER": [{ "SIZE": 200, "COLOR": "#c6c6c6" }] } ] } } } ``` **Сокращённый формат** (массив блоков): ```json { "fields": { "attach": [ { "MESSAGE": [{ "MESSAGE": "Текст блока", "STYLE": "bold" }] }, { "DELIMITER": [{}] }, { "GRID": [{ "NAME": "Поле", "VALUE": "Значение" }] } ] } } ``` Если в `attach` нет ключа `BLOCKS`, сервер считает, что передан сокращённый формат. ## Типы блоков ### MESSAGE — стилизованный текст | Поле | Тип | Описание | |------|-----|---------| | `MESSAGE` | string | Текст сообщения | | `STYLE` | string | Стиль: `bold`, `italic`, `base` | ```json { "MESSAGE": [{ "MESSAGE": "Статус обновлён", "STYLE": "bold" }] } ``` ### USER — карточка пользователя | Поле | Тип | Описание | |------|-----|---------| | `NAME` | string | Имя пользователя | | `AVATAR` | string | URL аватара | | `LINK` | string | URL профиля | ```json { "USER": [{ "NAME": "Иван Петров", "AVATAR": "https://example.com/avatar.jpg", "LINK": "https://portal.bitrix24.ru/company/personal/user/1/" }] } ``` ### LINK — превью ссылки | Поле | Тип | Описание | |------|-----|---------| | `NAME` | string | Заголовок ссылки | | `LINK` | string | URL | | `DESC` | string | Описание | | `PREVIEW` | string | URL изображения-превью | ```json { "LINK": [{ "NAME": "Документация API", "LINK": "https://vibecode.bitrix24.tech/docs", "DESC": "Полная документация API Вайбкод" }] } ``` ### DELIMITER — линия-разделитель | Поле | Тип | Описание | |------|-----|---------| | `SIZE` | integer | Ширина в пикселях | | `COLOR` | string | Цвет в формате HEX | ```json { "DELIMITER": [{ "SIZE": 200, "COLOR": "#c6c6c6" }] } ``` ### GRID — таблица / сетка | Поле | Тип | Описание | |------|-----|---------| | `NAME` | string | Название поля | | `VALUE` | string | Значение поля | | `DISPLAY` | string | Отображение: `LINE` (в строку), `BLOCK` (блок), `ROW` (строка) | | `WIDTH` | integer | Ширина столбца в пикселях | ```json { "GRID": [ { "NAME": "Задача", "VALUE": "Подготовить отчёт", "DISPLAY": "LINE" }, { "NAME": "Статус", "VALUE": "Выполнено", "DISPLAY": "LINE" } ] } ``` ### IMAGE — изображение | Поле | Тип | Описание | |------|-----|---------| | `LINK` | string | URL полного изображения | | `NAME` | string | Подпись | | `PREVIEW` | string | URL превью | | `WIDTH` | integer | Ширина в пикселях | | `HEIGHT` | integer | Высота в пикселях | ```json { "IMAGE": [{ "LINK": "https://example.com/chart.png", "NAME": "График продаж", "WIDTH": 600, "HEIGHT": 400 }] } ``` ### FILE — прикреплённый файл | Поле | Тип | Описание | |------|-----|---------| | `LINK` | string | URL файла | | `NAME` | string | Имя файла | | `SIZE` | integer | Размер в байтах | ```json { "FILE": [{ "LINK": "https://example.com/report.pdf", "NAME": "report.pdf", "SIZE": 2048576 }] } ``` ## Токены цвета (COLOR_TOKEN) `primary`, `secondary`, `alert`, `base` ## Полный пример ```json { "dialogId": "chat123", "fields": { "message": "", "attach": [ { "MESSAGE": [ { "MESSAGE": "Статус задачи обновлён", "STYLE": "bold" } ] }, { "DELIMITER": [{}] }, { "GRID": [ { "DISPLAY": "LINE", "NAME": "Задача", "VALUE": "Подготовить отчёт" }, { "DISPLAY": "LINE", "NAME": "Статус", "VALUE": "Выполнено" }, { "DISPLAY": "LINE", "NAME": "Исполнитель", "VALUE": "Иванов А.П." } ] }, { "LINK": [ { "NAME": "Открыть задачу", "LINK": "https://portal.bitrix24.ru/tasks/42/" } ] } ] } } ``` ## Смотрите также - [Отправить сообщение](/docs/bots/messages/send) - [Обновить сообщение](/docs/bots/messages/update) - [Форматирование текста](/docs/bots/messages/formatting) - [Клавиатура](/docs/bots/messages/keyboard) --- # Bot: Context ## Контекст сообщения `GET /v1/bots/:botId/messages/:messageId/context` Возвращает окно сообщений вокруг указанного. Используется для анализа истории диалога — например, чтобы понять контекст входящего сообщения. > **Ограничение по типу бота.** Метод доступен только для ботов с `type` ∈ {`personal`, `supervisor`}. Для остальных типов — `bot` и `openline` — ответ 422 с кодом `BITRIX_ERROR`, машиночитаемый код причины приходит в поле `error.b24Code` со значением `BOT_TYPE_NOT_ALLOWED`. Тип задаётся при регистрации через [POST /v1/bots](/docs/bots/management/create) и не меняется без перерегистрации. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `botId` (path) | number | да | ID бота | | `messageId` (path) | number | да | ID центрального сообщения | | `range` (query) | number | нет | Количество сообщений в каждую сторону от центрального (1-50). По умолчанию `50` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/bots/42/messages/1501/context?range=20" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/bots/42/messages/1501/context?range=20" \ -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/messages/1501/context?range=20', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Сообщений:', data.messages.length) console.log('Есть ещё до:', data.hasPrevPage) console.log('Есть ещё после:', data.hasNextPage) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/messages/1501/context?range=20', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `messages` | array | Массив сообщений вокруг центрального | | `messages[].id` | number | ID сообщения | | `messages[].chatId` | number | ID чата | | `messages[].authorId` | number | ID автора | | `messages[].date` | string | Дата отправки (ISO 8601) | | `messages[].text` | string | Текст сообщения | | `hasPrevPage` | boolean | Есть ещё сообщения до окна | | `hasNextPage` | boolean | Есть ещё сообщения после окна | ## Пример ответа ```json { "success": true, "data": { "messages": [ { "id": 1499, "chatId": 123, "authorId": 3, "date": "2026-03-31T09:58:00+03:00", "text": "Коллеги, есть вопрос по задаче" }, { "id": 1500, "chatId": 123, "authorId": 1, "date": "2026-03-31T09:59:00+03:00", "text": "Давай обсудим" }, { "id": 1501, "chatId": 123, "authorId": 1, "date": "2026-03-31T10:00:00+03:00", "text": "Привет, бот!" } ], "hasPrevPage": true, "hasNextPage": false } } ``` ## Пример ответа при ошибке 422 — тип бота не `personal` и не `supervisor`: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Bot type not allowed", "b24Code": "BOT_TYPE_NOT_ALLOWED" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_BOT_ID` | `botId` не является числом | | 404 | `BOT_NOT_FOUND` | Бот с таким ID не найден | | 403 | `BOT_ACCESS_DENIED` | Бот принадлежит другому API-ключу | | 422 | `BITRIX_ERROR` (`error.b24Code: BOT_TYPE_NOT_ALLOWED`) | Тип бота не `personal` и не `supervisor` | | 422 | `BITRIX_ERROR` (`error.b24Code: MESSAGE_NOT_FOUND`) | Сообщение с указанным `messageId` не найдено | | 422 | `BITRIX_ERROR` (`error.b24Code: MESSAGE_ACCESS_DENIED`) | Бот не является участником чата с этим сообщением или не имеет доступа к истории | | 422 | `BITRIX_ERROR` | Другая ошибка Битрикс24, текст в `message` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Пагинация:** `hasPrevPage` и `hasNextPage` указывают, есть ли сообщения за пределами окна. Для полного обхода можно использовать крайние `id` из `messages` как новый `messageId`. ## Смотрите также - [Получить сообщение](/docs/bots/messages/get) - [Прочитать сообщения](/docs/bots/messages/read) - [События](/docs/bots/events) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Delete ## Удалить сообщение `DELETE /v1/bots/:botId/messages/:messageId` Удаляет сообщение. По умолчанию — мягкое скрытие. Для полного удаления из базы данных передайте `complete: true`. ## Поля запроса (body) | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `complete` | boolean | нет | `false` | `true` — полное удаление из БД, `false` — мягкое скрытие | ## Примеры ### curl — личный ключ ```bash curl -X DELETE https://vibecode.bitrix24.tech/v1/bots/42/messages/1502 \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "complete": true }' ``` ### curl — OAuth-приложение ```bash curl -X DELETE https://vibecode.bitrix24.tech/v1/bots/42/messages/1502 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "complete": true }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/messages/1502', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ complete: true }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/messages/1502', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ complete: true }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.result` | boolean | `true` при успешном удалении | ## Пример ответа ```json { "success": true, "data": { "result": true } } ``` ## Пример ответа при ошибке 403 — бот принадлежит другому ключу: ```json { "success": false, "error": { "code": "BOT_ACCESS_DENIED", "message": "This bot belongs to a different API key" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_BOT_ID` | `botId` не является числом | | 404 | `BOT_NOT_FOUND` | Бот с таким ID не найден | | 403 | `BOT_ACCESS_DENIED` | Бот принадлежит другому API-ключу | | 422 | `BITRIX_ERROR` | Ошибка Битрикс24 (текст ошибки в `message`) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Мягкое vs полное удаление:** без `complete: true` сообщение помечается удалённым, но остаётся в базе. С `complete: true` удаляется полностью. **Системные сообщения:** сообщения с `authorId = 0` (отправленные с `system: true`) бот не может удалить, если не является администратором чата. **Пустое тело:** для мягкого удаления body можно не передавать. ## Смотрите также - [Отправить сообщение](/docs/bots/messages/send) - [Обновить сообщение](/docs/bots/messages/update) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Formatting ## Форматирование текста (BB-коды) Текст сообщений поддерживает BB-коды для стилизации. Используйте их в поле `fields.message` при отправке и обновлении сообщений. ## Список BB-кодов | Код | Описание | Пример | |-----|---------|--------| | `[B]...[/B]` | Жирный текст | `[B]Важно[/B]` | | `[I]...[/I]` | Курсив | `[I]примечание[/I]` | | `[U]...[/U]` | Подчёркнутый | `[U]внимание[/U]` | | `[S]...[/S]` | Зачёркнутый | `[S]устарело[/S]` | | `[URL=ссылка]текст[/URL]` | Гиперссылка | `[URL=https://example.com]Открыть[/URL]` | | `[CODE]...[/CODE]` | Блок кода (моноширинный шрифт) | `[CODE]console.log('hi')[/CODE]` | | `[BR]` или `\n` | Перенос строки | — | | `[SEND=значение]текст[/SEND]` | Клик отправляет значение как сообщение | `[SEND=/help]Помощь[/SEND]` | | `[PUT=значение]текст[/PUT]` | Вставка текста в поле ввода (без отправки) | `[PUT=/search ]Поиск[/PUT]` | | `[IMG]ссылка[/IMG]` | Встроенное изображение | `[IMG]https://example.com/pic.png[/IMG]` | | `[CALL=номер]текст[/CALL]` | Ссылка-звонок | `[CALL=+79161234567]Позвонить[/CALL]` | | `[SIZE=число]...[/SIZE]` | Размер текста | `[SIZE=18]Заголовок[/SIZE]` | | `[COLOR=цвет]...[/COLOR]` | Цвет текста (HEX или имя) | `[COLOR=#ff0000]Красный[/COLOR]` | ## Пример ```json { "dialogId": "chat123", "fields": { "message": "[B]Задача #42[/B]\nСтатус: [COLOR=#00aa00]выполнено[/COLOR]\n[URL=https://portal.bitrix24.ru/tasks/42/]Открыть задачу[/URL]\n\n[SEND=/status 42]Обновить статус[/SEND]" } } ``` ## Смотрите также - [Отправить сообщение](/docs/bots/messages/send) - [Клавиатура](/docs/bots/messages/keyboard) - [ATTACH-блоки](/docs/bots/messages/attach) --- # Bot: Get ## Получить сообщение `GET /v1/bots/:botId/messages/:messageId` Возвращает сообщение по его ID. > **Ограничение по типу бота.** Метод доступен только для ботов с `type` ∈ {`personal`, `supervisor`}. Для остальных типов — `bot` и `openline` — ответ 422 с кодом `BITRIX_ERROR`, машиночитаемый код причины приходит в поле `error.b24Code` со значением `BOT_TYPE_NOT_ALLOWED`. Тип задаётся при регистрации через [POST /v1/bots](/docs/bots/management/create) и не меняется без перерегистрации. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `botId` (path) | number | да | ID бота | | `messageId` (path) | number | да | ID сообщения | ## Примеры ### curl — личный ключ ```bash curl https://vibecode.bitrix24.tech/v1/bots/42/messages/1501 \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl https://vibecode.bitrix24.tech/v1/bots/42/messages/1501 \ -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/messages/1501', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Сообщение:', data.text) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/messages/1501', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID сообщения | | `chatId` | number | ID чата | | `authorId` | number | ID автора | | `date` | string | Дата отправки (ISO 8601) | | `text` | string | Текст сообщения | | `isSystem` | boolean | Системное сообщение | | `params` | object | Дополнительные параметры сообщения | ## Пример ответа ```json { "success": true, "data": { "id": 1501, "chatId": 123, "authorId": 1, "date": "2026-03-31T10:00:00+03:00", "text": "Привет, бот!", "isSystem": false, "params": {} } } ``` ## Пример ответа при ошибке 422 — тип бота не `personal` и не `supervisor`: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Bot type not allowed", "b24Code": "BOT_TYPE_NOT_ALLOWED" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_BOT_ID` | `botId` не является числом | | 404 | `BOT_NOT_FOUND` | Бот с таким ID не найден | | 403 | `BOT_ACCESS_DENIED` | Бот принадлежит другому API-ключу | | 422 | `BITRIX_ERROR` (`error.b24Code: BOT_TYPE_NOT_ALLOWED`) | Тип бота не `personal` и не `supervisor` | | 422 | `BITRIX_ERROR` | Другая ошибка Битрикс24, текст в `message` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Типичный сценарий:** бот получил событие с `replyId` и хочет прочитать исходное сообщение, на которое ответил пользователь. ## Смотрите также - [Контекст сообщения](/docs/bots/messages/context) - [Отправить сообщение](/docs/bots/messages/send) - [События](/docs/bots/events) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Keyboard ## Клавиатура Интерактивные кнопки, прикрепляемые к сообщению через поле `fields.keyboard`. Каждая кнопка — объект в массиве. ## Поля кнопки | Поле | Тип | По умолч. | Описание | |------|-----|-----------|---------| | `TEXT` | string | — | Текст кнопки. Обязателен для всех кнопок кроме `TYPE: "NEWLINE"` | | `TYPE` | string | — | Специальный тип: `NEWLINE` (перенос на новую строку) | | `LINK` | string | — | URL — кнопка становится ссылкой | | `COMMAND` | string | — | Команда бота (вызывает событие `ONIMBOTV2COMMANDADD`) | | `COMMAND_PARAMS` | string | — | Параметры команды | | `ACTION` | string | — | Действие при нажатии: `PUT` (вставить в поле ввода), `SEND` (отправить текст), `COPY` (скопировать), `CALL` (позвонить), `DIALOG` (открыть чат) | | `ACTION_VALUE` | string | — | Значение для `ACTION` (текст, номер телефона, ID чата) | | `BG_COLOR` | string | — | Цвет фона в формате HEX (`#ff6600`) | | `BG_COLOR_TOKEN` | string | `base` | Токен цвета (см. [таблицу ниже](#токены-цветов)) | | `TEXT_COLOR` | string | — | Цвет текста в формате HEX | | `DISPLAY` | string | `BLOCK` | Отображение: `LINE` (в строке с другими) или `BLOCK` (на всю ширину) | | `DISABLED` | string | `N` | Неактивная кнопка: `Y` или `N` | | `BLOCK` | string | `N` | Блокировка после нажатия: `Y` (деактивируется после клика) или `N` | | `WIDTH` | integer | — | Ширина кнопки в пикселях | | `CONTEXT` | string | `ALL` | Контекст: `MOBILE`, `DESKTOP`, `ALL` | | `OFF_BG_COLOR` | string | — | Цвет фона в неактивном состоянии (после нажатия при `BLOCK: "Y"`) | | `OFF_TEXT_COLOR` | string | — | Цвет текста в неактивном состоянии | ## Токены цветов | Токен | Цвет | Назначение | |-------|------|-----------| | `primary` | Синий | Основное действие | | `secondary` | Серый | Дополнительное действие | | `alert` | Красный | Деструктивное действие | | `base` | Белый | Нейтральная кнопка (по умолчанию) | ## Пример ```json { "dialogId": "chat123", "fields": { "message": "Подтвердите действие:", "keyboard": [ { "TEXT": "Одобрить", "BG_COLOR_TOKEN": "primary", "ACTION": "SEND", "ACTION_VALUE": "/approve", "BLOCK": "Y" }, { "TEXT": "Отклонить", "BG_COLOR_TOKEN": "alert", "ACTION": "SEND", "ACTION_VALUE": "/reject", "BLOCK": "Y" }, { "TYPE": "NEWLINE" }, { "TEXT": "Подробнее", "LINK": "https://portal.bitrix24.ru/tasks/42/", "BG_COLOR_TOKEN": "secondary", "DISPLAY": "LINE" }, { "TEXT": "Позвонить менеджеру", "ACTION": "CALL", "ACTION_VALUE": "+79161234567", "DISPLAY": "LINE", "CONTEXT": "MOBILE" } ] } } ``` ## Смотрите также - [Отправить сообщение](/docs/bots/messages/send) - [Обновить сообщение](/docs/bots/messages/update) - [Форматирование текста](/docs/bots/messages/formatting) - [ATTACH-блоки](/docs/bots/messages/attach) --- # Bot: Read ## Прочитать сообщения `POST /v1/bots/:botId/chats/:dialogId/read` Отмечает сообщения как прочитанные от имени бота. Без `messageId` прочитает все сообщения в чате. ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `botId` (path) | number | да | — | ID бота | | `dialogId` (path) | string | да | — | ID диалога: числовой ID пользователя для личных сообщений, `chatXXX` для групповых | | `messageId` (body) | number | нет | — | Прочитать все сообщения до этого включительно. Без параметра — прочитать все | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/read \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "messageId": 1501 }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/read \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "messageId": 1501 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/read', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ messageId: 1501 }), }) const { success, data } = await res.json() console.log('Прочитано до:', data.lastId) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/chats/chat456/read', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ messageId: 1501 }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `chatId` | number | ID чата | | `lastId` | number | ID последнего прочитанного сообщения | | `counter` | number | Оставшееся количество непрочитанных | | `viewedMessages` | number[] | ID прочитанных сообщений | ## Пример ответа ```json { "success": true, "data": { "chatId": 456, "lastId": 1501, "counter": 0, "viewedMessages": [1499, 1500, 1501] } } ``` ## Пример ответа при ошибке 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-ключу | | 422 | `BITRIX_ERROR` | Ошибка Битрикс24 (текст ошибки в `message`) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ в режиме «только чтение» | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Без messageId:** если не передать `messageId`, будут прочитаны все сообщения в чате. **Чтение до сообщения:** при указании `messageId` прочитываются все сообщения до указанного включительно, а не только это одно сообщение. ## Смотрите также - [Отправить сообщение](/docs/bots/messages/send) - [Получить сообщение](/docs/bots/messages/get) - [События](/docs/bots/events) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Send ## Отправить сообщение `POST /v1/bots/:botId/messages` Отправляет сообщение от имени бота в указанный диалог. Текст поддерживает [BB-коды](/docs/bots/messages/formatting), к сообщению можно прикрепить [клавиатуру](/docs/bots/messages/keyboard) и [ATTACH-блоки](/docs/bots/messages/attach). ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `botId` (path) | number | да | — | ID бота | | `dialogId` | string | да | — | ID диалога: числовой ID пользователя для личных сообщений, `chatXXX` для групповых | | `fields.message` | string | да | — | Текст сообщения (до 20 000 символов). Поддерживает [BB-коды](/docs/bots/messages/formatting) | | `fields.keyboard` | array | нет | — | Интерактивная [клавиатура](/docs/bots/messages/keyboard) | | `fields.attach` | array/object | нет | — | [ATTACH-блоки](/docs/bots/messages/attach) с оформленным содержимым | | `fields.replyId` | number | нет | — | ID сообщения для цитирования | | `fields.forwardIds` | object | нет | — | Сообщения для пересылки: `{uuid: messageId}`, где uuid — произвольная строка-ключ, messageId — ID исходного сообщения. Максимум 100. В ответе `uuidMap` вернёт `{uuid: newMessageId}` | | `fields.system` | boolean | нет | `false` | Системное сообщение (другой стиль, без аватара бота) | | `fields.urlPreview` | boolean | нет | `true` | Показывать превью ссылок в тексте | | `fields.templateId` | string | нет | — | UUID шаблона сообщения | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/messages \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "dialogId": "chat123", "fields": { "message": "[b]Задача #42[/b]\nСтатус: выполнено", "keyboard": [ { "TEXT": "Открыть задачу", "LINK": "https://portal.bitrix24.ru/tasks/42/", "BG_COLOR_TOKEN": "primary" } ] } }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/messages \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "dialogId": "chat123", "fields": { "message": "[b]Задача #42[/b]\nСтатус: выполнено", "keyboard": [ { "TEXT": "Открыть задачу", "LINK": "https://portal.bitrix24.ru/tasks/42/", "BG_COLOR_TOKEN": "primary" } ] } }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/messages', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ dialogId: 'chat123', fields: { message: '[b]Задача #42[/b]\nСтатус: выполнено', keyboard: [ { TEXT: 'Открыть задачу', LINK: 'https://portal.bitrix24.ru/tasks/42/', BG_COLOR_TOKEN: 'primary', }, ], }, }), }) const { success, data } = await res.json() console.log('Message ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/messages', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ dialogId: 'chat123', fields: { message: '[b]Задача #42[/b]\nСтатус: выполнено', keyboard: [ { TEXT: 'Открыть задачу', LINK: 'https://portal.bitrix24.ru/tasks/42/', BG_COLOR_TOKEN: 'primary', }, ], }, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID созданного сообщения | | `uuidMap` | array | Маппинг UUID при пересылке (пустой массив если без `forwardIds`) | ## Пример ответа ```json { "success": true, "data": { "id": 36357, "uuidMap": [] } } ``` ## Пример ответа при ошибке 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` не является числом | | 400 | `MESSAGE_REQUIRED` | В теле нет ни `message`, ни другого ключа содержимого. В тексте ошибки перечислены нераспознанные ключи тела и указано, куда положить текст. Пустой массив в `attach` и пустая строка в `message` содержимым не считаются | | 404 | `BOT_NOT_FOUND` | Бот с таким ID не найден | | 403 | `BOT_ACCESS_DENIED` | Бот принадлежит другому API-ключу | | 422 | `BITRIX_ERROR` | Ошибка Битрикс24 при отправке (текст ошибки в `message`) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Два формата тела:** канонический формат — содержимое сообщения внутри `fields` (как в примерах выше). Для удобства принимается и «плоский» формат, когда `message`, `keyboard`, `attach`, `system`, `urlPreview`, `replyId`, `forwardIds`, `templateId` передаются на верхнем уровне рядом с `dialogId` — они автоматически оборачиваются в `fields`. Это та же симметрия, что и у [обновления сообщения](/docs/bots/messages/update). Если передан `fields`, плоские ключи не применяются (приоритет у `fields`). **Системные сообщения:** при `system: true` сообщение отображается без аватара бота и имеет `authorId = 0`. Такие сообщения нельзя обновить или удалить через бота. **Текст обрезается:** если сообщение длиннее 20 000 символов, Битрикс24 обрежет текст и добавит ` (...)`. **Пересылка (forwardIds):** формат — объект `{uuid: messageId}`, где uuid — произвольная строка, а messageId — ID исходного сообщения. Бот может пересылать только сообщения из чатов, где он является участником. ## Смотрите также - [Обновить сообщение](/docs/bots/messages/update) - [Форматирование текста](/docs/bots/messages/formatting) - [Клавиатура](/docs/bots/messages/keyboard) - [ATTACH-блоки](/docs/bots/messages/attach) - [События](/docs/bots/events) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Update ## Обновить сообщение `PATCH /v1/bots/:botId/messages/:messageId` Обновляет ранее отправленное ботом сообщение. Бот может обновлять только собственные сообщения. ## Поля запроса (body) | Параметр | Тип | Описание | |----------|-----|---------| | `message` | string | Новый текст сообщения (до 20 000 символов). Поддерживает [BB-коды](/docs/bots/messages/formatting) | | `keyboard` | array | Новая [клавиатура](/docs/bots/messages/keyboard). Для удаления передайте `"N"` | | `attach` | array/object | Новые [ATTACH-блоки](/docs/bots/messages/attach) | | `urlPreview` | boolean | Показывать превью ссылок | ## Примеры ### curl — личный ключ ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/bots/42/messages/1502 \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "message": "Обновлённый текст сообщения", "keyboard": [ { "TEXT": "Готово", "BG_COLOR_TOKEN": "primary", "DISABLED": "Y" } ] }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/bots/42/messages/1502 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "message": "Обновлённый текст сообщения", "keyboard": [ { "TEXT": "Готово", "BG_COLOR_TOKEN": "primary", "DISABLED": "Y" } ] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/messages/1502', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ message: 'Обновлённый текст сообщения', keyboard: [ { TEXT: 'Готово', BG_COLOR_TOKEN: 'primary', DISABLED: 'Y', }, ], }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/messages/1502', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ message: 'Обновлённый текст сообщения', keyboard: [ { TEXT: 'Готово', BG_COLOR_TOKEN: 'primary', DISABLED: 'Y', }, ], }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.result` | boolean | `true` при успешном обновлении | ## Пример ответа ```json { "success": true, "data": { "result": true } } ``` ## Пример ответа при ошибке 403 — сообщение не принадлежит боту или не существует: ```json { "success": false, "error": { "code": "BITRIX_ACCESS_DENIED", "message": "Access denied" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_BOT_ID` | `botId` не является числом | | 400 | `MESSAGE_REQUIRED` | В теле нет ни `message`, ни другого ключа содержимого. Пустая строка в `message` содержимым не считается. Раньше такой запрос отвечал `200` и ничего не менял | | 404 | `BOT_NOT_FOUND` | Бот с таким ID не найден | | 403 | `BOT_ACCESS_DENIED` | Бот принадлежит другому API-ключу | | 403 | `BITRIX_ACCESS_DENIED` | Сообщение не принадлежит боту или не существует. Бот обновляет только свои сообщения | | 422 | `BITRIX_ERROR` | Другая ошибка Битрикс24, текст в `message` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Системные сообщения нельзя обновить:** сообщения, отправленные с `system: true`, имеют `authorId = 0` и не принадлежат боту с точки зрения прав. Битрикс24 вернёт ошибку. **Удаление клавиатуры:** передайте `"keyboard": "N"` чтобы убрать клавиатуру с сообщения. ## Смотрите также - [Отправить сообщение](/docs/bots/messages/send) - [Удалить сообщение](/docs/bots/messages/delete) - [Клавиатура](/docs/bots/messages/keyboard) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Ownership Recovery # Восстановление доступа к боту Бот привязан к тому ключу, которым зарегистрирован, поэтому другой ключ не видит его в списке и не может занять тот же код. Доступ возвращается переносом владения на действующий ключ — бот не пересоздаётся, чаты и история сообщений сохраняются. ## Как выглядит потеря доступа Признаки приходят все сразу: - `GET /v1/bots` отвечает успехом и пустым массивом `bots`, хотя бот на портале работает. - `POST /v1/bots` с тем же `code` отвечает `409 BOT_ALREADY_EXISTS` — код занят. - `GET /v1/bots/:botId` по идентификатору из ответа `409` отвечает `403 BOT_ACCESS_DENIED`. - `GET /v1/me` при этом подтверждает, что сам ключ действует: `accessMode` равен `READWRITE`, скоуп `imbot` присутствует. Список ботов ключом, который ими не управляет: ```json { "success": true, "data": { "bots": [], "users": [], "hasNextPage": false } } ``` Повторная регистрация с тем же кодом — в поле `data` приходит существующий бот: ```json { "success": false, "error": { "code": "BOT_ALREADY_EXISTS", "message": "Bot with this code already exists" }, "data": { "botId": 42, "code": "support_bot", "name": "Техподдержка" } } ``` Обращение к этому боту тем же ключом: ```json { "success": false, "error": { "code": "BOT_ACCESS_DENIED", "message": "This bot belongs to a different API key" } } ``` ## Почему бот не виден У бота две разные привязки. Владение закреплено за пользователем Вайбкод и не меняется, когда ключи истекают или отзываются. Привязка к ключу означает другое — каким ключом бот управляется сейчас. `GET /v1/bots` возвращает записи из базы Вайбкод, отфильтрованные по вызывающему ключу, поэтому бот, зарегистрированный другим ключом, в список не попадает. Остальные операции — события, сообщения, обновление — авторизуются так же и отвечают `403 BOT_ACCESS_DENIED`. Уникальность кода бота при этом проверяется в границах портала, а не ключа. Отсюда и расхождение: список пуст, а код занят. Сам бот не затронут. Он остаётся на портале, состоит в тех же чатах и сохраняет историю сообщений — недоступно только управление им через API. ## Как вернуть доступ Четыре шага. Вызовы к боту выполняются тем ключом, на который переносится владение. Перенос доступен владельцу бота, то есть пользователю Вайбкод, которому принадлежит ключ-владелец. Выполнить перенос может и администратор портала. ### 1. Узнать идентификатор бота Повторите регистрацию с тем же `code`. Ответ `409` означает, что код занят: идентификатор существующего бота приходит в `data.botId`, и запись бота при этом не меняется. Регистрация выполняется от лица администратора портала Битрикс24 — иначе Битрикс24 отвечает отказом в доступе. ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "code": "support_bot", "name": "Техподдержка" }' ``` Ответ `201` вместо `409` означает, что регистрация прошла идемпотентно. Владение при этом не переходит, бот по-прежнему не приходит в `GET /v1/bots`, а его `name`, `type`, `eventMode` и `webhookUrl` обновляются значениями из запроса. Если бот работал в режиме `webhook`, передайте `eventMode` и `webhookUrl` вместе с `code` и `name`, чтобы сохранить доставку событий. Идентификатор бота в этом ответе приходит в `data.botId` — переходите к шагу 2. Порядок применим к ботам, зарегистрированным через Вайбкод. Бот, заведённый на портале Битрикс24 в обход платформы, в базе Вайбкод записи не имеет: в ответе `409` поле `data` не придёт, а перенос ответит `404 BOT_NOT_FOUND`. ### 2. Узнать идентификатор целевого ключа `targetApiKeyId` — это поле `id` записи ключа, а не строка ключа. Список отдаёт [`GET /v1/keys`](/docs/management-keys) менеджмент-ключу со скоупом `vibe:mgmt:keys` — ключу портала этот список не доступен, в ответ приходит `401 WRONG_KEY_TYPE`. Менеджмент-ключ создаётся в личном кабинете, и для этого шага достаточно ключа в режиме «только чтение»: список отдаётся, а изменять ключи такой ключ не может. После переноса его можно отозвать. В ответ приходят ключи владельца менеджмент-ключа на указанном портале. Свой ключ узнаётся по полям `prefix` и `suffix`, `portalId` приходит в поле `portal.id` ответа [`GET /v1/me`](/docs/keys-auth) — этому вызову менеджмент-скоупы не нужны. Тот же идентификатор отдаёт [`GET /v1/portals`](/docs/management-keys), но у него свой скоуп `vibe:mgmt:portals`. Администратору, который переносит бота на ключ другого пользователя, идентификатор этого ключа сообщает его владелец — чужие ключи в списке не приходят. ```bash curl -H "X-Api-Key: YOUR_MANAGEMENT_KEY" \ "https://vibecode.bitrix24.tech/v1/keys?portalId=PORTAL_ID" ``` ### 3. Перенести владение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/transfer \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "targetApiKeyId": "3f9a1c20-5e6b-4d18-9a77-0c2b8e4f1d33" }' ``` ```json { "success": true, "data": { "transferred": true, "botId": 42, "fromApiKeyId": "8c41d5e7-2b90-4a63-b1f5-6d7e9a0c4b12", "toApiKeyId": "3f9a1c20-5e6b-4d18-9a77-0c2b8e4f1d33" } } ``` После этого ответа бот приходит в `GET /v1/bots` нового ключа. ### 4. Проверить привязку Перенос меняет привязку на стороне Вайбкод. Проверяет доступ нового ключа к боту на портале отдельный вызов. Он отвечает только ключу-владельцу, поэтому шаг выполняет владелец целевого ключа: администратор, перенёсший бота на ключ другого пользователя, получит `403 BOT_ACCESS_DENIED`. ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/reauth \ -H "X-Api-Key: YOUR_API_KEY" ``` ```json { "success": true, "data": { "validated": true, "refreshed": false } } ``` `validated: true` подтверждает, что новый ключ управляет ботом на портале, — с ним снова работают события, сообщения и обновление. ## Требования к целевому ключу Ключ принимается, когда выполнены все условия: | Условие | Значение | |---------|----------| | Состояние | `ACTIVE` | | Портал | Тот же портал Битрикс24, что и у бота | | Владелец | Тот же пользователь Вайбкод, который выполняет перенос. Администратор портала переносит бота на ключ любого пользователя того же портала — этот путь работает с личного ключа `vibe_api_`, роль на портале определяется по нему | | Скоуп | `imbot` | | Срок действия | Не закончился | | Назначение | Ключ общего назначения. Выпущенные платформой служебные ключи не принимаются: у них свой жизненный цикл, и после их ротации бот снова останется без управления | Режим доступа целевого ключа перенос не проверяет — ключ «только чтение» он примет. Управлять ботом таким ключом всё равно нельзя: шаг 4 и все последующие вызовы ответят `403 WRITE_BLOCKED_READONLY_KEY`. Переносите владение на ключ в режиме `READWRITE`. Проверить ключ до вызова можно по его записи из `GET /v1/keys` шага 2: состояние приходит в поле `status`, портал — в `portalId`, владелец — в `userId`, скоупы — в `scopes`, срок действия — в `expiresAt`, режим доступа — в `accessMode`. Ключ, не прошедший проверку, отклоняется с `400 TARGET_KEY_INVALID`, а причина приходит в поле `reason` — расшифровка причин в таблице ошибок раздела [Перенос владения ботом](/docs/bots/management/transfer). ## Когда это нужно Три состояния приводят к одной картине — бот работает, а ключ его не видит. **Ключ-владелец перестал работать.** Значение ключа не сохранили при создании, ключ отозван или его срок действия закончился. Привязка бота цела — доступ возвращается переносом на новый ключ. **Бот зарегистрирован другим ключом.** Так происходит, когда приложение развёрнуто с одним ключом, а бот регистрировался другим, либо когда ключ пересоздали вместе с OAuth-приложением. Перенос собирает бота и рабочий ключ обратно вместе. **Бот принадлежит ресурсу платформы.** Ботом AI-агента или управляемого бота распоряжается сам ресурс, поэтому прямой перенос отвечает `409 BOT_TRANSFER_NOT_ALLOWED`. Такой бот восстанавливается со стороны своего ресурса — см. [AI-агенты](/docs/agents). ## Ошибки | HTTP | Код | Когда возвращается | |------|-----|---------------------| | 409 | `BOT_ALREADY_EXISTS` | Код занят ботом, зарегистрированным другим ключом. Для бота, заведённого через Вайбкод, в `data.botId` приходит его идентификатор | | 403 | `BOT_ACCESS_DENIED` | Обращение к боту ключом, который им не управляет | | 401 | `WRONG_KEY_TYPE` | Список ключей запрошен ключом портала — `GET /v1/keys` отвечает только менеджмент-ключу | | 403 | `NOT_BOT_OWNER` | Перенос выполняет не владелец бота — нужен тот же пользователь Вайбкод, что у ключа-владельца, или администратор портала | | 400 | `TARGET_KEY_INVALID` | Целевой ключ не прошёл проверку, причина в поле `reason` | | 404 | `TARGET_KEY_NOT_FOUND` | Ключа с таким `targetApiKeyId` нет | | 409 | `BOT_TRANSFER_NOT_ALLOWED` | Бот принадлежит AI-агенту или другому ресурсу платформы | | 409 | `BOT_TRANSFER_CONFLICT` | Владение изменил параллельный запрос — перечитайте текущую привязку и повторите при необходимости | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключом в режиме «только чтение» выполнен пишущий вызов: регистрация, перенос или проверка привязки | | 401 | `TOKEN_MISSING` | Ключ авторизации `vibe_app_` отправлен без заголовка `Authorization: Bearer` | | 410 | `REAUTH_REQUIRED` | Проверка на шаге 4 не подтвердила доступ: учётные данные ключа недействительны и не обновляются автоматически. Авторизуйте ключ заново через OAuth или создайте личный ключ заново | Полный справочник кодов — [Коды ошибок](/docs/errors). ## Известные особенности **Порядок безопасно повторять с начала.** Перенос на ключ, который уже владеет ботом, привязку не меняет. Сверять текущее состояние перед повтором не нужно. **Прежний ключ перестаёт видеть бота сразу.** После переноса бот пропадает из `GET /v1/bots` прежнего ключа — остальные его боты в списке остаются. Если бота опрашивали два процесса, опрос продолжает только тот, что работает новым ключом. **Регистрация под новым кодом даёт другого бота.** У него собственный `botId`, собственные чаты и история, а прежний бот остаётся на портале и продолжает занимать свой код. ## Смотрите также - [Перенос владения ботом](/docs/bots/management/transfer) - [Повторная авторизация бота](/docs/bots/management/reauth) - [Список ботов](/docs/bots/management/list) - [Диагностика проблем](/docs/bots/troubleshooting) - [Менеджмент-ключи](/docs/management-keys) --- # Bot: Troubleshooting # Диагностика проблем бот-платформы Если бот не отвечает на сообщения, начните с разделов ниже. Каждый сценарий — отдельный набор проверок с готовыми командами `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 не направляет события боту. Соберите данные по разделу [Куда обратиться](#куда-обратиться) и отправьте тикет. --- ## TOKEN_MISSING при ключе авторизации Симптом: ```json { "success": false, "error": { "code": "TOKEN_MISSING", "message": "API key has no tokens configured." } } ``` ### Причина Ключ `vibe_app_…` отправлен без заголовка `Authorization: Bearer `. Ключ авторизации работает в паре с токеном пользовательской сессии — без 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)) } ``` --- ## Бот отключён (BOT_DISABLED) Симптом: ```json { "success": false, "error": { "code": "BOT_DISABLED", "message": "Bot is disabled (reason: …)" } } ``` HTTP-код — `410 Gone`. Затронуты все эндпоинты бота: события, сообщения, чаты, команды, обновление, удаление. ### Возможные причины (поле `reason`) - `AUTH_FAILURES` — 10 подряд `401 INVALID_CREDENTIALS` от Битрикс24. Платформа защищает портал от шумных запросов и автоматически отключает бота со сломанной авторизацией. - `PORTAL_DELETED` — портал Битрикс24 удалён или подтверждён недоступным. ### Решение `AUTH_FAILURES` — вызовите [`POST /v1/bots/:botId/reauth`](/docs/bots/management/reauth). Проверка подтверждает доступ бота, при необходимости обновляет токен и снимает отключение. Если в ответ пришёл `410 REAUTH_REQUIRED` — доступ восстановить автоматически нельзя, ключ нужно авторизовать заново через OAuth или пересоздать личный ключ. Сбросить только счётчик ошибок авторизации, без проверки доступа, можно через `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-бота отключите автоматический переход в сон, чтобы сервер оставался доступен. Достижимость `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/keys-auth) - [Коды ошибок](/docs/errors) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Ui # Интерфейс Ставьте реакции на сообщения, показывайте индикатор набора текста и управляйте полем ввода в чате. **Скоуп:** `imbot` | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` ## Операции - [Добавить реакцию](./ui/reaction-add.md) — `POST /v1/bots/:botId/messages/:messageId/reactions` - [Удалить реакцию](./ui/reaction-delete.md) — `DELETE /v1/bots/:botId/messages/:messageId/reactions` - [Индикатор набора](./ui/typing.md) — `POST /v1/bots/:botId/typing` - [Управление полем ввода](./ui/text-field.md) — `POST /v1/bots/:botId/text-field` ## Справочники - [Коды реакций](./ui/reactions.md) — 48 доступных кодов --- # Bot: Reaction Add ## Добавить реакцию `POST /v1/bots/:botId/messages/:messageId/reactions` Добавляет реакцию бота на сообщение. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `reaction` | string | да | Код реакции (см. [Коды реакций](/docs/bots/ui/reactions)) | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/messages/1501/reactions \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "reaction": "like" }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/messages/1501/reactions \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "reaction": "like" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/messages/1501/reactions', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ reaction: 'like' }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/messages/1501/reactions', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ reaction: 'like' }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.result` | boolean | `true` при успешном добавлении | ## Пример ответа ```json { "success": true, "data": { "result": true } } ``` ## Пример ответа при ошибке 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-ключу | | 422 | `BITRIX_ERROR` | Ошибка Битрикс24 (текст ошибки в `message`) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Коды реакций](/docs/bots/ui/reactions) - [Удалить реакцию](/docs/bots/ui/reaction-delete) - [Отправить сообщение](/docs/bots/messages/send) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Reaction Delete ## Удалить реакцию `DELETE /v1/bots/:botId/messages/:messageId/reactions` Удаляет реакцию бота с сообщения. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `reaction` | string | да | Код реакции для удаления (см. [Коды реакций](/docs/bots/ui/reactions)) | ## Примеры ### curl — личный ключ ```bash curl -X DELETE https://vibecode.bitrix24.tech/v1/bots/42/messages/1501/reactions \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "reaction": "like" }' ``` ### curl — OAuth-приложение ```bash curl -X DELETE https://vibecode.bitrix24.tech/v1/bots/42/messages/1501/reactions \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "reaction": "like" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/messages/1501/reactions', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ reaction: 'like' }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/messages/1501/reactions', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ reaction: 'like' }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.result` | boolean | `true` при успешном удалении | ## Пример ответа ```json { "success": true, "data": { "result": true } } ``` ## Пример ответа при ошибке 403 — бот принадлежит другому ключу: ```json { "success": false, "error": { "code": "BOT_ACCESS_DENIED", "message": "This bot belongs to a different API key" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_BOT_ID` | `botId` не является числом | | 404 | `BOT_NOT_FOUND` | Бот с таким ID не найден | | 403 | `BOT_ACCESS_DENIED` | Бот принадлежит другому API-ключу | | 422 | `BITRIX_ERROR` | Ошибка Битрикс24 (текст ошибки в `message`) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Коды реакций](/docs/bots/ui/reactions) - [Добавить реакцию](/docs/bots/ui/reaction-add) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Reactions ## Коды реакций 48 доступных кодов для [добавления](/docs/bots/ui/reaction-add) и [удаления](/docs/bots/ui/reaction-delete) реакций. | Код | Описание | |-----|---------| | `like` | Нравится | | `dislike` | Не нравится | | `faceWithTearsOfJoy` | До слёз | | `redHeart` | Сердечко | | `neutralFace` | Равнодушен | | `fire` | Огонь! | | `cry` | Жаль | | `slightlySmilingFace` | Улыбаюсь | | `winkingFace` | Подмигиваю | | `laugh` | Смеюсь | | `kiss` | Восхищаюсь | | `wonder` | Шок | | `slightlyFrowningFace` | Грущу | | `loudlyCryingFace` | Плачу | | `faceWithStuckOutTongue` | Язык | | `faceWithStuckOutTongueAndWinkingEye` | Дразнюсь | | `smilingFaceWithSunglasses` | Круто | | `confusedFace` | Ну не знаю | | `flushedFace` | Смущаюсь | | `thinkingFace` | Сомневаюсь | | `angry` | Злюсь | | `smilingFaceWithHorns` | Злорадно | | `faceWithThermometer` | Болею | | `facepalm` | Без комментариев | | `poo` | Фу | | `flexedBiceps` | Мощно | | `clappingHands` | Великолепно | | `raisedHand` | Дай пять | | `smilingFaceWithHeartEyes` | Красота | | `smilingFaceWithHearts` | Обожаю | | `pleadingFace` | Умоляю | | `relievedFace` | Дзен | | `foldedHands` | Спасибо | | `okHand` | ОК | | `signHorns` | Рок! | | `loveYouGesture` | Всё круто | | `clownFace` | Клоун | | `partyingFace` | Поздравляю | | `questionMark` | Вопрос | | `exclamationMark` | Внимание | | `lightBulb` | Идея | | `bomb` | Бомба | | `sleepingSymbol` | Засыпаю | | `crossMark` | Отмена | | `whiteHeavyCheckMark` | Готово | | `eyes` | Глаза | | `handshake` | Договорились | | `hundredPoints` | Поддерживаю | ## Смотрите также - [Добавить реакцию](/docs/bots/ui/reaction-add) - [Удалить реакцию](/docs/bots/ui/reaction-delete) - [События](/docs/bots/events) --- # Bot: Text Field ## Управление полем ввода `POST /v1/bots/:botId/text-field` Включает или отключает поле ввода текста в чате с ботом. Полезно, если бот принимает ввод только через клавиатуру (кнопки). ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `dialogId` | string | да | ID диалога: числовой ID пользователя для личных, `chatXXX` для групповых | | `enabled` | boolean | да | `true` — включить поле ввода, `false` — отключить | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/text-field \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "dialogId": "chat123", "enabled": false }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/text-field \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "dialogId": "chat123", "enabled": false }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/text-field', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ dialogId: 'chat123', enabled: false }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/text-field', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ dialogId: 'chat123', enabled: false }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.result` | boolean | `true` при успешном изменении | ## Пример ответа ```json { "success": true, "data": { "result": true } } ``` ## Пример ответа при ошибке 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-ключу | | 422 | `BITRIX_ERROR` | Ошибка Битрикс24 (текст ошибки в `message`) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Индикатор набора](/docs/bots/ui/typing) - [Клавиатура](/docs/bots/messages/keyboard) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Bot: Typing ## Индикатор набора `POST /v1/bots/:botId/typing` Показывает индикатор статуса в чате. Вызывайте перед отправкой ответа, чтобы пользователь видел, что бот работает. ## Поля запроса (body) | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `dialogId` | string | да | — | ID диалога: числовой ID пользователя для личных, `chatXXX` для групповых | | `statusMessageCode` | string | нет | — | Код статуса действия (см. [таблицу ниже](#коды-статуса)). Без параметра — стандартный индикатор «печатает» | | `duration` | number | нет | — | Длительность отображения в секундах (1-600) | ## Коды статуса | Код | Описание | |-----|---------| | `IMBOT_AGENT_ACTION_THINKING` | Думает | | `IMBOT_AGENT_ACTION_SEARCHING` | Ищет | | `IMBOT_AGENT_ACTION_GENERATING` | Генерирует | | `IMBOT_AGENT_ACTION_ANALYZING` | Анализирует | | `IMBOT_AGENT_ACTION_PROCESSING` | Обрабатывает | | `IMBOT_AGENT_ACTION_TRANSLATING` | Переводит | | `IMBOT_AGENT_ACTION_CONNECTING` | Подключается | | `IMBOT_AGENT_ACTION_CHECKING` | Проверяет | | `IMBOT_AGENT_ACTION_CALCULATING` | Вычисляет | | `IMBOT_AGENT_ACTION_READING_DOCS` | Читает документацию | | `IMBOT_AGENT_ACTION_COMPOSING` | Составляет ответ | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/typing \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "dialogId": "chat123", "statusMessageCode": "IMBOT_AGENT_ACTION_THINKING", "duration": 30 }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/bots/42/typing \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "dialogId": "chat123", "statusMessageCode": "IMBOT_AGENT_ACTION_THINKING", "duration": 30 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/typing', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ dialogId: 'chat123', statusMessageCode: 'IMBOT_AGENT_ACTION_THINKING', duration: 30, }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bots/42/typing', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ dialogId: 'chat123', statusMessageCode: 'IMBOT_AGENT_ACTION_THINKING', duration: 30, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.result` | boolean | `true` при успешной отправке | ## Пример ответа ```json { "success": true, "data": { "result": true } } ``` ## Пример ответа при ошибке 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-ключу | | 422 | `BITRIX_ERROR` | Ошибка Битрикс24 (текст ошибки в `message`) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imbot` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **AI-боты:** используйте `statusMessageCode` для информативного статуса. Например, `IMBOT_AGENT_ACTION_ANALYZING` при обработке запроса, затем `IMBOT_AGENT_ACTION_COMPOSING` перед отправкой ответа. **Автоматическое скрытие:** индикатор исчезает при отправке сообщения ботом или по истечении `duration`. ## Смотрите также - [Управление полем ввода](/docs/bots/ui/text-field) - [Отправить сообщение](/docs/bots/messages/send) - [Бот-платформа](/docs/bots) - [Лимиты и оптимизация](/docs/optimization) --- # Entity: Activities # Дела Управление делами CRM: звонки, встречи, задачи, email. Привязываются к сделкам, лидам, контактам и другим сущностям. Bitrix24 API: `crm.activity.*` Скоуп: `crm` Одно дело можно показать в таймлайне сразу нескольких CRM-сущностей — см. [Привязки дел](./activities/bindings.md). Дело с собственным оформлением в таймлайне — иконка, заголовок, блоки, кнопки — создаётся через [Конфигурируемые дела](./activities/configurable.md). AI-расшифровку звонка клиента — дела типа «Звонок» — возвращает [Расшифровки звонков CRM](./activities/transcript.md). ## Операции - [Создать дело](./activities/create.md) — `POST /v1/activities` - [Список дел](./activities/list.md) — `GET /v1/activities` - [Получить дело](./activities/get.md) — `GET /v1/activities/:id` - [Обновить дело](./activities/update.md) — `PATCH /v1/activities/:id` - [Удалить дело](./activities/delete.md) — `DELETE /v1/activities/:id` - [Поиск дел](./activities/search.md) — `POST /v1/activities/search` - [Поля дела](./activities/fields.md) — `GET /v1/activities/fields` - [Агрегация дел](./activities/aggregate.md) — `POST /v1/activities/aggregate` - [Скачать файл дела](./activities/file-download.md) — `GET /v1/activities/:activityId/files/:fileId/download` --- # Entity: Addresses # Адреса Адреса CRM-сущностей: фактический, юридический, для корреспонденции, доставки. Чаще всего привязаны к реквизиту, но тот же эндпоинт работает для контактов, компаний и лидов. У адреса нет отдельного числового `id`: конкретный адрес задаётся тремя значениями — тип адреса `typeId`, тип владельца `entityTypeId` и ID владельца `entityId`. Битрикс24 API: `crm.address.*` Скоуп: `crm` ## Операции - [Создать адрес](./addresses/create.md) — `POST /v1/addresses` - [Список адресов](./addresses/list.md) — `GET /v1/addresses` - [Получить адрес](./addresses/get.md) — `GET /v1/addresses/:typeId/:entityTypeId/:entityId` - [Обновить адрес](./addresses/update.md) — `PATCH /v1/addresses/:typeId/:entityTypeId/:entityId` - [Удалить адрес](./addresses/delete.md) — `DELETE /v1/addresses/:typeId/:entityTypeId/:entityId` - [Поиск адресов](./addresses/search.md) — `POST /v1/addresses/search` - [Поля адреса](./addresses/fields.md) — `GET /v1/addresses/fields` ## Ключевые поля | Поле | Описание | |------|---------| | `typeId` | Тип адреса, коды с `1` по `12`. Для фактического — `1`, для юридического — `6`, для корреспонденции — `8`, для доставки — `11`. Полный справочник — [Получить адрес](./addresses/get.md) | | `entityTypeId` | Тип владельца: `8` — реквизит (также контакт, компания, лид) | | `entityId` | ID владельца адреса | | `address1` | Улица, дом | | `city` | Город | | `postalCode` | Почтовый индекс | Полный список полей — [`GET /v1/addresses/fields`](./addresses/fields.md). ## Что нужно знать перед работой 1. **У адреса нет отдельного числового `id`.** Адрес определяется тремя значениями: `typeId`, `entityTypeId`, `entityId`. Получение, обновление и удаление используют их в пути. Создание передаёт их в теле запроса. 2. **`typeId` — тип адреса, `entityTypeId` — тип владельца.** Один владелец может иметь несколько адресов разных типов. Для реквизита `entityTypeId` равен `8`. 3. **Набор доступных типов зависит от страновой зоны портала.** Всего кодов двенадцать, но часть из них конкретный портал не вернёт никогда — состав определяет его страна. Выбирайте нужный тип из того, что реально пришло в ответе, а не по фиксированному номеру. Для юридического адреса это `typeId` `6`, запасной вариант при его отсутствии — `1`, фактический. 4. **Имена полей — camelCase везде.** Список и получение возвращают `address1`, `city`, `postalCode`. Схема `GET /v1/addresses/fields` отдаёт те же имена: `typeId`, `address1`, `postalCode`. В `filter` и в теле запроса передавайте их же. 5. **Адреса вызываются собственными маршрутами.** Составной ключ не укладывается в общую форму Entity API, поэтому операции идут по путям `/v1/addresses/...` — по одному вызову на адрес. В сводном [`POST /v1/batch`](/docs/batch) сущность `addresses` не участвует: такой вызов отклоняется до Битрикс24 с кодом `ENTITY_CUSTOM_ROUTES` в `data.errors` по идентификатору вызова. Если в пакете есть другие рабочие вызовы, ответ остаётся `200`, а `400` приходит только когда отклонены все. ## Связанные сущности | Сущность | Эндпоинт | Назначение | |----------|----------|-----------| | Реквизиты | `GET /v1/requisites` | Владелец адреса: `entityTypeId` равен `8`, а `entityId` — это `id` реквизита. | | Шаблоны реквизитов | `GET /v1/requisite-presets` | Шаблон набора полей реквизита-владельца. | | Банковские реквизиты | `GET /v1/bank-details` | Банковские счета того же реквизита. | ## Типичный сценарий 1. Найти реквизит компании: [`GET /v1/requisites?filter[entityTypeId]=4&filter[entityId]=15`](./requisites/list.md). 2. Создать адрес на него: [`POST /v1/addresses`](./addresses/create.md) с `typeId`, `entityTypeId: 8` и `entityId` реквизита. 3. Прочитать или обновить адрес по тройке: [`GET /v1/addresses/:typeId/:entityTypeId/:entityId`](./addresses/get.md). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | `offset` на больших выборках | рекомендуется `limit ≤ 500` при `offset ≥ 2500` | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Реквизиты компании для генерации документа](/docs/recipes/document-requisites) - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Справочник сущностей](/docs/entities-index) --- # Entity: Bank Details # Банковские реквизиты Банковские счета, привязанные к реквизиту: расчётный счёт, БИК, корреспондентский счёт, SWIFT, IBAN. Без банковского реквизита нельзя выставить счёт на оплату. Битрикс24 API: `crm.requisite.bankdetail.*` Скоуп: `crm` ## Операции - [Создать банковский реквизит](./bank-details/create.md) — `POST /v1/bank-details` - [Список банковских реквизитов](./bank-details/list.md) — `GET /v1/bank-details` - [Получить банковский реквизит](./bank-details/get.md) — `GET /v1/bank-details/:id` - [Обновить банковский реквизит](./bank-details/update.md) — `PATCH /v1/bank-details/:id` - [Удалить банковский реквизит](./bank-details/delete.md) — `DELETE /v1/bank-details/:id` - [Поиск банковских реквизитов](./bank-details/search.md) — `POST /v1/bank-details/search` - [Поля банковского реквизита](./bank-details/fields.md) — `GET /v1/bank-details/fields` ## Ключевые поля | Поле | Описание | |------|---------| | `entityId` | ID реквизита, которому принадлежит банковский реквизит (из `GET /v1/requisites`) | | `name` | Название банковского реквизита | | `rqBik` | БИК банка | | `rqAccNum` | Расчётный счёт | | `rqCorAccNum` | Корреспондентский счёт | | `rqSwift` / `rqIban` | Международные реквизиты счёта | Полный список полей — [`GET /v1/bank-details/fields`](./bank-details/fields.md). ## Что нужно знать перед работой 1. **Банковский реквизит привязан к реквизиту.** При создании обязательны `entityId` — идентификатор реквизита из `GET /v1/requisites` — и `name`. 2. **`entityTypeId` необязателен, но не возвращается на чтении.** Это поле-владелец. Укажите `8` — реквизит — при создании, чтобы привязать запись к реквизиту. В ответе `GET` его нет. 3. **Поля возвращаются в camelCase.** Российские реквизиты счёта — `rqBik`, `rqAccNum`, `rqCorAccNum`, `rqAccCurrency`, международные — `rqSwift`, `rqIban`. У записей без указанной страны `countryId` приходит как `0`. ## Связанные сущности | Сущность | Эндпоинт | Назначение | |----------|----------|-----------| | Реквизиты | `GET /v1/requisites` | Владелец банковского реквизита. `entityId` банковского реквизита — это `id` реквизита. | | Шаблоны реквизитов | `GET /v1/requisite-presets` | Шаблон набора полей реквизита-владельца. | | Связи реквизитов | `POST /v1/requisite-links` | Привязка реквизита и банковского реквизита к счёту или предложению. | ## Типичный сценарий 1. Найти реквизит компании: [`GET /v1/requisites?filter[entityTypeId]=4&filter[entityId]=15`](./requisites/list.md). 2. Создать банковский реквизит на него: [`POST /v1/bank-details`](./bank-details/create.md) с `entityTypeId: 8` и `entityId` реквизита. 3. Использовать `id` банковского реквизита при выставлении счёта или в [связи реквизитов](./requisite-links.md). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | `offset` на больших выборках | рекомендуется `limit ≤ 500` при `offset ≥ 2500` | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Реквизиты компании для генерации документа](/docs/recipes/document-requisites) - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Справочник сущностей](/docs/entities-index) --- # Entity: Basket Items # Позиции корзины Управление товарными позициями в заказах: создание, получение, обновление, удаление, поиск, агрегация. Позиция корзины — отдельная сущность, привязанная к заказу по полю `orderId`. У одного заказа может быть несколько позиций — по одной на каждый купленный товар. Битрикс24 API: `sale.basketitem.*` Скоуп: `sale` ## Операции - [Добавить позицию](./basket-items/create.md) — `POST /v1/basket-items` - [Список позиций](./basket-items/list.md) — `GET /v1/basket-items` - [Получить позицию](./basket-items/get.md) — `GET /v1/basket-items/:id` - [Обновить позицию](./basket-items/update.md) — `PATCH /v1/basket-items/:id` - [Удалить позицию](./basket-items/delete.md) — `DELETE /v1/basket-items/:id` - [Поиск позиций](./basket-items/search.md) — `POST /v1/basket-items/search` - [Поля позиции](./basket-items/fields.md) — `GET /v1/basket-items/fields` - [Агрегация позиций](./basket-items/aggregate.md) — `POST /v1/basket-items/aggregate` ## Ключевые поля | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор позиции (только чтение) | | `orderId` | number | Обязателен при создании. Идентификатор заказа. Источник: [`GET /v1/orders`](./orders/list.md) | | `productId` | number | Обязателен при создании. Идентификатор товара в каталоге. `0` — виртуальная позиция без привязки к каталогу. Источник: [`GET /v1/catalog-products`](/docs/entities/catalog-products) | | `name` | string | Название позиции. Для каталожного товара заполняется из карточки | | `price` | number | Цена за единицу | | `basePrice` | number | Базовая цена до скидки | | `discountPrice` | number | Размер скидки за единицу | | `quantity` | number | Обязательно при создании. Количество | | `currency` | string | Обязательна при создании. Валюта позиции. Список: [`GET /v1/currencies`](/docs/entities/currencies) | | `vatRate` | number | Ставка НДС в долях единицы (`0.20` = 20%) | | `vatIncluded` | boolean | Включён ли НДС в цену | | `weight` | number | Вес в граммах | | `dimensions` | string | Габариты в формате сериализации PHP | | `measureCode` | number | Код единицы измерения (`796` = шт, `163` = г, `006` = м и др.) | | `measureName` | string | Название единицы измерения | | `xmlId` | string | Внешний идентификатор позиции | Полный список полей — [`GET /v1/basket-items/fields`](./basket-items/fields.md). ## Что нужно знать перед работой 1. **Тело запроса плоское.** При создании и обновлении передавайте поля прямо в корне JSON: `{"orderId": 33, "productId": 119, ...}`. Обёртка `fields` не нужна. 2. **Обязательные поля при создании.** Для добавления позиции нужны `orderId`, `productId`, `currency` и `quantity`. Поле `orderId` ссылается на существующий заказ — сначала вызовите [`POST /v1/orders`](./orders/create.md). Поле `productId` привязывает позицию к товару каталога. Значение `productId: 0` создаёт виртуальную позицию без привязки к каталогу — для неё `name` и `price` задаются вручную. 3. **`vatRate` хранится в долях единицы.** Для НДС 20% передавайте `0.20`, не `20`. Для 10% — `0.10`. Для без НДС — `0` или не передавать. 4. **Цены передавайте согласованно.** `price` — итоговая цена за единицу с учётом скидки, `basePrice` — до скидки, `discountPrice` — размер скидки. Битрикс24 не пересчитывает эти поля между собой автоматически. Передайте `customPrice: true`, чтобы цена позиции не обновлялась при изменении цены товара в каталоге. ## Связанные сущности | Сущность | Эндпоинт | Назначение | |----------|----------|-----------| | Заказы | [`GET /v1/orders/:id`](./orders/get.md) | Родительский заказ — `orderId` указывается при создании позиции. | | Товары каталога | [`GET /v1/catalog-products`](/docs/entities/catalog-products) | Источник `productId` для привязки позиции к товару. | | Оплаты | [`GET /v1/payments?filter[orderId]=:id`](./payments.md) | Платежи по тому же заказу. | ## Типичный сценарий Добавление товаров в заказ из внешней системы: 1. Создать заказ: [`POST /v1/orders`](./orders/create.md) — получить `orderId`. 2. Найти товары в каталоге: [`GET /v1/catalog-products`](/docs/entities/catalog-products) — получить `productId` для каждой позиции. 3. Добавить позиции: цикл [`POST /v1/basket-items`](./basket-items/create.md) с `orderId`, `productId`, `quantity`, `price`, `currency`, `vatRate`. 4. Зарегистрировать оплату: [`POST /v1/payments`](./payments/create.md). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Автоматическая пагинация | включается при `limit > 50` | | `offset` на больших выборках | рекомендуется `limit ≤ 500` при `offset ≥ 2500` | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Частота запросов | общая для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Поля позиции](./basket-items/fields.md) - [Заказы](./orders.md) - [Оплаты](./payments.md) - [Товары каталога](/docs/entities/catalog-products) - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Справочник сущностей](/docs/entities-index) --- # Entity: Bizproc Activities # Действия бизнес-процессов Регистрация собственных действий для дизайнера бизнес-процессов Битрикс24. Действие — это внешний обработчик, который появляется в конструкторе бизнес-процессов и вызывается по ходу процесса: получает входные параметры, выполняет свою логику на стороне приложения и возвращает результат обратно в процесс. Читать, регистрировать, обновлять и удалять действия можно только ключом авторизации `vibe_app_…` — API-ключ `vibe_api_…` для этих методов не подходит. Управлять действиями может только администратор портала. Битрикс24 API: `bizproc.activity.*` Скоуп: `bizproc` ## Операции - [Зарегистрировать действие](./bizproc-activities/create.md) — `POST /v1/bizproc-activities` - [Список действий](./bizproc-activities/list.md) — `GET /v1/bizproc-activities` - [Обновить действие](./bizproc-activities/update.md) — `PATCH /v1/bizproc-activities/:code` - [Удалить действие](./bizproc-activities/delete.md) — `DELETE /v1/bizproc-activities/:code` - [Поля действия](./bizproc-activities/fields.md) — `GET /v1/bizproc-activities/fields` ## Ключевые поля | Поле | Тип | Описание | |------|-----|---------| | `code` | string | Уникальный код действия. Служит идентификатором в путях обновления и удаления | | `handler` | string | URL обработчика действия. Домен должен совпадать с доменом приложения | | `name` | string \| object | Название действия. Строка или локализованный объект | | `properties` | object | Входные параметры действия — поля, которые заполняются в дизайнере | | `returnProperties` | object | Выходные параметры действия — значения, которые действие возвращает в процесс | | `documentType` | array | Тип документа, к которому применимо действие — модуль, объект, тип | | `authUserId` | number | Пользователь, чей токен передаётся приложению при вызове. Список: `GET /v1/users` | Полный список полей — [Поля действия](./bizproc-activities/fields.md). Все они передаются при [регистрации](./bizproc-activities/create.md) и [обновлении](./bizproc-activities/update.md). Идентификатор действия — символьный код `code`, а не числовой `id`. ### Типы документов Значение `documentType` — массив из трёх строк `[модуль, объект, тип]`. | Сущность | `documentType` | |----------|----------------| | Лиды | `["crm", "CCrmDocumentLead", "LEAD"]` | | Контакты | `["crm", "CCrmDocumentContact", "CONTACT"]` | | Компании | `["crm", "CCrmDocumentCompany", "COMPANY"]` | | Сделки | `["crm", "CCrmDocumentDeal", "DEAL"]` | | Предложения | `["crm", "Bitrix\\Crm\\Integration\\BizProc\\Document\\Quote", "QUOTE"]` | | Счета | `["crm", "Bitrix\\Crm\\Integration\\BizProc\\Document\\SmartInvoice", "SMART_INVOICE"]` | | Смарт-процессы | `["crm", "Bitrix\\Crm\\Integration\\BizProc\\Document\\Dynamic", "DYNAMIC_"]` | | Процессы в ленте новостей | `["lists", "BizprocDocument", "iblock_"]` | | Списки в группах | `["lists", "Bitrix\\Lists\\BizprocDocumentLists", "iblock_"]` | | Документы Диска | `["disk", "Bitrix\\Disk\\BizProcDocument", "STORAGE_"]` | Набор шире, чем у [роботов](/docs/entities/bizproc-robots) — те применимы только к сущностям CRM. ## Что нужно знать перед работой 1. **Нужен ключ авторизации `vibe_app_…`, не API-ключ `vibe_api_…`.** Все пять операций требуют контекст приложения. API-ключ на любой из них вернёт `403 OAUTH_REQUIRED`. Отправляйте ключ авторизации вместе с заголовком `Authorization: Bearer <сессия>` — см. [Ключи и авторизация](/docs/keys-auth). Токен сессии выдаёт OAuth-авторизация, живёт 24 часа и не продлевается — после истечения вызовы возвращают `401 INVALID_SESSION` и нужна повторная авторизация. Как получить и передать токен — [Передача ключа](/docs/keys-auth#передача-ключа). 2. **Только администратор.** Управлять действиями может пользователь с правами администратора портала. У остальных Битрикс24 вернёт ошибку доступа. 3. **Идентификатор — символьный `code`.** В путях обновления и удаления указывается `code` (строка), а не числовой идентификатор. Получения одного действия по коду нет — операция `get` недоступна. 4. **Список возвращает только коды.** [`GET /v1/bizproc-activities`](./bizproc-activities/list.md) отдаёт массив строк — кодов зарегистрированных действий, без остальных полей. 5. **Домен обработчика.** URL в `handler` и `placementHandler` должен быть на домене приложения — Битрикс24 вызывает обработчик по этому адресу во время выполнения процесса. Обработчик на субдомене Black Hole доставляет платформа — [Доставка вызовов действий и роботов](/docs/infra/bizproc-callbacks). ## Связанные сущности | Сущность | Эндпоинт | Назначение | |----------|----------|-----------| | Роботы | [`/v1/bizproc-robots`](/docs/entities/bizproc-robots) | Роботы автоматизации. Появляются и в конструкторе роботов, и в дизайнере процессов — рекомендуемый Битрикс24 формат вместо действий | | Журнал процесса | [`POST /v1/workflows/activity-log`](/docs/automation/workflows/activity-log) | Запись сообщения обработчика в журнал бизнес-процесса | ## Типичный сценарий 1. Зарегистрируйте действие через [`POST /v1/bizproc-activities`](./bizproc-activities/create.md): задайте `code`, `name`, `handler` на домене приложения и входные параметры `properties`. 2. Действие появляется в дизайнере бизнес-процессов. Когда процесс доходит до него, Битрикс24 вызывает `handler` с заполненными параметрами. 3. При `useSubscription: "Y"` процесс ждёт ответа приложения, при `"N"` — продолжается сразу. 4. Проверить список зарегистрированных действий — [`GET /v1/bizproc-activities`](./bizproc-activities/list.md). Ненужное действие удалите по коду через [`DELETE /v1/bizproc-activities/:code`](./bizproc-activities/delete.md). ## Лимиты | Лимит | Значение | |-------|----------| | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Частота запросов | общий лимит API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Роботы](/docs/entities/bizproc-robots) - [Журнал бизнес-процесса](/docs/automation/workflows/activity-log) - [Доставка вызовов действий и роботов](/docs/infra/bizproc-callbacks) - [Ключи и авторизация](/docs/keys-auth) - [Справочник сущностей](/docs/entities-index) --- # Entity: Bizproc Robots # Роботы бизнес-процессов Регистрация собственных роботов для автоматизации Битрикс24. Робот — это внешний обработчик, который появляется и в конструкторе роботов, и в дизайнере бизнес-процессов. Робот вызывается по правилу автоматизации: получает входные параметры, выполняет логику на стороне приложения и возвращает результат. Битрикс24 рекомендует роботов как формат для автоматизации вместо действий. Читать, регистрировать, обновлять и удалять роботов можно только ключом авторизации `vibe_app_…` — API-ключ `vibe_api_…` для этих методов не подходит. Управлять роботами может только администратор портала. Битрикс24 API: `bizproc.robot.*` Скоуп: `bizproc` ## Операции - [Зарегистрировать робота](./bizproc-robots/create.md) — `POST /v1/bizproc-robots` - [Список роботов](./bizproc-robots/list.md) — `GET /v1/bizproc-robots` - [Обновить робота](./bizproc-robots/update.md) — `PATCH /v1/bizproc-robots/:code` - [Удалить робота](./bizproc-robots/delete.md) — `DELETE /v1/bizproc-robots/:code` - [Поля робота](./bizproc-robots/fields.md) — `GET /v1/bizproc-robots/fields` ## Ключевые поля | Поле | Тип | Описание | |------|-----|---------| | `code` | string | Уникальный код робота. Служит идентификатором в путях обновления и удаления | | `handler` | string | URL обработчика робота. Домен должен совпадать с доменом приложения | | `name` | string \| object | Название робота. Строка или локализованный объект | | `properties` | object | Входные параметры робота — поля, которые заполняются в правиле автоматизации | | `returnProperties` | object | Выходные параметры робота — значения, которые робот возвращает | | `documentType` | array | Тип документа, к которому применим робот — модуль, объект, тип. См. таблицу ниже | | `authUserId` | number | Пользователь, чей токен передаётся приложению при вызове. Список: `GET /v1/users` | Полный список полей — [Поля робота](./bizproc-robots/fields.md). Все они передаются при [регистрации](./bizproc-robots/create.md) и [обновлении](./bizproc-robots/update.md). Идентификатор робота — символьный код `code`, а не числовой `id`. ### Типы документов Значение `documentType` — массив из трёх строк `[модуль, объект, тип]`. Робот применим только к сущностям CRM — набор уже, чем у [действий](/docs/entities/bizproc-activities) и [шаблонов](/docs/entities/bizproc-templates). | Сущность | `documentType` | |----------|----------------| | Лиды | `["crm", "CCrmDocumentLead", "LEAD"]` | | Сделки | `["crm", "CCrmDocumentDeal", "DEAL"]` | | Предложения | `["crm", "Bitrix\\Crm\\Integration\\BizProc\\Document\\Quote", "QUOTE"]` | | Счета | `["crm", "Bitrix\\Crm\\Integration\\BizProc\\Document\\SmartInvoice", "SMART_INVOICE"]` | | Смарт-процессы | `["crm", "Bitrix\\Crm\\Integration\\BizProc\\Document\\Dynamic", "DYNAMIC_XXX"]` | ## Что нужно знать перед работой 1. **Нужен ключ авторизации `vibe_app_…`, не API-ключ `vibe_api_…`.** Все пять операций требуют контекст приложения. API-ключ на любой из них вернёт `403 OAUTH_REQUIRED`. Отправляйте ключ авторизации вместе с заголовком `Authorization: Bearer <сессия>` — см. [Ключи и авторизация](/docs/keys-auth). Токен сессии выдаёт OAuth-авторизация, живёт 24 часа и не продлевается — после истечения вызовы возвращают `401 INVALID_SESSION` и нужна повторная авторизация. Как получить и передать токен — [Передача ключа](/docs/keys-auth#передача-ключа). 2. **Только администратор.** Управлять роботами может пользователь с правами администратора портала. У остальных Битрикс24 вернёт ошибку доступа. 3. **Идентификатор — символьный `code`.** В путях обновления и удаления указывается `code` (строка), а не числовой идентификатор. Получения одного робота по коду нет — операция `get` недоступна. 4. **Список возвращает только коды.** [`GET /v1/bizproc-robots`](./bizproc-robots/list.md) отдаёт массив строк — кодов зарегистрированных роботов, без остальных полей. 5. **Домен обработчика.** URL в `handler` и `placementHandler` должен быть на домене приложения — Битрикс24 вызывает обработчик по этому адресу во время автоматизации. Обработчик на субдомене Black Hole доставляет платформа — [Доставка вызовов действий и роботов](/docs/infra/bizproc-callbacks). ## Связанные сущности | Сущность | Эндпоинт | Назначение | |----------|----------|-----------| | Действия | [`/v1/bizproc-activities`](/docs/entities/bizproc-activities) | Действия для дизайнера бизнес-процессов. Появляются только в дизайнере процессов, без конструктора роботов | | Журнал процесса | [`POST /v1/workflows/activity-log`](/docs/automation/workflows/activity-log) | Запись сообщения обработчика в журнал бизнес-процесса | ## Типичный сценарий 1. Зарегистрируйте робота через [`POST /v1/bizproc-robots`](./bizproc-robots/create.md): задайте `code`, `name`, `handler` на домене приложения, тип документа `documentType` и входные параметры `properties`. 2. Робот появляется в конструкторе роботов и в дизайнере бизнес-процессов. По правилу автоматизации для документа заданного типа Битрикс24 вызывает `handler` с заполненными параметрами. 3. При `useSubscription: "Y"` автоматизация ждёт ответа приложения, при `"N"` — продолжается сразу. 4. Проверить список зарегистрированных роботов — [`GET /v1/bizproc-robots`](./bizproc-robots/list.md). Ненужного робота удалите по коду через [`DELETE /v1/bizproc-robots/:code`](./bizproc-robots/delete.md). ## Лимиты | Лимит | Значение | |-------|----------| | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Частота запросов | общий лимит API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Действия бизнес-процессов](/docs/entities/bizproc-activities) - [Журнал бизнес-процесса](/docs/automation/workflows/activity-log) - [Доставка вызовов действий и роботов](/docs/infra/bizproc-callbacks) - [Ключи и авторизация](/docs/keys-auth) - [Справочник сущностей](/docs/entities-index) --- # Entity: Bizproc Templates # Шаблоны бизнес-процессов Шаблон бизнес-процесса — заготовка процесса, привязанная к типу документа: сделке, лиду, элементу списка, документу Диска. По шаблону Битрикс24 запускает процесс, когда документ создаётся или меняется. Приложение загружает готовый шаблон файлом `.bpt`, меняет его настройки и удаляет. Битрикс24 API: `bizproc.workflow.template.*` Скоуп: `bizproc` ## Операции - [Загрузить шаблон](./bizproc-templates/create.md) — `POST /v1/bizproc-templates` - [Список шаблонов](./bizproc-templates/list.md) — `GET /v1/bizproc-templates` - [Обновить шаблон](./bizproc-templates/update.md) — `PATCH /v1/bizproc-templates/:id` - [Удалить шаблон](./bizproc-templates/delete.md) — `DELETE /v1/bizproc-templates/:id` - [Поиск шаблонов](./bizproc-templates/search.md) — `POST /v1/bizproc-templates/search` - [Поля шаблона](./bizproc-templates/fields.md) — `GET /v1/bizproc-templates/fields` ## Ключевые поля | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор шаблона. Указывается в путях обновления и удаления | | `name` | string | Название шаблона | | `documentType` | array | Тип документа из трёх элементов — модуль, объект, тип. Задаётся при загрузке, допустимые значения — [Загрузить шаблон](./bizproc-templates/create.md) | | `templateData` | array | Файл шаблона — имя файла и содержимое в base64. Передаётся при загрузке и обновлении, в ответах не возвращается | | `autoExecute` | number | Условие автозапуска: `0` — без автозапуска, `1` — при создании документа, `2` — при изменении, `3` — при создании и изменении | | `isModified` | boolean | Правился ли шаблон после загрузки файла | | `userId` | number | Автор последнего изменения. Список: [`GET /v1/users`](/docs/entities/users) | ## Что нужно знать перед работой 1. **Нужен ключ авторизации `vibe_app_…`, не API-ключ `vibe_api_…`.** Все шесть операций требуют контекст приложения. API-ключ вернёт `403 OAUTH_REQUIRED`. Ключ авторизации отправляется вместе с заголовком `Authorization: Bearer` — см. [Ключи и авторизация](/docs/keys-auth). Токен сессии выдаёт OAuth-авторизация, живёт 24 часа и не продлевается — после истечения вызовы возвращают `401 INVALID_SESSION` и нужна повторная авторизация. Как получить и передать токен — [Передача ключа](/docs/keys-auth#передача-ключа). 2. **Только администратор.** Управлять шаблонами может пользователь с правами администратора портала. У остальных запрос завершается ошибкой доступа. 3. **Приложение распоряжается только своими шаблонами.** Обновить и удалить можно шаблон, загруженный тем же приложением. Шаблоны из конструктора Битрикс24 и других приложений видны в списке, но на изменение возвращают `422`. 4. **Шаблон загружается файлом.** Процесс настраивается в конструкторе бизнес-процессов Битрикс24 и выгружается в файл `.bpt`, содержимое которого передаётся в `templateData` в base64. Собрать шаблон из полей через API нельзя. 5. **Без `select` список возвращает все объявленные поля, включая `id`.** Параметр нужен, только чтобы сузить ответ до конкретных полей. 6. **Получения одного шаблона нет.** Операция `get` недоступна — читайте запись через список с фильтром по `id`. ## Связанные сущности | Сущность | Эндпоинт | Назначение | |----------|----------|-----------| | Действия бизнес-процессов | [`/v1/bizproc-activities`](/docs/entities/bizproc-activities) | Собственные действия приложения в дизайнере процессов | | Роботы | [`/v1/bizproc-robots`](/docs/entities/bizproc-robots) | Роботы автоматизации в конструкторе правил | | Бизнес-процессы | [`/v1/workflows`](/docs/automation/workflows) | Запуск процесса по шаблону, список запущенных, завершение | | Смарт-процессы | [`/v1/smart-processes`](/docs/entities/smart-processes) | Источник `entityTypeId` для типа документа смарт-процесса | ## Типичный сценарий 1. Настройте процесс в конструкторе бизнес-процессов Битрикс24 и выгрузите его в файл `.bpt`. 2. Загрузите файл через [`POST /v1/bizproc-templates`](./bizproc-templates/create.md), указав тип документа и условие автозапуска. В ответе придёт `id`. 3. Проверьте запись через [`GET /v1/bizproc-templates`](./bizproc-templates/list.md) с фильтром по `id` и нужным `select`. 4. Меняйте название, описание, условие автозапуска или сам файл через [`PATCH /v1/bizproc-templates/:id`](./bizproc-templates/update.md). 5. Ненужный шаблон удалите через [`DELETE /v1/bizproc-templates/:id`](./bizproc-templates/delete.md). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 | | Автоматическая пагинация | включается при `limit` больше 50 | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Частота запросов | общий лимит API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Действия бизнес-процессов](/docs/entities/bizproc-activities) - [Роботы](/docs/entities/bizproc-robots) - [Бизнес-процессы](/docs/automation/workflows) - [Ключи и авторизация](/docs/keys-auth) - [Справочник сущностей](/docs/entities-index) --- # Entity: Bookings # Бронирования Бронирования резервируют ресурсы портала Битрикс24 на заданный интервал времени: создание, получение по идентификатору, список и поиск по диапазону дат, обновление и удаление. Каждое бронирование привязано к одному или нескольким ресурсам и хранит период от и до. Битрикс24 API: `booking.v1.booking.*` Скоуп: `booking` ## Операции - [Создать бронирование](./bookings/create.md) — `POST /v1/bookings` - [Список бронирований](./bookings/list.md) — `GET /v1/bookings` - [Получить бронирование](./bookings/get.md) — `GET /v1/bookings/:id` - [Обновить бронирование](./bookings/update.md) — `PATCH /v1/bookings/:id` - [Удалить бронирование](./bookings/delete.md) — `DELETE /v1/bookings/:id` - [Поиск бронирований](./bookings/search.md) — `POST /v1/bookings/search` - [Поля бронирования](./bookings/fields.md) — `GET /v1/bookings/fields` ## Поля ### Изменяемые поля Принимаются при [создании](./bookings/create.md) и [обновлении](./bookings/update.md). | Поле | Тип | Описание | |------|-----|---------| | `resourceIds` | number[] | Идентификаторы ресурсов, которые резервирует бронирование. Обязательно при создании, массив не может быть пустым. Получить список ресурсов через API Вайбкод нельзя — укажите известные идентификаторы | | `datePeriod` | object | Период бронирования. Обязательно при создании. Структура: `from` и `to`, у каждого `timestamp` (Unix-секунды) и `timezone` (часовой пояс в формате IANA, например `Europe/Moscow`) | | `name` | string | Название бронирования. Необязательно — может быть `null` | | `description` | string | Описание бронирования. Необязательно — может быть `null` | ### Только для чтения Приходит в ответе, не принимается при создании и обновлении. | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор бронирования | ## Что нужно знать перед работой 1. **Для создания нужны два поля:** `resourceIds` (непустой массив) и `datePeriod`. Без любого из них ответ — `422 BITRIX_ERROR` с перечнем недостающих полей. `name` и `description` необязательны. 2. **`datePeriod` — вложенный объект, а не строка.** Время задаётся как `{"from": {"timestamp": 1780132384, "timezone": "Europe/Moscow"}, "to": {"timestamp": 1780135984, "timezone": "Europe/Moscow"}}`. `timestamp` — Unix-секунды, `timezone` — часовой пояс в формате IANA. 3. **Список и поиск требуют интервал дат.** `GET /v1/bookings` и `POST /v1/bookings/search` принимают обязательные `dateFrom` и `dateTo` (формат ISO 8601 или Unix-секунды). Без них — `400 MISSING_REQUIRED_PARAMS`. Бронирования вне интервала в ответ не попадают. 4. **Имена полей остаются как есть.** Имена полей в ответе совпадают с именами в запросе (`resourceIds`, `datePeriod`) — дополнительного преобразования регистра нет. 5. **Набор полей фиксирован.** Все доступные поля перечислены в разделе «Поля» выше. ## Типичный сценарий 1. Создать бронирование на нужный период: [`POST /v1/bookings`](./bookings/create.md). 2. Получить бронирования за интервал: [`GET /v1/bookings?dateFrom=...&dateTo=...`](./bookings/list.md). 3. Изменить период или название: [`PATCH /v1/bookings/:id`](./bookings/update.md). 4. Снять бронь: [`DELETE /v1/bookings/:id`](./bookings/delete.md). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Обязательный интервал для списка и поиска | `dateFrom` + `dateTo` | | Размер страницы по умолчанию | 50 (`limit`) | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Справочник сущностей](/docs/entities-index) --- # Entity: Calendar Events # События календаря Управление событиями календарей Битрикс24: личных, групповых и календарей компании. Поддерживаются создание, получение, обновление и удаление событий, а также получение схемы полей. Битрикс24 API: `calendar.event.*` Скоуп: `calendar` ## Операции - [Создать событие](./calendar-events/create.md) — `POST /v1/calendar-events` - [Список событий](./calendar-events/list.md) — `GET /v1/calendar-events` - [Получить событие](./calendar-events/get.md) — `GET /v1/calendar-events/:id` - [Обновить событие](./calendar-events/update.md) — `PATCH /v1/calendar-events/:id` - [Удалить событие](./calendar-events/delete.md) — `DELETE /v1/calendar-events/:id` - [Поиск событий](./calendar-events/search.md) — `POST /v1/calendar-events/search` - [Поля события](./calendar-events/fields.md) — `GET /v1/calendar-events/fields` ## Ключевые поля | Поле | Описание | |------|---------| | `type` | Тип календаря: `user`, `group`, `company_calendar` | | `ownerId` | ID владельца календаря. Для `type=user` — ID сотрудника из `GET /v1/users`, для `type=group` — ID рабочей группы | | `name` | Название события | | `from` / `to` | Начало и конец события в ISO 8601 | | `timezoneFrom` / `timezoneTo` | Часовой пояс события в формате IANA (`Europe/Moscow`). Необязателен — без него используется часовой пояс сотрудника, к которому привязан API-ключ | | `skipTime` | Событие на весь день — при `true` длительность фиксируется в 24 часа | | `sectionId` | ID секции календаря | | `attendees` | Массив ID приглашённых сотрудников для записи (`POST`/`PATCH`). На чтение участники приходят в полях `attendeeList`, `attendeesCodes` | | `rrule` | Расписание повторения регулярного события — объект с полями периодичности и границ серии | Полный список полей — [`GET /v1/calendar-events/fields`](./calendar-events/fields.md). ## Что нужно знать перед работой 1. **Календарь определяется парой `type` + `ownerId`.** Эта пара обязательна и для списка событий, и для создания. События всегда привязаны к конкретному календарю, а не к порталу в целом. 2. **Для создания события нужны 5 полей:** `type`, `ownerId`, `name`, `from`, `to`. Если событие на весь день — передайте `skipTime: true`; время в `from`/`to` будет проигнорировано, длительность события зафиксируется в 24 часа. 3. **`from` и `to` принимают ISO 8601 в любом виде:** с offset (`"2026-06-01T10:00:00+03:00"`), в UTC (`"2026-06-01T07:00:00Z"`) или без зоны (`"2026-06-01T10:00:00"`). В ответе возвращается ISO 8601 с offset; instant и wall-clock соответствуют тому, что отображается в календаре пользователя. 4. **Часовой пояс события задаётся через `timezoneFrom` / `timezoneTo`.** Передайте IANA-имя (`Europe/Moscow`, `Asia/Almaty`, `UTC`). Если параметры опущены, событие создаётся в часовом поясе сотрудника-владельца API-ключа. 5. **`PATCH` — частичный.** При обновлении одного поля Вайбкод дочитывает текущее состояние события и автоматически подставляет `type`, `ownerId`, `name`, которые Битрикс24 требует при каждом обновлении. 6. **Отключение источника — на стороне приложения, не платформы.** API без состояния: чтобы перестать получать события календаря, приложение не вызывает `GET /v1/calendar-events`. Платформа не хранит признак «источник включён» и не возобновляет загрузку по сохранённым настройкам приложения. Ответы `calendar-events` не кэшируются — кэш на стороне Вайбкод включается только для `GET /v1/users` и `GET /v1/statuses`, см. [Кэширование](/docs/optimization). Устаревшие данные после отключения источника берутся из состояния самого приложения, а не от платформы. ## Типичный сценарий 1. Найти владельца календаря: [`GET /v1/users`](/docs/entities/users) для личного календаря или ID рабочей группы для группового. 2. Получить ближайшие события: [`GET /v1/calendar-events?type=user&ownerId=1`](./calendar-events/list.md). 3. Создать новое или обновить существующее: [`POST /v1/calendar-events`](./calendar-events/create.md) / [`PATCH /v1/calendar-events/:id`](./calendar-events/update.md). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | `offset` на больших выборках | рекомендуется `limit ≤ 500` при `offset ≥ 2500` | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Entity API](/docs/entity-api) - [Batch](/docs/batch) - [Справочник сущностей](/docs/entities-index) --- # Entity: Calendar Sections # Секции календаря Управление секциями календаря Битрикс24: личными, групповыми и календарями переговорных. Секция — это сам календарь, в котором живут события. У одного сотрудника может быть несколько секций, например «Работа» и «Личное», у группы — один или несколько групповых календарей. Битрикс24 API: `calendar.section.*` Скоуп: `calendar` ## Операции - [Список секций](./calendar-sections/list.md) — `GET /v1/calendar-sections` - [Создать секцию](./calendar-sections/create.md) — `POST /v1/calendar-sections` - [Обновить секцию](./calendar-sections/update.md) — `PATCH /v1/calendar-sections/:id` - [Удалить секцию](./calendar-sections/delete.md) — `DELETE /v1/calendar-sections/:id` - [Пакет операций](./calendar-sections/batch.md) — `POST /v1/calendar-sections/batch` ## Что НЕ поддерживается | Операция | Причина | |---|---| | `GET /v1/calendar-sections/:id` | Получить секцию по одному `id` нельзя — доступен только список по паре `type` + `ownerId`. Запросите `GET /v1/calendar-sections?type=<...>&ownerId=<...>` и отфильтруйте результат по полю `id` на стороне клиента | | `GET /v1/calendar-sections/fields` | Описание полей через API недоступно — список полей зафиксирован и приведён в [Списке секций](./calendar-sections/list.md) | | `POST /v1/calendar-sections/search` | Поиск по секциям не поддерживается | | `POST /v1/calendar-sections/aggregate` | Агрегация по секциям не поддерживается | Если попытаться вызвать запрещённую операцию, например `GET /v1/calendar-sections/42`, API Вайбкод вернёт `404`. ## Ключевые поля | Поле | Описание | |------|---------| | `id` | Идентификатор секции | | `type` | Тип календаря: `user`, `group`, `company_calendar`, `location` | | `ownerId` | Идентификатор владельца календаря. Для `type=user` — `id` сотрудника из `GET /v1/users`, для `type=group` — `id` рабочей группы, для `type=location` — `0` | | `name` | Название секции | | `color` | Цвет секции в формате `#RRGGBB` | | `textColor` | Цвет текста в формате `#RRGGBB` | | `export` | Параметры экспорта в формате iCal: `{ "ALLOW": boolean, "SET": "all" \| "3_9" \| "6_12" }` — поле сохраняет регистр Битрикс24 и проходит без преобразований | | `access` | Карта прав доступа к секции. Возвращается только на чтение | | `perm` | Карта разрешений текущего сотрудника. Возвращается только на чтение | | `isCollab` | Принадлежность к коллабе. Возвращается только на чтение | Полный список полей с типами — в ответе [`GET /v1/calendar-sections`](./calendar-sections/list.md). ## Что нужно знать перед работой 1. **Секция определяется парой `type` + `ownerId`.** Эта пара обязательна и для списка, и для удаления. Для создания и обновления она тоже обязательна. 2. **Поле `export` передаётся объектом.** В отличие от остальных полей, ключи внутри `export` — `ALLOW` и `SET` — идут в верхнем регистре и сохраняются без преобразований на запись и чтение. 3. **`PATCH` требует `type` + `ownerId` в теле запроса.** Секцию нельзя найти по одному `id` — поэтому при обновлении нужно явно указать, какой именно секции принадлежит этот `id`. Один и тот же числовой `id` может встречаться в разных контекстах — например, у сотрудника `1` и сотрудника `2`. 4. **`DELETE` требует `type` + `ownerId` в строке запроса или теле.** Если переданы оба — приоритет у строки запроса. Если параметры опущены — API Вайбкод возвращает `400 MISSING_REQUIRED_PARAMS` ещё до обращения к Битрикс24. 5. **Удаление секции необратимо.** Запрос выполняется без подтверждения и без возможности отмены через API. Если в секции остались нужные события, заранее перенесите их в другую секцию через [`PATCH /v1/calendar-events/:id`](/docs/entities/calendar-events/update) с новым `sectionId`. ## Типичный сценарий 1. Получить список секций сотрудника: [`GET /v1/calendar-sections?type=user&ownerId=1`](./calendar-sections/list.md). 2. Если нужна новая отдельная секция, например «Командные встречи», — создать её: [`POST /v1/calendar-sections`](./calendar-sections/create.md). 3. Переименовать или сменить цвет: [`PATCH /v1/calendar-sections/:id`](./calendar-sections/update.md). 4. Если секция больше не нужна, заранее перенести нужные события в другую секцию, как описано в пункте 5 «Что нужно знать перед работой», затем удалить: [`DELETE /v1/calendar-sections/:id`](./calendar-sections/delete.md). После создания секции её `id` можно передавать в [`POST /v1/calendar-events`](./calendar-events/create.md) через поле `sectionId`, чтобы все события писались в одну секцию. ## Лимиты | Лимит | Значение | |-------|----------| | Максимум секций на запрос `limit` | 5000 | | Авто-пагинация | включается при `limit > 50` | | Пакет операций одной сущности | до 500 элементов в [`POST /v1/calendar-sections/batch`](./calendar-sections/batch.md) | | Универсальный batch | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [События календаря](/docs/entities/calendar-events) - [Entity API](/docs/entity-api) - [Batch](/docs/batch) - [Справочник сущностей](/docs/entities-index) --- # Entity: Catalog Prices # Цены каталога Цены товаров: список, получение, создание, изменение и удаление. У одного товара может быть несколько цен — по одной на каждый тип цены (`catalogGroupId`). Цены привязаны к товарам из [каталога](/docs/entities/catalog-products). Битрикс24 API: `catalog.price.*` Скоуп: `catalog` ## Операции - [Создать цену](./catalog-prices/create.md) — `POST /v1/catalog-prices` - [Список цен](./catalog-prices/list.md) — `GET /v1/catalog-prices` - [Получить цену](./catalog-prices/get.md) — `GET /v1/catalog-prices/:id` - [Обновить цену](./catalog-prices/update.md) — `PATCH /v1/catalog-prices/:id` - [Удалить цену](./catalog-prices/delete.md) — `DELETE /v1/catalog-prices/:id` - [Поиск цен](./catalog-prices/search.md) — `POST /v1/catalog-prices/search` - [Поля цены](./catalog-prices/fields.md) — `GET /v1/catalog-prices/fields` ## Ключевые поля | Поле | Описание | |------|---------| | `productId` | ID товара, к которому относится цена. Список: [`GET /v1/catalog-products?filter[iblockId]=21`](/docs/entities/catalog-products) | | `catalogGroupId` | Тип цены. Базовая цена — `1`. Какие типы заведены на портале, видно по значениям `catalogGroupId` в [списке цен](./catalog-prices/list.md) | | `price` | Значение цены | | `currency` | Валюта цены, например `RUB`. Список: [`GET /v1/currencies`](/docs/entities/currencies) | | `quantityFrom` | Нижняя граница количественного диапазона, если цена зависит от количества | | `quantityTo` | Верхняя граница количественного диапазона | ## Что нужно знать перед работой 1. **Минимум для создания — четыре поля.** `productId`, `catalogGroupId`, `price`, `currency` обязательны; без любого из них запрос вернёт ошибку. `quantityFrom` и `quantityTo` опциональны. 2. **Тип цены задаётся числом `catalogGroupId`.** Базовая цена соответствует `1`. Отдельного эндпоинта со списком типов цен нет — доступные на портале значения видно по полю `catalogGroupId` в [списке цен](./catalog-prices/list.md). Один товар может иметь по одной цене на каждый тип. 3. **Цена привязана к товару.** Перед созданием получите `productId` из [`GET /v1/catalog-products`](/docs/entities/catalog-products) (товарам нужен фильтр `filter[iblockId]`, а `iblockId` — из [`GET /v1/catalogs`](/docs/entities/catalogs)). 4. **В ответе больше полей, чем доступно для фильтра.** Кроме перечисленных, в ответе приходят `extraId`, `priceScale` (цена в базовой валюте) и `timestampX` (дата изменения). Фильтрация и сортировка работают только по полям из таблицы выше. ## Типичный сценарий 1. Найти каталог и его `iblockId`: [`GET /v1/catalogs`](/docs/entities/catalogs). 2. Найти товар: [`GET /v1/catalog-products?filter[iblockId]=21`](/docs/entities/catalog-products) — взять `id` товара. 3. Посмотреть текущие цены товара: [`GET /v1/catalog-prices?filter[productId]=101`](./catalog-prices/list.md). 4. Создать или изменить цену: [`POST /v1/catalog-prices`](./catalog-prices/create.md) / [`PATCH /v1/catalog-prices/:id`](./catalog-prices/update.md). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Товары каталога](/docs/entities/catalog-products) - [Каталоги](/docs/entities/catalogs) - [Разделы каталога](/docs/entities/catalog-sections) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entities-index) --- # Entity: Catalog Product Properties # Свойства товаров каталога Схема свойств торгового каталога: список, получение, создание, изменение и удаление. Свойство описывает определение пользовательского поля каталога — `id`, название и тип. Это спутник [Товаров каталога](/docs/entities/catalog-products): свойства-списки товара приходят там в полях вида `propertyNNN`, где `NNN` — это `id` свойства. Эта сущность превращает `id` в название и тип — например, свойство `154` → `{ "name": "Наименование по РУ", "propertyType": "S" }`. Битрикс24 API: `catalog.productProperty.*` Скоуп: `catalog` ## Операции - [Создать свойство](./catalog-product-properties/create.md) — `POST /v1/catalog-product-properties` - [Список свойств](./catalog-product-properties/list.md) — `GET /v1/catalog-product-properties` - [Получить свойство](./catalog-product-properties/get.md) — `GET /v1/catalog-product-properties/:id` - [Обновить свойство](./catalog-product-properties/update.md) — `PATCH /v1/catalog-product-properties/:id` - [Удалить свойство](./catalog-product-properties/delete.md) — `DELETE /v1/catalog-product-properties/:id` - [Поиск свойств](./catalog-product-properties/search.md) — `POST /v1/catalog-product-properties/search` - [Поля свойства](./catalog-product-properties/fields.md) — `GET /v1/catalog-product-properties/fields` ## Ключевые поля | Поле | Описание | |------|---------| | `id` | ID свойства. Это `NNN` в ключе `propertyNNN` на товаре каталога | | `iblockId` | ID каталога. Список: [`GET /v1/catalogs`](/docs/entities/catalogs) | | `name` | Название свойства для отображения | | `propertyType` | Базовый тип. Значения: `N` число, `S` строка, `L` список, `F` файл, `E` привязка к элементу, `G` привязка к разделу | | `active` | Активно ли свойство | | `sort` | Индекс сортировки | ## Что нужно знать перед работой 1. **Эта сущность — схема свойств каталога.** Каждая запись описывает определение поля: `id`, `name` и `propertyType`. Свойства-списки товара приходят в [Товарах каталога](/docs/entities/catalog-products) в полях вида `propertyNNN`, где `NNN` совпадает с `id` свойства. По `id` строится сопоставление `id` → название и тип, а значения `propertyNNN` получают подпись. 2. **Фильтр по каталогу ограничивает выдачу одним каталогом.** В `GET /v1/catalog-product-properties` и `POST /v1/catalog-product-properties/search` поле `filter[iblockId]` ограничивает выборку свойствами одного каталога. Значение `iblockId` берётся из [`GET /v1/catalogs`](/docs/entities/catalogs). 3. **Код типа задаёт поведение свойства.** `propertyType` принимает значения `N` число, `S` строка, `L` список, `F` файл, `E` привязка к элементу, `G` привязка к разделу. 4. **Минимум для создания — три поля.** `iblockId`, `name` и `propertyType` обязательны. Остальные поля опциональны и принимают значения по умолчанию. 5. **Тип задаётся только при создании.** Поля `iblockId`, `propertyType` и `userType` доступны для записи только при создании. `PATCH` с любым из них отклоняется с `400 READONLY_FIELD`. 6. **Булевы флаги — значения `true`/`false`.** `active`, `multiple`, `withDescription`, `searchable`, `filtrable`, `isRequired` приходят и принимаются как булевы. Пустые строки приходят как `null`. ## Типичный сценарий 1. Найти каталог и его `iblockId`: [`GET /v1/catalogs`](/docs/entities/catalogs). 2. Прочитать схему свойств каталога: [`GET /v1/catalog-product-properties?filter[iblockId]=19`](./catalog-product-properties/list.md). 3. Построить сопоставление `id` → `name` по полученным записям. 4. Прочитать товар и сопоставить его поля `propertyNNN`: [`GET /v1/catalog-products/:id`](/docs/entities/catalog-products). 5. Для свойства-списка (`propertyType: "L"`) забрать все возможные варианты: [`GET /v1/catalog-product-property-enums?filter[propertyId]=166&limit=1000`](/docs/entities/catalog-product-property-enums/list). Шаг 5 нужен, когда требуется весь набор вариантов — выпадашка, фильтр, экспорт. Для одного товара текст выбранного варианта уже приходит в `propertyNNN.valueEnum`. Форму значения у товара задаёт `listType` свойства: `L` — объект `{ value, valueEnum, valueId }`, `C` — голый скаляр `"Y"`/`"N"` (состояние галочки, а не id варианта). При `multiple: true` та же форма приходит массивом. ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Значения списочных свойств](/docs/entities/catalog-product-property-enums) - [Товары каталога](/docs/entities/catalog-products) - [Каталоги](/docs/entities/catalogs) - [API сущностей](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entities-index) --- # Entity: Catalog Product Property Enums # Значения списочных свойств каталога Справочник вариантов свойства-списка торгового каталога: чтение списка, получение одного элемента, поиск и справочник полей. Каждая запись — один вариант выпадающего списка: `id` элемента и его читаемый текст `value`. Это спутник [Свойств товаров каталога](/docs/entities/catalog-product-properties): свойство с `propertyType: "L"` описывает поле, а эта сущность перечисляет варианты, которые в нём можно выбрать. Отсюда берётся то, чего не даёт ни один эндпоинт товара: **все возможные** значения списочного свойства, а не только выбранное у конкретного товара. Битрикс24 API: `catalog.productPropertyEnum.*` Скоуп: `catalog` ## Операции - [Список значений](./catalog-product-property-enums/list.md) — `GET /v1/catalog-product-property-enums` - [Получить значение](./catalog-product-property-enums/get.md) — `GET /v1/catalog-product-property-enums/:id` - [Поиск значений](./catalog-product-property-enums/search.md) — `POST /v1/catalog-product-property-enums/search` - [Поля значения](./catalog-product-property-enums/fields.md) — `GET /v1/catalog-product-property-enums/fields` Сущность только для чтения: `POST`, `PATCH`, `DELETE` и `POST /aggregate` не зарегистрированы и отвечают `404`. ## Ключевые поля | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID элемента перечисления. Именно он приходит у товара каталога в `propertyNNN.value` | | `propertyId` | number | ID свойства-владельца. Обязателен в фильтре | | `value` | string | Читаемый текст варианта — тот же, что приходит у товара в `propertyNNN.valueEnum` | | `def` | boolean | Является ли вариант значением свойства по умолчанию | | `sort` | number | Индекс сортировки внутри свойства | | `xmlId` | string | Внешний код. Приходит `null`, если не задан | ## Что нужно знать перед работой 1. **`filter[propertyId]` обязателен.** Справочник читается по одному свойству за раз. Запрос без этого фильтра отклоняется с `400 MISSING_REQUIRED_FILTER` ещё до обращения к Битрикс24 — на обеих доступных поверхностях: списке и [поиске](./catalog-product-property-enums/search.md). `propertyId` берётся из [`GET /v1/catalog-product-properties`](/docs/entities/catalog-product-properties). Проверка смотрит на **наличие** ключа, а не на форму значения, и не распространяется на подвызовы [пакетного запроса](/docs/batch) — это ограничитель стоимости и подсказка, а не граница доступа: то, что доступно ключу со скоупом `catalog`, доступно ему и без этого фильтра. 2. **Перечисление есть только у `propertyType: "L"`.** Сначала прочитайте тип свойства: [`GET /v1/catalog-product-properties/:id`](/docs/entities/catalog-product-properties/get). Для свойства любого другого типа (`S` строка, `N` число, `F` файл, `E`/`G` привязки) запрос вернёт **пустой список**, а не ошибку. 3. **Связь с полями товара идёт через `id`.** У товара каталога значение свойства-списка приходит в поле `propertyNNN`, где `NNN` — `id` свойства. Внутри — `value` (это `id` элемента перечисления, строкой), `valueEnum` (готовый читаемый текст) и `valueId` (id строки значения). Сопоставление делается по `String(элемент.id) === товар.propertyNNN.value` — `value` у товара строковый, а `id` справочника числовой. 4. **Форма значения у товара зависит от `listType` свойства.** При `listType: "L"` (выпадающий список) приходит объект с тройкой полей выше. При `listType: "C"` (флажок) приходит голый скаляр `"Y"`/`"N"` — это состояние галочки, а не идентификатор варианта. Справочник у такого свойства всё равно есть и возвращает одну запись — подпись отмеченного состояния (например `value: "да"`). Соединять её с товаром по `id` нельзя: товар несёт флаг, а не id элемента. При `multiple: true` та же форма приходит массивом — разворачивать нужно каждый элемент. 5. **Пагинация обычная: `limit` + `offset`, конец выборки — по `meta.hasMore`.** Битрикс24 сообщает общее количество, поэтому `meta.total` и `meta.hasMore` достоверны. Потолок — 5000 записей за вызов, значение по умолчанию — 50. Редкий крайний случай: если общее количество не придёт, платформа подставит в `meta.total` длину полученного окна, и на полной странице `hasMore` окажется `false` — подстраховаться можно, сверив `data.length` с размером страницы. 6. **Все поля доступны только для чтения.** Варианты списка заводятся в интерфейсе Битрикс24. `GET /v1/catalog-product-property-enums/fields` возвращает `batch: []` — записывающих операций у сущности нет. ## Типичный сценарий Задача: показать пользователю выпадашку со **всеми** размерами и подсветить тот, что выбран у товара. 1. Узнать `iblockId` каталога: [`GET /v1/catalogs`](/docs/entities/catalogs). Делается один раз и кэшируется. 2. Прочитать схему свойств каталога: [`GET /v1/catalog-product-properties?filter[iblockId]=26`](/docs/entities/catalog-product-properties/list). Здесь важны три поля свойства — `propertyType` (перечисление есть только у `L`), `listType` (объект или голый скаляр у товара) и `multiple` (один объект или массив). Кэшируется вместе с шагом 1. 3. Забрать справочник вариантов: [`GET /v1/catalog-product-property-enums?filter[propertyId]=166&limit=1000`](./catalog-product-property-enums/list.md). Построить карту `String(id) → value`. 4. Прочитать товар: [`GET /v1/catalog-products/160`](/docs/entities/catalog-products/get) — в `property166.value` придёт `"116"`, и карта развернёт его в `L`. Для одного товара шаг 3 не нужен: текст уже лежит в `property166.valueEnum`. Справочник нужен ровно тогда, когда требуются **все** варианты — выпадашка, фильтр, экспорт. Справочники для нескольких свойств сразу забираются одним [пакетным запросом](/docs/batch) — до 50 подвызовов, по одному на `propertyId`. Пример тела — в разделе «Известные особенности» на странице [списка значений](./catalog-product-property-enums/list.md). Передать данные между подвызовами одного батча нельзя: поэтому шаг 2 остаётся отдельным кэшируемым вызовом, а батч экономит N справочников по **уже известным** `propertyId`. ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Значение `limit` по умолчанию | 50 | | Авто-пагинация | включается при `limit > 50` | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Свойства товаров каталога](/docs/entities/catalog-product-properties) - [Товары каталога](/docs/entities/catalog-products) - [Каталоги](/docs/entities/catalogs) - [API сущностей](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entities-index) --- # Entity: Catalog Products # Товары каталога Товары торгового каталога: список, получение, создание, изменение и удаление. Товар описывает позицию каталога — название, активность, единицу измерения и флаги продажи. Цены продажи задаются отдельно, в [Ценах каталога](/docs/entities/catalog-prices). Битрикс24 API: `catalog.product.*` Скоуп: `catalog` ## Операции - [Создать товар](./catalog-products/create.md) — `POST /v1/catalog-products` - [Список товаров](./catalog-products/list.md) — `GET /v1/catalog-products` - [Получить товар](./catalog-products/get.md) — `GET /v1/catalog-products/:id` - [Обновить товар](./catalog-products/update.md) — `PATCH /v1/catalog-products/:id` - [Удалить товар](./catalog-products/delete.md) — `DELETE /v1/catalog-products/:id` - [Поиск товаров](./catalog-products/search.md) — `POST /v1/catalog-products/search` - [Поля товара](./catalog-products/fields.md) — `GET /v1/catalog-products/fields` - [Агрегация товаров](./catalog-products/aggregate.md) — `POST /v1/catalog-products/aggregate` ## Ключевые поля | Поле | Описание | |------|---------| | `name` | Название товара. Отдельного поля `title` у товара нет | | `iblockId` | ID каталога. Обязателен в фильтре списка и поиска. Список: [`GET /v1/catalogs`](/docs/entities/catalogs) | | `iblockSectionId` | ID раздела каталога. Список: [`GET /v1/catalog-sections`](/docs/entities/catalog-sections) | | `active` | Активен ли товар | | `measure` | ID единицы измерения | | `purchasingPrice` | Закупочная цена. Валюта — в `purchasingCurrency` | | `quantity` | Остаток на складе | ## Что нужно знать перед работой 1. **Список и поиск требуют фильтр по каталогу.** В `GET /v1/catalog-products` и `POST /v1/catalog-products/search` поле `filter[iblockId]` обязательно — без него запрос возвращает ошибку. Значение `iblockId` берётся из [`GET /v1/catalogs`](/docs/entities/catalogs). 2. **Выборка полей включает `iblockId`.** Если в запросе списка или поиска передаётся `select`, в нём обязательно должен быть `iblockId`. Без явного `select` возвращается полный набор полей товара. 3. **Минимум для создания — два поля.** `name` и `iblockId` обязательны. Остальные поля опциональны и принимают значения по умолчанию. 4. **Булевы флаги — значения `true`/`false`.** `active`, `vatIncluded`, `canBuyZero`, `quantityTrace`, `subscribe`, `barcodeMulti`, `withoutOrder` приходят и принимаются как булевы. Поля `available` и `bundle` вычисляются Битрикс24 и доступны только для чтения. 5. **Остаток и закупочная цена зависят от управления складом.** Когда на портале включено управление складом, поля `quantity`, `purchasingPrice` и `purchasingCurrency` при создании и изменении товара не применяются — остатки и закупочные цены ведутся складскими документами. Цены продажи задаются через [Цены каталога](/docs/entities/catalog-prices). 6. **Ответ `get` подробнее ответа `list`.** Одна запись по `id` возвращает дополнительные поля товара — символьный код, размеры, тип, а также пользовательские свойства каталога вида `propertyNNN`. У свойств-списков элемент приходит вместе с названием — в поле `valueEnum` рядом с `valueId` и `value`. Названия и типы самих свойств `propertyNNN` — в [Свойствах товаров каталога](/docs/entities/catalog-product-properties). Список и поиск возвращают набор полей из [справочника полей](./catalog-products/fields.md). ## Типичный сценарий 1. Найти каталог и его `iblockId`: [`GET /v1/catalogs`](/docs/entities/catalogs). 2. Посмотреть товары каталога: [`GET /v1/catalog-products?filter[iblockId]=25`](./catalog-products/list.md). 3. Создать или изменить товар: [`POST /v1/catalog-products`](./catalog-products/create.md) / [`PATCH /v1/catalog-products/:id`](./catalog-products/update.md). 4. Задать цену товара: [`POST /v1/catalog-prices`](/docs/entities/catalog-prices/create). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Цены каталога](/docs/entities/catalog-prices) - [Каталоги](/docs/entities/catalogs) - [Разделы каталога](/docs/entities/catalog-sections) - [Свойства товаров каталога](/docs/entities/catalog-product-properties) - [Значения списочных свойств](/docs/entities/catalog-product-property-enums) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entities-index) --- # Entity: Catalog Sections # Разделы каталога Разделы товарного каталога: список, получение, создание, изменение и удаление. Разделы образуют дерево внутри каталога — у раздела может быть родительский раздел. Каждый раздел привязан к каталогу по полю `iblockId`. Битрикс24 API: `catalog.section.*` Скоуп: `catalog` ## Операции - [Создать раздел](./catalog-sections/create.md) — `POST /v1/catalog-sections` - [Список разделов](./catalog-sections/list.md) — `GET /v1/catalog-sections` - [Получить раздел](./catalog-sections/get.md) — `GET /v1/catalog-sections/:id` - [Обновить раздел](./catalog-sections/update.md) — `PATCH /v1/catalog-sections/:id` - [Удалить раздел](./catalog-sections/delete.md) — `DELETE /v1/catalog-sections/:id` - [Поиск разделов](./catalog-sections/search.md) — `POST /v1/catalog-sections/search` - [Поля раздела](./catalog-sections/fields.md) — `GET /v1/catalog-sections/fields` ## Ключевые поля | Поле | Описание | |------|---------| | `iblockId` | ID каталога, которому принадлежит раздел. Обязателен для списка, поиска и создания. Список: [`GET /v1/catalogs`](/docs/entities/catalogs) | | `name` | Название раздела | | `iblockSectionId` | ID родительского раздела. `null` — раздел верхнего уровня | | `code` | Символьный код раздела | | `sort` | Индекс сортировки | | `active` | Активен ли раздел | | `description` | Описание раздела | | `descriptionType` | Формат описания: `text` или `html` | Полный список полей — [`GET /v1/catalog-sections/fields`](./catalog-sections/fields.md). ## Что нужно знать перед работой 1. **Список и поиск требуют `filter[iblockId]`.** Без него [`GET /v1/catalog-sections`](./catalog-sections/list.md) и [`POST /v1/catalog-sections/search`](./catalog-sections/search.md) отвечают `400` с кодом `MISSING_REQUIRED_FILTER`. Запрос отклоняется до обращения к Битрикс24, сообщение содержит имя недостающего поля и пример вызова. Значение `iblockId` берётся из [`GET /v1/catalogs`](/docs/entities/catalogs). 2. **Минимум для создания — два поля:** `iblockId` и `name`. Без любого из них запрос вернёт `422`. Поле `iblockSectionId` опционально — задаёт родительский раздел, без него раздел создаётся на верхнем уровне. 3. **Разделы образуют дерево.** Поле `iblockSectionId` указывает на родительский раздел внутри того же каталога. У разделов верхнего уровня оно `null`. ## Типичный сценарий 1. Найти каталог и его `iblockId`: [`GET /v1/catalogs`](/docs/entities/catalogs). 2. Посмотреть разделы каталога: [`GET /v1/catalog-sections?filter[iblockId]=25`](./catalog-sections/list.md). 3. Создать новый раздел или изменить существующий: [`POST /v1/catalog-sections`](./catalog-sections/create.md) / [`PATCH /v1/catalog-sections/:id`](./catalog-sections/update.md). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Товары каталога](/docs/entities/catalog-products) - [Каталоги](/docs/entities/catalogs) - [Цены каталога](/docs/entities/catalog-prices) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entities-index) --- # Entity: Catalogs # Каталоги Торговые каталоги портала: список, получение и фильтрация. Каталог задаёт `iblockId`, по которому работают [товары](/docs/entities/catalog-products), [разделы](/docs/entities/catalog-sections) и [цены](/docs/entities/catalog-prices). Каталоги доступны только для чтения. Битрикс24 API: `catalog.catalog.*` Скоуп: `catalog` ## Операции - [Список каталогов](./catalogs/list.md) — `GET /v1/catalogs` - [Получить каталог](./catalogs/get.md) — `GET /v1/catalogs/:id` - [Поиск каталогов](./catalogs/search.md) — `POST /v1/catalogs/search` - [Поля каталога](./catalogs/fields.md) — `GET /v1/catalogs/fields` ## Ключевые поля | Поле | Описание | |------|---------| | `id` | Идентификатор каталога. Совпадает с `iblockId` | | `iblockId` | ID информационного блока каталога. Используется как фильтр в [`GET /v1/catalog-products`](/docs/entities/catalog-products), [`GET /v1/catalog-sections`](/docs/entities/catalog-sections), [`GET /v1/catalog-prices`](/docs/entities/catalog-prices) | | `name` | Название каталога | | `iblockTypeId` | Тип информационного блока, например `CRM_PRODUCT_CATALOG` | | `productIblockId` | У каталога предложений — `iblockId` связанного каталога товаров. У базового каталога товаров — `null` | | `skuPropertyId` | У каталога предложений — ID свойства, связывающего предложение с товаром. У базового каталога — `null` | Полный список полей — [`GET /v1/catalogs/fields`](./catalogs/fields.md). ## Что нужно знать перед работой 1. **Каталоги доступны только для чтения.** Через API можно получить список и одну запись; создание, изменение и удаление не поддерживаются. Все поля в ответе помечены «только для чтения». 2. **Каталог — источник `iblockId` для остальных эндпоинтов товарного каталога.** Чтобы получить товары, разделы или цены, сначала возьмите `iblockId` нужного каталога из [`GET /v1/catalogs`](./catalogs/list.md) и передайте его фильтром в [`GET /v1/catalog-products`](/docs/entities/catalog-products), [`GET /v1/catalog-sections`](/docs/entities/catalog-sections), [`GET /v1/catalog-prices`](/docs/entities/catalog-prices). 3. **Базовый каталог товаров и каталог предложений различаются по двум полям.** У каталога предложений заполнены `productIblockId` (ссылка на каталог товаров) и `skuPropertyId`; у базового каталога товаров оба равны `null`. ## Типичный сценарий 1. Получить список каталогов: [`GET /v1/catalogs`](./catalogs/list.md) — взять `iblockId` нужного каталога. 2. Получить товары этого каталога: [`GET /v1/catalog-products?filter[iblockId]=25`](/docs/entities/catalog-products). 3. При необходимости — разделы и цены: [`GET /v1/catalog-sections`](/docs/entities/catalog-sections), [`GET /v1/catalog-prices`](/docs/entities/catalog-prices). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | Batch-запросы | каталоги доступны только для чтения — операции записи в [`POST /v1/batch`](/docs/batch) не поддерживаются | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Товары каталога](/docs/entities/catalog-products) - [Разделы каталога](/docs/entities/catalog-sections) - [Цены каталога](/docs/entities/catalog-prices) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entities-index) --- # Entity: Categories # Воронки Универсальное управление воронками CRM для любого типа сущности: сделок, смарт-процессов и других. Каждая воронка содержит свой набор стадий. В отличие от [воронок сделок](/docs/entities/deal-categories), этот эндпоинт работает для всех типов CRM через единый путь. Битрикс24 API: `crm.category.*` Скоуп: `crm` Путь содержит динамический параметр `:entityTypeId` — ID типа CRM-сущности. Для сделок это `2`, для счетов — `31`, для смарт-процессов — значение из `GET /v1/smart-processes`. Основная воронка сделок доступна здесь по id `0`. ## Операции - [Создать воронку](./categories/create.md) — `POST /v1/categories/:entityTypeId` - [Список воронок](./categories/list.md) — `GET /v1/categories/:entityTypeId` - [Получить воронку](./categories/get.md) — `GET /v1/categories/:entityTypeId/:id` - [Обновить воронку](./categories/update.md) — `PATCH /v1/categories/:entityTypeId/:id` - [Удалить воронку](./categories/delete.md) — `DELETE /v1/categories/:entityTypeId/:id` - [Поля воронки](./categories/fields.md) — `GET /v1/categories/:entityTypeId/fields` ## Ключевые поля | Поле | Описание | |------|---------| | `id` | ID воронки. Для сделок основная воронка имеет id `0` | | `entityTypeId` | ID типа CRM-сущности, повторяет параметр пути | | `name` | Название воронки. Обязательно при создании | | `sort` | Порядок сортировки | | `isDefault` | Признак основной воронки типа | Полный список полей — [`GET /v1/categories/:entityTypeId/fields`](./categories/fields.md). Стадии воронки берутся отдельно: `GET /v1/statuses?filter[entityId]=DEAL_STAGE_{id}`. ## Что нужно знать перед работой 1. Воронка задаёт свой набор стадий: они запрашиваются отдельно через `GET /v1/statuses`. Сама воронка хранит только название и сортировку. 2. Для создания достаточно одного поля `name`. Без него ответ — `422` с сообщением `Field 'NAME' is required.` 3. Поддерживаются сделки `2`, счета `31` и смарт-процессы. Предложения `7` воронок не имеют — запрос вернёт `422` с сообщением о неподдерживаемой сущности. Резервные id `2` и `31` здесь рабочие, в отличие от `/v1/items`. 4. **Поля `code` и `isDefault` — только чтение.** Передача любого из них в теле при создании или обновлении возвращает `400` с кодом `READONLY_FIELD`, сообщение называет конкретное поле. Записываются `name` и `sort`. Основная воронка типа назначается в интерфейсе Битрикс24. 5. `GET /v1/categories/:entityTypeId` возвращает полный список воронок типа без фильтрации: параметры `filter`, `select` и `order` принимаются без ошибки, но игнорируются. ## Типичный сценарий 1. Определить тип CRM-сущности: для сделок `entityTypeId` равен `2`, для смарт-процесса — значение из [`GET /v1/smart-processes`](/docs/entities/smart-processes/list). 2. Посмотреть существующие воронки типа: [`GET /v1/categories/2`](./categories/list.md). 3. Создать новую или обновить существующую: [`POST /v1/categories/2`](./categories/create.md) / [`PATCH /v1/categories/2/:id`](./categories/update.md). 4. Запросить стадии нужной воронки: `GET /v1/statuses?filter[entityId]=DEAL_STAGE_{id}`. ## Лимиты | Лимит | Значение | |-------|----------| | Фильтрация и пагинация | не поддерживаются — список типа возвращается целиком | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Воронки сделок](/docs/entities/deal-categories) - [Стадии и статусы](/docs/entities/statuses) - [Типы смарт-процессов](/docs/entities/smart-processes) - [Справочник сущностей](/docs/entities-index) --- # Entity: Companies # Компании Управление компаниями CRM: создание, получение, обновление, удаление, фильтрация. Bitrix24 API: `crm.company.*` Скоуп: `crm` ## Операции - [Создать компанию](./companies/create.md) — `POST /v1/companies` - [Список компаний](./companies/list.md) — `GET /v1/companies` - [Получить компанию](./companies/get.md) — `GET /v1/companies/:id` - [Обновить компанию](./companies/update.md) — `PATCH /v1/companies/:id` - [Удалить компанию](./companies/delete.md) — `DELETE /v1/companies/:id` - [Поиск компаний](./companies/search.md) — `POST /v1/companies/search` - [Поля компании](./companies/fields.md) — `GET /v1/companies/fields` - [Агрегация компаний](./companies/aggregate.md) — `POST /v1/companies/aggregate` - [Импорт записей](../import.md) — `POST /v1/companies/import` --- # Entity: Contacts # Контакты Управление контактами CRM: создание, получение, обновление, удаление, фильтрация. Bitrix24 API: `crm.contact.*` Скоуп: `crm` ## Операции - [Создать контакт](./contacts/create.md) — `POST /v1/contacts` - [Список контактов](./contacts/list.md) — `GET /v1/contacts` - [Получить контакт](./contacts/get.md) — `GET /v1/contacts/:id` - [Обновить контакт](./contacts/update.md) — `PATCH /v1/contacts/:id` - [Удалить контакт](./contacts/delete.md) — `DELETE /v1/contacts/:id` - [Поиск контактов](./contacts/search.md) — `POST /v1/contacts/search` - [Поля контакта](./contacts/fields.md) — `GET /v1/contacts/fields` - [Агрегация контактов](./contacts/aggregate.md) — `POST /v1/contacts/aggregate` - [Импорт записей](../import.md) — `POST /v1/contacts/import` --- # Entity: Crm Card Config # Раскладка карточки CRM Управление раскладкой полей в карточках CRM-сущностей: лиды, сделки, контакты, компании, смарт-процессы. Позволяет прочитать текущую конфигурацию секций и полей, перезаписать её, сбросить к настройкам по умолчанию или принудительно применить общую раскладку ко всем сотрудникам. У раскладки нет отдельного числового `id`: она адресуется набором значений — тип объекта `entityTypeId`, область `scope`, сотрудник `userId` и уточнения `extras`. Битрикс24 API: `crm.item.details.configuration.*` Скоуп: `crm` ## Операции - [Получить раскладку](./crm-card-config/get.md) — `GET /v1/crm/card-config/:entityTypeId` - [Установить раскладку](./crm-card-config/set.md) — `PUT /v1/crm/card-config/:entityTypeId` - [Сбросить раскладку](./crm-card-config/reset.md) — `DELETE /v1/crm/card-config/:entityTypeId` - [Общая раскладка для всех](./crm-card-config/force-common.md) — `POST /v1/crm/card-config/:entityTypeId/force-common` ## Ключевые поля | Поле | Описание | |------|---------| | `entityTypeId` | Тип CRM-объекта в пути:
`1` — лид
`2` — сделка
`3` — контакт
`4` — компания
`7` — предложение
`31` — счёт
смарт-процесс — числовой ID типа из [`GET /v1/smart-processes`](/docs/entities/smart-processes), поле `entityTypeId` | | `scope` | Область раскладки: `P` — личная (по умолчанию), `C` — общая | | `userId` | Сотрудник, чья личная раскладка читается или записывается. По умолчанию — владелец API-ключа. Имеет смысл только при `scope=P` | | `dealCategoryId` | Воронка сделок, только для сделок (`entityTypeId=2`). Источник: [`GET /v1/categories/2`](/docs/entities/categories) | | `categoryId` | Воронка смарт-процесса, только для смарт-процессов. Источник: [`GET /v1/categories/:entityTypeId`](/docs/entities/categories) | | `leadCustomerType` | Тип лида, только для лидов (`entityTypeId=1`): `1` — простой, `2` — повторный | Значения `dealCategoryId`, `categoryId` и `leadCustomerType` можно передать на верхнем уровне запроса или внутри объекта `extras`. Оба варианта дают одинаковый результат. ## Структура раскладки Тело `PUT` содержит массив секций `data`. Каждая секция описывает блок карточки и его поля. ```json { "name": "section_1", "title": "Личные данные", "type": "section", "elements": [ { "name": "NAME", "optionFlags": 1 }, { "name": "LAST_NAME", "optionFlags": 1 }, { "name": "PHONE", "optionFlags": 1, "options": { "defaultCountry": "GB" } } ] } ``` | Поле секции | Описание | |------|---------| | `name` | Внутреннее имя секции | | `title` | Отображаемое название секции | | `type` | Всегда `section` | | `elements` | Массив полей в порядке отображения | | `elements[].name` | Имя поля CRM в формате Битрикс24: `TITLE`, `NAME`, `PHONE`, `UF_CRM_1234567890` для пользовательских полей. Источник для пользовательских полей: [`GET /v1/userfields/:entity`](/docs/userfields) | | `elements[].optionFlags` | Флаг поля: `0` — обычное, `1` — поле клиента | | `elements[].options` | Параметры конкретного поля, например `defaultCountry` для `PHONE` или `defaultAddressType` для `ADDRESS` | ## Что нужно знать перед работой 1. **`scope` регистрозависим.** Допустимы только `P` (личная) и `C` (общая). Любое другое значение возвращает `400 INVALID_SCOPE`, а не откат к значению по умолчанию. 2. **`userId` имеет смысл только при `scope=P`.** Для общей раскладки (`scope=C`) сервер его принимает, но не использует. 3. **`data: null` в ответе — это не пустая раскладка.** `null` означает, что для указанной области ещё не было явной конфигурации, и Битрикс24 показывает встроенную раскладку по умолчанию. Пустой массив `[]` означает явно сохранённую пустую раскладку. 4. **Имена полей в `elements[].name` — в формате Битрикс24, UPPER_SNAKE_CASE.** Например `TITLE`, `STAGE_ID`, `OPPORTUNITY_WITH_CURRENCY`, `UF_CRM_1234567890`. 5. **`force-common` не принимает `scope` и `userId`.** Метод удаляет личные раскладки всех сотрудников и оставляет общую. ## Типичный сценарий Единая настройка карточки контакта под партнёрскую программу и применение её ко всем сотрудникам. 1. Добавить пользовательские поля: [`POST /v1/userfields/contacts`](/docs/userfields). 2. Прочитать текущую общую раскладку: [`GET /v1/crm/card-config/3?scope=C`](./crm-card-config/get.md). 3. Записать новую общую раскладку с секцией «Партнёрка» и нужными полями: [`PUT /v1/crm/card-config/3`](./crm-card-config/set.md) со `scope: "C"`. 4. Сбросить личные раскладки сотрудников, чтобы все увидели единый макет: [`POST /v1/crm/card-config/3/force-common`](./crm-card-config/force-common.md). ## Лимиты Раскладка хранится по одной на область: `scope` плюс `userId` для личной и `extras` для воронки или типа лида. Пагинации нет — `GET` возвращает всю раскладку одной выборкой. Общий лимит частоты запросов к API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization). ## Смотрите также - [Смарт-процессы](/docs/entities/smart-processes) - [Воронки](/docs/entities/categories) - [Пользовательские поля](/docs/userfields) - [Сделки](/docs/entities/deals) - [Контакты](/docs/entities/contacts) - [Справочник сущностей](/docs/entities-index) --- # Entity: Currencies # Валюты Справочник валют портала с курсами обмена. ID валюты — строковый код (`RUB`, `USD`, `EUR`). Bitrix24 API: `crm.currency.*` Скоуп: `crm` ## Операции - [Создать валюту](./currencies/create.md) — `POST /v1/currencies` - [Список валют](./currencies/list.md) — `GET /v1/currencies` - [Получить валюту](./currencies/get.md) — `GET /v1/currencies/:id` - [Обновить валюту](./currencies/update.md) — `PATCH /v1/currencies/:id` - [Удалить валюту](./currencies/delete.md) — `DELETE /v1/currencies/:id` - [Поиск валют](./currencies/search.md) — `POST /v1/currencies/search` - [Поля валюты](./currencies/fields.md) — `GET /v1/currencies/fields` - [Агрегация валют](./currencies/aggregate.md) — `POST /v1/currencies/aggregate` --- # Entity: Deal Categories # Воронки сделок Воронки продаж (категории сделок). Каждая воронка содержит свой набор стадий. Bitrix24 API: `crm.dealcategory.*` Скоуп: `crm` Стадии воронки: `GET /v1/statuses?filter[entityId]=DEAL_STAGE_{categoryId}` Основная воронка с id `0` через `/v1/deal-categories` не возвращается и недоступна по id — для неё используйте универсальный эндпоинт `/v1/categories/2`. ## Операции - [Создать воронку](./deal-categories/create.md) — `POST /v1/deal-categories` - [Список воронок](./deal-categories/list.md) — `GET /v1/deal-categories` - [Получить воронку](./deal-categories/get.md) — `GET /v1/deal-categories/:id` - [Обновить воронку](./deal-categories/update.md) — `PATCH /v1/deal-categories/:id` - [Удалить воронку](./deal-categories/delete.md) — `DELETE /v1/deal-categories/:id` - [Поиск воронок](./deal-categories/search.md) — `POST /v1/deal-categories/search` - [Поля воронки](./deal-categories/fields.md) — `GET /v1/deal-categories/fields` - [Агрегация воронок](./deal-categories/aggregate.md) — `POST /v1/deal-categories/aggregate` --- # Entity: Deals # Сделки Управление сделками CRM: создание, получение, обновление, удаление, фильтрация. Bitrix24 API: `crm.item.*` Скоуп: `crm` ## Операции - [Создать сделку](./deals/create.md) — `POST /v1/deals` - [Список сделок](./deals/list.md) — `GET /v1/deals` - [Получить сделку](./deals/get.md) — `GET /v1/deals/:id` - [Обновить сделку](./deals/update.md) — `PATCH /v1/deals/:id` - [Удалить сделку](./deals/delete.md) — `DELETE /v1/deals/:id` - [Поиск сделок](./deals/search.md) — `POST /v1/deals/search` - [Поля сделки](./deals/fields.md) — `GET /v1/deals/fields` - [Агрегация сделок](./deals/aggregate.md) — `POST /v1/deals/aggregate` - [Получить товары](./deals/products-get.md) — `GET /v1/deals/:id/products` - [Установить товары](./deals/products-set.md) — `PUT /v1/deals/:id/products` - [Добавить товар](./deals/products-add.md) — `POST /v1/deals/:id/products` - [Удалить товар](./deals/products-delete.md) — `DELETE /v1/deals/:id/products/:rowId` - [Получить товар](./deals/products-get-single.md) — `GET /v1/deals/:id/products/:rowId` - [Обновить товар](./deals/products-update.md) — `PATCH /v1/deals/:id/products/:rowId` - [Поля товаров](./deals/products-fields.md) — `GET /v1/deals/:id/products/fields` - [Импорт записей](../import.md) — `POST /v1/deals/import` --- # Entity: Departments # Отделы Управление организационной структурой портала: создание, получение, обновление, удаление и фильтрация отделов. Отделы образуют дерево — каждый отдел кроме корневого ссылается на родительский через `parentId`, а сотрудники назначаются в отделы через [справочник сотрудников](/docs/entities/users). Битрикс24 API: `department.*` Скоуп: `department` ## Операции - [Создать отдел](./departments/create.md) — `POST /v1/departments` - [Список отделов](./departments/list.md) — `GET /v1/departments` - [Получить отдел](./departments/get.md) — `GET /v1/departments/:id` - [Обновить отдел](./departments/update.md) — `PATCH /v1/departments/:id` - [Удалить отдел](./departments/delete.md) — `DELETE /v1/departments/:id` - [Поиск отделов](./departments/search.md) — `POST /v1/departments/search` - [Поля отдела](./departments/fields.md) — `GET /v1/departments/fields` ## Ключевые поля | Поле | Описание | |------|---------| | `id` | Идентификатор отдела | | `name` | Название отдела | | `parentId` | ID родительского отдела. У корневого отдела портала равен `1` | | `headId` | ID руководителя отдела. Источник: [`GET /v1/users`](/docs/entities/users) | | `sort` | Порядок сортировки отдела среди соседей (целое число, по возрастанию) | Полный список полей — [`GET /v1/departments/fields`](./departments/fields.md). ## Что нужно знать перед работой 1. **Структура отделов — дерево с одним корнем.** Отделы верхнего уровня ссылаются на корневой узел через `parentId: 1`. Сам корневой узел не возвращается в [`GET /v1/departments`](./departments/list.md) и не доступен через `GET /v1/departments/:id` — это служебная вершина дерева. Попытка создать второй отдел верхнего уровня (без `parentId` либо с `parentId: 0`) возвращает HTTP 422 с сообщением «В структуре компании должен быть только один раздел верхнего уровня.». 2. **Минимум для создания одного отдела — два поля:** `name` и `parentId`. Если `parentId` опущен — запрос трактуется как попытка создать отдел верхнего уровня (см. пункт выше). 3. **`headId` — ID сотрудника, а не отдела, и НЕ проверяется на существование.** Назначить руководителем можно любого сотрудника портала. Bitrix24 не валидирует `headId`: несуществующий ID будет принят и сохранён как висячая ссылка (запрос вернёт `201`/`200`). Проверяется только `parentId`. Убедитесь, что пользователь существует — [`GET /v1/users`](/docs/entities/users). 4. **`sort` управляет порядком в списке.** Значение `sort` сравнивается между отделами одного уровня — внутри одного `parentId`. Меньшее значение — выше в списке. 5. **Удаление отдела с детьми не запрещено и перестраивает дерево.** Bitrix24 удаляет отдел даже при наличии дочерних отделов или сотрудников: прямые дочерние отделы переподвешиваются на родителя удалённого отдела с переназначением `sort`. Чтобы контролировать итоговую структуру, перенесите дочерние отделы и сотрудников до удаления. ## Типичный сценарий 1. Получить текущую структуру: [`GET /v1/departments`](./departments/list.md) — увидеть дерево по `parentId`. 2. Найти руководителя для нового отдела: [`GET /v1/users?filter[name]=Иван`](/docs/entities/users). 3. Создать отдел: [`POST /v1/departments`](./departments/create.md) с `name`, `parentId`, `headId`. 4. Назначить сотрудников в отдел: через [`PATCH /v1/users/:id`](/docs/entities/users) с указанием поля `departmentId` (массив ID отделов). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | Параметр `offset` | применяется построчно (`offset=7` — с 8-й записи) | | Параметр `order` | не применяется — порядок выдачи фиксирован | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch). Поддерживаются `create`, `update`, `delete` | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Сотрудники](/docs/entities/users) - [Справочник сущностей](/docs/entities-index) --- # Entity: Doc Templates # Шаблоны документов Шаблон документов — это файл `.docx` с подстановочными метками, по которому Битрикс24 формирует готовые документы с подставленными значениями. Битрикс24 API: `documentgenerator.template.*` Скоуп: `documentgenerator` ## Операции - [Создать шаблон](./doc-templates/create.md) — `POST /v1/doc-templates` - [Список шаблонов](./doc-templates/list.md) — `GET /v1/doc-templates` - [Получить шаблон](./doc-templates/get.md) — `GET /v1/doc-templates/:id` - [Обновить шаблон](./doc-templates/update.md) — `PATCH /v1/doc-templates/:id` - [Удалить шаблон](./doc-templates/delete.md) — `DELETE /v1/doc-templates/:id` - [Поиск шаблонов](./doc-templates/search.md) — `POST /v1/doc-templates/search` - [Поля шаблона](./doc-templates/fields.md) — `GET /v1/doc-templates/fields` - [Агрегация шаблонов](./doc-templates/aggregate.md) — `POST /v1/doc-templates/aggregate` ## Ключевые поля | Поле | Описание | |------|---------| | `name` | Название шаблона | | `numeratorId` | Идентификатор нумератора | | `region` | Регион, например `ru` | | `file` | Содержимое `.docx` в виде строки base64 | | `fileId` | Идентификатор файла на Диске. Источник: загрузка через `POST /v1/files/upload` | Полный список полей — [Поля шаблона](./doc-templates/fields.md). ## Что нужно знать перед работой 1. При создании нужен файл — либо содержимое в виде base64 в поле `file`, либо `fileId` уже загруженного на Диск файла. Передаётся ровно одно из двух. 2. Обязательные поля при создании: `name`, `numeratorId`, `region`. 3. Поля ответа приходят в camelCase. 4. Эндпоинты `/v1` принимают только JSON. Формат `multipart/form-data` не поддерживается. ## Типичный сценарий 1. Загрузить файл `.docx` через `POST /v1/files/upload` — поле `id` из ответа становится значением `fileId`. 2. Создать шаблон с этим `fileId` через [`POST /v1/doc-templates`](./doc-templates/create.md). 3. Получить, обновить или удалить шаблон по `id`: [`GET /v1/doc-templates/:id`](./doc-templates/get.md), [`PATCH /v1/doc-templates/:id`](./doc-templates/update.md), [`DELETE /v1/doc-templates/:id`](./doc-templates/delete.md). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | `offset` на больших выборках | рекомендуется `limit ≤ 500` при `offset ≥ 2500` | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Реквизиты компании для генерации документа](/docs/recipes/document-requisites) - [Документы](/docs/entities/documents) - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) --- # Entity: Documents # Документы Документ — это готовый файл, который Битрикс24 формирует по шаблону с подстановкой значений. Каждый документ создаётся на основе шаблона документов и провайдера данных. Битрикс24 API: `documentgenerator.document.*` Скоуп: `documentgenerator` ## Операции - [Создать документ](./documents/create.md) — `POST /v1/documents` - [Список документов](./documents/list.md) — `GET /v1/documents` - [Документы по CRM-сущности](./documents/crm-list.md) — `GET /v1/crm-documents` - [Получить документ](./documents/get.md) — `GET /v1/documents/:id` - [Обновить документ](./documents/update.md) — `PATCH /v1/documents/:id` - [Удалить документ](./documents/delete.md) — `DELETE /v1/documents/:id` - [Поиск документов](./documents/search.md) — `POST /v1/documents/search` - [Поля документа](./documents/fields.md) — `GET /v1/documents/fields` ## Ключевые поля | Поле | Описание | |------|---------| | `templateId` | Идентификатор шаблона. Источник: `GET /v1/doc-templates` | | `providerClassName` | Класс провайдера данных, например `Bitrix\DocumentGenerator\DataProvider\Rest` | | `value` | Внешний идентификатор объекта-источника, например `ORDER-1024` | | `values` | Значения полей-меток шаблона | | `number` | Номер документа | | `pdfUrl` | Ссылка на готовый PDF | Полный список полей — [Поля документа](./documents/fields.md). ## Что нужно знать перед работой 1. Документ создаётся по шаблону: обязательны `templateId`, `providerClassName` и `value`. 2. Поля ответа приходят в camelCase. 3. Готовый файл доступен по ссылкам `downloadUrl` и `pdfUrl` (для пользователя) и `downloadUrlMachine` / `pdfUrlMachine` (для приложения). 4. Документы конкретной записи CRM возвращает отдельный эндпоинт [`GET /v1/crm-documents`](./documents/crm-list.md) со скоупом `crm`: отбор идёт по `entityTypeId` и `entityId`, идентификаторы в ответе приходят строками. ## Типичный сценарий 1. Выбрать шаблон: [`GET /v1/doc-templates`](/docs/entities/doc-templates). 2. Создать документ по шаблону: [`POST /v1/documents`](./documents/create.md) с `templateId`, `providerClassName` и `value`. 3. Получить, обновить или удалить документ по `id`: [`GET /v1/documents/:id`](./documents/get.md), [`PATCH /v1/documents/:id`](./documents/update.md), [`DELETE /v1/documents/:id`](./documents/delete.md). 4. Посмотреть все документы, прикреплённые к записи CRM: [`GET /v1/crm-documents`](./documents/crm-list.md) с `entityTypeId` и `entityId`. ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | `offset` на больших выборках | рекомендуется `limit ≤ 500` при `offset ≥ 2500` | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Шаблоны документов](/docs/entities/doc-templates) - [Реквизиты компании для генерации документа](/docs/recipes/document-requisites) - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) --- # Entity: Files # Файлы Управление файлами на диске Битрикс24: получение списка, загрузка, скачивание, переименование, перемещение, копирование и удаление. Файлы хранятся в папках внутри хранилищ. Битрикс24 API: `disk.file.*` Скоуп: `disk` ## Операции - [Список файлов папки](./files/list.md) — `GET /v1/files` - [Поиск файлов](./files/search.md) — `POST /v1/files/search` - [Получить файл](./files/get.md) — `GET /v1/files/:id` - [Переименовать файл](./files/update.md) — `PATCH /v1/files/:id` - [Удалить файл](./files/delete.md) — `DELETE /v1/files/:id` - [Поля файла](./files/fields.md) — `GET /v1/files/fields` - [Загрузить файл](./files/upload.md) — `POST /v1/files/upload` - [Скачать файл](./files/download.md) — `GET /v1/files/:id/download` - [Переместить файл](./files/moveto.md) — `POST /v1/files/:id/moveto` - [Скопировать файл](./files/copyto.md) — `POST /v1/files/:id/copyto` ## Ключевые поля | Поле | Описание | |------|---------| | `id` | Числовой идентификатор файла | | `name` | Имя файла с расширением | | `size` | Размер файла в байтах. Приходит у записей-файлов | | `folderId` | Идентификатор родительской папки (из [`GET /v1/folders`](/docs/entities/folders)) | | `storageId` | Идентификатор хранилища (из [`GET /v1/storages`](/docs/entities/storages)) | | `type` | Тип объекта — для файлов всегда `"file"` | | `downloadUrl` | Временная ссылка для скачивания. Для программного скачивания используйте [`GET /v1/files/:id/download`](./files/download.md) | | `createdAt` | Дата и время создания в формате ISO 8601 | | `updatedAt` | Дата и время последнего изменения в формате ISO 8601 | Полный список полей — [`GET /v1/files/fields`](./files/fields.md). ## Что нужно знать перед работой 1. **Для получения списка файлов требуется `folderId`.** `GET /v1/files` возвращает содержимое конкретной папки. Чтобы получить идентификатор папки, сначала запросите список хранилищ через `GET /v1/storages`, затем список папок через `GET /v1/folders` с нужным `storageId`. 2. **`GET /v1/files` возвращает смешанный список.** В ответе одновременно присутствуют файлы (`type: "file"`) и подпапки (`type: "folder"`). Для фильтрации по типу используйте поле `type`. 3. **Удаление — мягкое.** `DELETE /v1/files/:id` помечает файл как удалённый, физически файл не стирается. Удалённый файл остаётся в Битрикс24 до окончательной очистки. 4. **Изменить можно только имя.** `PATCH /v1/files/:id` принимает только поле `name`. Прочие поля доступны только для чтения. 5. **Перемещение работает только внутри одного хранилища.** `POST /v1/files/:id/moveto` не перемещает файлы между хранилищами. Для переноса между хранилищами используйте `POST /v1/files/:id/copyto`, затем `DELETE /v1/files/:id`. ## Типичный сценарий 1. Получить идентификатор хранилища: [`GET /v1/storages`](/docs/entities/storages). 2. Найти нужную папку: [`GET /v1/folders`](/docs/entities/folders) с параметром `storageId`. 3. Загрузить файл в папку: [`POST /v1/files/upload`](./files/upload.md) с `folderId` — в ответе придёт `id` нового файла. 4. Скачать содержимое файла: [`GET /v1/files/:id/download`](./files/download.md). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (при `limit > 50` Вайбкод выполняет несколько запросов автоматически, смещение через `offset`) | | Максимальный размер загружаемого файла | определяется настройками портала Битрикс24 | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Папки](/docs/entities/folders) - [Хранилища](/docs/entities/storages) - [Синтаксис фильтрации](/docs/filtering) - [Ключи и авторизация](/docs/keys-auth) - [Коды ошибок](/docs/errors) --- # Entity: Folders # Папки Управление папками на диске Битрикс24: список содержимого, создание, переименование и удаление. Папки хранятся внутри хранилищ и образуют дерево вложенности. Битрикс24 API: `disk.folder.*` Скоуп: `disk` ## Операции - [Создать папку](./folders/create.md) — `POST /v1/folders` - [Список содержимого папки](./folders/list.md) — `GET /v1/folders` - [Получить папку](./folders/get.md) — `GET /v1/folders/:id` - [Переименовать папку](./folders/update.md) — `PATCH /v1/folders/:id` - [Удалить папку](./folders/delete.md) — `DELETE /v1/folders/:id` - [Поиск папок](./folders/search.md) — `POST /v1/folders/search` - [Поля папки](./folders/fields.md) — `GET /v1/folders/fields` - [Переместить папку](./folders/moveto.md) — `POST /v1/folders/:id/moveto` - [Скопировать папку](./folders/copyto.md) — `POST /v1/folders/:id/copyto` ## Ключевые поля | Поле | Описание | |------|---------| | `id` | Числовой идентификатор папки | | `name` | Имя папки. Обязательно при создании | | `parentId` | Идентификатор родительской папки. Обязателен при создании и для листинга. Корневую папку хранилища даёт поле `rootFolderId` в [`GET /v1/storages`](/docs/entities/storages) | | `storageId` | Идентификатор хранилища, из [`GET /v1/storages`](/docs/entities/storages) | | `type` | Тип объекта — `"folder"` или `"file"` | | `detailUrl` | Ссылка на папку в интерфейсе Битрикс24 | | `createdAt` | Дата и время создания в формате ISO 8601 | Полный список полей — [`GET /v1/folders/fields`](./folders/fields.md). ## Что нужно знать перед работой 1. **Имена полей в ответе — camelCase.** Схема приводит исходные UPPER_SNAKE-имена к camelCase. 2. **`parentId` обязателен и для создания, и для листинга.** `GET /v1/folders` возвращает содержимое конкретной папки. Корневую папку хранилища даёт поле `rootFolderId` в [`GET /v1/storages`](/docs/entities/storages). 3. **`GET /v1/folders` возвращает смешанный список.** В ответе одновременно подпапки (`type: "folder"`) и файлы (`type: "file"`). У файлов набор полей отличается — есть `fileId`, `size`, `downloadUrl` и нет `realObjectId`. Для управления файлами используйте раздел [Файлы](/docs/entities/files). Карточка файла доступна через [`GET /v1/files/:id`](/docs/entities/files/get), а не `GET /v1/folders/:id`. 4. **Минимум для создания — `name` и `parentId`.** 5. **Через `PATCH` меняется только имя.** `PATCH /v1/folders/:id` переименовывает папку. Поля `parentId` и `code` в теле `PATCH` неизменяемы. Чтобы переместить папку в другую родительскую, используйте [`POST /v1/folders/:id/moveto`](./folders/moveto.md). 6. **Удаление — мягкое.** `DELETE /v1/folders/:id` помечает папку удалённой и переносит в корзину, физически папка не стирается. Восстановление через API не предусмотрено. ## Типичный сценарий 1. Получить хранилище: [`GET /v1/storages`](/docs/entities/storages) — нужны `id` и `rootFolderId`. 2. Посмотреть содержимое корня: [`GET /v1/folders?parentId=`](./folders/list.md). 3. Создать подпапку: [`POST /v1/folders`](./folders/create.md) с `name` и `parentId`. 4. Переименовать при необходимости: [`PATCH /v1/folders/:id`](./folders/update.md). 5. Удалить: [`DELETE /v1/folders/:id`](./folders/delete.md). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000. При `limit > 50` Вайбкод выполняет несколько запросов автоматически, смещение через `offset` | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Файлы](/docs/entities/files) - [Хранилища](/docs/entities/storages) - [Синтаксис фильтрации](/docs/filtering) - [Ключи и авторизация](/docs/keys-auth) - [Коды ошибок](/docs/errors) --- # Entity: Invoices # Счета Управление счетами CRM: создание, получение, обновление, удаление, фильтрация. Bitrix24 API: `crm.item.*` (SPA-сущность, entityTypeId = 31) Скоуп: `crm` ## Операции - [Создать счёт](./invoices/create.md) — `POST /v1/invoices` - [Список счетов](./invoices/list.md) — `GET /v1/invoices` - [Получить счёт](./invoices/get.md) — `GET /v1/invoices/:id` - [Обновить счёт](./invoices/update.md) — `PATCH /v1/invoices/:id` - [Удалить счёт](./invoices/delete.md) — `DELETE /v1/invoices/:id` - [Поиск счетов](./invoices/search.md) — `POST /v1/invoices/search` - [Поля счёта](./invoices/fields.md) — `GET /v1/invoices/fields` - [Агрегация счетов](./invoices/aggregate.md) — `POST /v1/invoices/aggregate` - [Получить товары](./invoices/products-get.md) — `GET /v1/invoices/:id/products` - [Установить товары](./invoices/products-set.md) — `PUT /v1/invoices/:id/products` - [Добавить товар](./invoices/products-add.md) — `POST /v1/invoices/:id/products` - [Удалить товар](./invoices/products-delete.md) — `DELETE /v1/invoices/:id/products/:rowId` - [Получить товар](./invoices/products-get-single.md) — `GET /v1/invoices/:id/products/:rowId` - [Обновить товар](./invoices/products-update.md) — `PATCH /v1/invoices/:id/products/:rowId` - [Поля товаров](./invoices/products-fields.md) — `GET /v1/invoices/:id/products/fields` - [Импорт записей](../import.md) — `POST /v1/invoices/import` --- # Entity: Items # Смарт-процессы (Items) Управление элементами смарт-процессов CRM: создание, получение, обновление, удаление, фильтрация. Битрикс24 API: `crm.item.*` Скоуп: `crm` Путь содержит динамический параметр `:entityTypeId` — ID типа смарт-процесса. Узнать доступные типы: `GET /v1/smart-processes`. ## Операции - [Создать элемент](./items/create.md) — `POST /v1/items/:entityTypeId` - [Список элементов](./items/list.md) — `GET /v1/items/:entityTypeId` - [Получить элемент](./items/get.md) — `GET /v1/items/:entityTypeId/:id` - [Обновить элемент](./items/update.md) — `PATCH /v1/items/:entityTypeId/:id` - [Удалить элемент](./items/delete.md) — `DELETE /v1/items/:entityTypeId/:id` - [Поиск элементов](./items/search.md) — `POST /v1/items/:entityTypeId/search` - [Поля элемента](./items/fields.md) — `GET /v1/items/:entityTypeId/fields` - [Агрегация элементов](./items/aggregate.md) — `POST /v1/items/:entityTypeId/aggregate` - [Получить товары](./items/products-get.md) — `GET /v1/items/:entityTypeId/:id/products` - [Установить товары](./items/products-set.md) — `PUT /v1/items/:entityTypeId/:id/products` - [Добавить товар](./items/products-add.md) — `POST /v1/items/:entityTypeId/:id/products` - [Удалить товар](./items/products-delete.md) — `DELETE /v1/items/:entityTypeId/:id/products/:rowId` - [Получить товар](./items/products-get-single.md) — `GET /v1/items/:entityTypeId/:id/products/:rowId` - [Обновить товар](./items/products-update.md) — `PATCH /v1/items/:entityTypeId/:id/products/:rowId` - [Поля товаров](./items/products-fields.md) — `GET /v1/items/:entityTypeId/:id/products/fields` ## Ключевые поля | Поле | Описание | |------|---------| | `title` | Название элемента | | `stageId` | Стадия. Формат `DT{typeId}_{catId}:{stage}`. Список: `GET /v1/statuses?filter[entityId]=DYNAMIC_{entityTypeId}_STAGE_{categoryId}` | | `categoryId` | ID воронки. Список: `GET /v1/categories/:entityTypeId` | | `opportunity` | Сумма | | `currencyId` | Валюта. Список: `GET /v1/currencies` | | `assignedById` | Ответственный. Список: `GET /v1/users` | | `companyId` / `contactId` | Привязки к компании и контакту. Списки: `GET /v1/companies`, `GET /v1/contacts` | Полный список полей — [`GET /v1/items/:entityTypeId/fields`](./items/fields.md). ## Что нужно знать перед работой 1. `entityTypeId` в пути — ID типа смарт-процесса из [`GET /v1/smart-processes`](/docs/entities/smart-processes). Значения `1`, `2`, `3`, `4`, `7`, `31` зарезервированы за специализированными API (`/v1/leads`, `/v1/deals`, `/v1/contacts`, `/v1/companies`, `/v1/quotes`, `/v1/invoices`) — обращение к ним через `/v1/items` возвращает `400 INVALID_DYNAMIC_PARAM`. 2. Минимум для создания — `title`. Остальные обязательные поля зависят от настроек типа. 3. Имена пользовательских полей используют внутренний номер типа — `ufCrm_*`, который не равен `entityTypeId`. Точные имена приходят в [`GET /v1/items/:entityTypeId/fields`](./items/fields.md). 4. Поля-даты `begindate` и `closedate` хранятся без времени — переданное время отбрасывается. 5. Списочные ответы кладут пагинацию в `meta` (`meta.total`, `meta.hasMore`), не на верхний уровень. ## Типичный сценарий 1. Найти тип смарт-процесса: [`GET /v1/smart-processes`](/docs/entities/smart-processes) — взять `entityTypeId`. 2. Посмотреть поля типа: [`GET /v1/items/:entityTypeId/fields`](./items/fields.md). 3. Создать элемент: [`POST /v1/items/:entityTypeId`](./items/create.md). 4. Найти и отфильтровать: [`GET /v1/items/:entityTypeId`](./items/list.md) или [`POST /v1/items/:entityTypeId/search`](./items/search.md). 5. При необходимости — добавить товарные позиции: [`GET /v1/items/:entityTypeId/:id/products`](./items/products-get.md). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Ограничение частоты | общее для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Пользовательские поля Управление пользовательскими полями элементов смарт-процесса — отдельный раздел: [Поля смарт-процессов](/docs/userfields/smart-processes) (`/v1/items/:entityTypeId/userfields*`). ## Смотрите также - [Типы смарт-процессов](/docs/entities/smart-processes) - [Поля смарт-процессов](/docs/userfields/smart-processes) - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entities-index) - [Импорт записей](../import.md) — `POST /v1/items/:entityTypeId/import` --- # Entity: Leads # Лиды Управление лидами CRM: создание, получение, обновление, удаление, фильтрация. Bitrix24 API: `crm.item.*` Скоуп: `crm` ## Операции - [Создать лид](./leads/create.md) — `POST /v1/leads` - [Список лидов](./leads/list.md) — `GET /v1/leads` - [Получить лид](./leads/get.md) — `GET /v1/leads/:id` - [Обновить лид](./leads/update.md) — `PATCH /v1/leads/:id` - [Удалить лид](./leads/delete.md) — `DELETE /v1/leads/:id` - [Поиск лидов](./leads/search.md) — `POST /v1/leads/search` - [Поля лида](./leads/fields.md) — `GET /v1/leads/fields` - [Агрегация лидов](./leads/aggregate.md) — `POST /v1/leads/aggregate` - [Получить товары](./leads/products-get.md) — `GET /v1/leads/:id/products` - [Установить товары](./leads/products-set.md) — `PUT /v1/leads/:id/products` - [Добавить товар](./leads/products-add.md) — `POST /v1/leads/:id/products` - [Удалить товар](./leads/products-delete.md) — `DELETE /v1/leads/:id/products/:rowId` - [Получить товар](./leads/products-get-single.md) — `GET /v1/leads/:id/products/:rowId` - [Обновить товар](./leads/products-update.md) — `PATCH /v1/leads/:id/products/:rowId` - [Поля товаров](./leads/products-fields.md) — `GET /v1/leads/:id/products/fields` - [Импорт записей](../import.md) — `POST /v1/leads/import` --- # Entity: Order Statuses # Статусы заказов Управление статусами заказов и доставки интернет-магазина: создание, получение, обновление, удаление, поиск, агрегация. Статусы — это справочник, на который ссылается поле [`orders.statusId`](./orders/fields.md). У каждого статуса есть тип: `O` — статус заказа, `D` — статус доставки. Битрикс24 API: `sale.status.*` Скоуп: `sale` ## Операции - [Создать статус](./order-statuses/create.md) — `POST /v1/order-statuses` - [Список статусов](./order-statuses/list.md) — `GET /v1/order-statuses` - [Получить статус](./order-statuses/get.md) — `GET /v1/order-statuses/:id` - [Обновить статус](./order-statuses/update.md) — `PATCH /v1/order-statuses/:id` - [Удалить статус](./order-statuses/delete.md) — `DELETE /v1/order-statuses/:id` - [Поиск статусов](./order-statuses/search.md) — `POST /v1/order-statuses/search` - [Поля статуса](./order-statuses/fields.md) — `GET /v1/order-statuses/fields` - [Агрегация статусов](./order-statuses/aggregate.md) — `POST /v1/order-statuses/aggregate` ## Ключевые поля | Поле | Тип | Описание | |------|-----|---------| | `id` | string | Символьный код статуса (1-2 символа: `N`, `IP`, `DT`). **Задаётся пользователем при создании**, не генерируется автоматически | | `type` | string | Тип статуса: `O` — статус заказа, `D` — статус доставки | | `sort` | number \| null | Порядок сортировки в списках. При создании без `sort` поле остаётся `null` — значение по умолчанию не подставляется | | `notify` | boolean | Отправлять ли уведомление клиенту при переходе заказа в этот статус. При создании без `notify` поле остаётся `false` — значение по умолчанию не подставляется | | `color` | string \| null | HEX-код цвета для отображения, например `#FFA500`, либо `null`. При создании без `color` поле остаётся `null` — значение по умолчанию не подставляется | | `xmlId` | string \| null | Внешний идентификатор. При создании без явного значения генерируется автоматически вида `bx_`. У части системных статусов — `null` | Полный список полей — [`GET /v1/order-statuses/fields`](./order-statuses/fields.md). Отдельного поля с локализованным названием статуса через этот API нет — для идентификации служат символьный код `id` и тип `type`. ## Что нужно знать перед работой 1. **`id` задаётся пользователем.** При создании передавайте короткий символьный код (1-2 символа): например, `N` («новый»), `IP` («в работе»), `DT` («доставлен»). Идентификатор должен быть уникальным независимо от типа — нельзя создать два статуса с одинаковым `id`, даже если один из них для заказа, а второй для доставки. 2. **Тело запроса плоское.** При создании и обновлении передавайте поля прямо в корне JSON: `{"id": "DT", "type": "O", ...}`. Обёртка `fields` не нужна. 3. **Набор статусов по умолчанию.** На новом портале есть стандартные статусы: `N` («Принят, ожидается оплата»), `P` («Оплачен»), `F` («Выполнен»), `D` («Отказ»), `DN` («Доставляется») и другие. Их можно изменять и удалять тем же API, но заказы со ссылками на старый `id` после удаления статуса не находятся в выборках по `statusId`. ## Связанные сущности | Сущность | Эндпоинт | Назначение | |----------|----------|-----------| | Заказы | [`GET /v1/orders?filter[statusId]=:id`](./orders/list.md) | Заказы, находящиеся в этом статусе — поле `orders.statusId` ссылается сюда. | ## Типичный сценарий Создание нового статуса заказа и его использование: 1. Получить существующие статусы: [`GET /v1/order-statuses?filter[type]=O`](./order-statuses/list.md) — убедиться, что новый код `id` не занят. 2. Создать статус: [`POST /v1/order-statuses`](./order-statuses/create.md) с `id`, `type: "O"`, `sort`, `notify`, `color`. 3. Использовать в заказах: [`PATCH /v1/orders/:id`](./orders/update.md) с `statusId: "новый_id"`. ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Автоматическая пагинация | включается при `limit > 50` | | Длина `id` | максимум 2 символа (символьный код статуса) | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Частота запросов | общая для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Заказы](./orders.md) - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Справочник сущностей](/docs/entities-index) --- # Entity: Orders # Заказы Управление заказами интернет-магазина: создание, получение, обновление, удаление, поиск, агрегация. Заказ — корневая сущность интернет-магазина: с него начинается путь покупателя, к нему привязываются позиции корзины, оплаты, отгрузки и статусы. Битрикс24 API: `sale.order.*` Скоуп: `sale` ## Операции - [Создать заказ](./orders/create.md) — `POST /v1/orders` - [Список заказов](./orders/list.md) — `GET /v1/orders` - [Получить заказ](./orders/get.md) — `GET /v1/orders/:id` - [Обновить заказ](./orders/update.md) — `PATCH /v1/orders/:id` - [Удалить заказ](./orders/delete.md) — `DELETE /v1/orders/:id` - [Поиск заказов](./orders/search.md) — `POST /v1/orders/search` - [Поля заказа](./orders/fields.md) — `GET /v1/orders/fields` - [Агрегация заказов](./orders/aggregate.md) — `POST /v1/orders/aggregate` ## Ключевые поля | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор заказа (только чтение) | | `accountNumber` | string | Номер счёта для покупателя — порядковый номер заказа на портале | | `lid` | string | Идентификатор сайта-источника, всегда `"s1"` для облачных порталов | | `personTypeId` | number | Идентификатор типа плательщика (юр. лицо, физ. лицо и т. п.). На каждом портале свой набор типов. Узнать ID можно по существующим заказам: `GET /v1/orders` или `POST /v1/orders/aggregate` с `groupBy: "personTypeId"` | | `currency` | string | Валюта заказа. Список: [`GET /v1/currencies`](/docs/entities/currencies) | | `price` | number | Общая сумма заказа | | `statusId` | string | Текущий статус заказа. Источник: [`GET /v1/order-statuses?filter[type]=O`](./order-statuses/list.md) | | `userId` | number | Идентификатор пользователя Битрикс24 — покупателя в интернет-магазине. Источник: [`GET /v1/users`](/docs/entities/users) | | `payed` | boolean | Оплачен ли заказ полностью | | `canceled` | boolean | Отменён ли заказ | | `responsibleId` | number | Ответственный сотрудник. Источник: [`GET /v1/users`](/docs/entities/users) | | `dateInsert` | datetime | Дата создания (только чтение) | | `dateUpdate` | datetime | Дата последнего изменения (только чтение) | Полный список полей — [`GET /v1/orders/fields`](./orders/fields.md). ## Что нужно знать перед работой 1. **Тело запроса плоское.** При создании и обновлении передавайте поля прямо в корне JSON: `{"lid": "s1", "personTypeId": 5, ...}`. Обёртка `fields` не нужна. 2. **Для создания обязательны три поля:** `lid` (всегда `"s1"` для облачных порталов), `personTypeId` (тип плательщика — на каждом портале свой набор), `currency`. Без них `POST /v1/orders` вернёт `BITRIX_ERROR` с перечислением отсутствующих полей. 3. **Заказ возвращает связанные сущности вложенно.** `GET /v1/orders/:id` отдаёт массивы `basketItems[]` (позиции корзины), `payments[]` (оплаты), `propertyValues[]` (свойства заказа), `clients[]` (CRM-привязки) внутри одного объекта. Отдельные эндпоинты [`/v1/basket-items`](./basket-items.md) и [`/v1/payments`](./payments.md) используются для создания и обновления — но для чтения содержимого одного заказа отдельные вызовы не нужны. 4. **Автоматическая пагинация** включается при `limit > 50`. Общее количество приходит в `meta.total`. ## Связанные сущности Полноценный жизненный цикл заказа использует семейство сущностей `sale.*`: | Сущность | Эндпоинт | Назначение | |----------|----------|-----------| | Позиции корзины | [`GET /v1/basket-items?filter[orderId]=:id`](./basket-items.md) | Товарные позиции заказа — что купил покупатель, по какой цене, с какой скидкой. | | Оплаты | [`GET /v1/payments?filter[orderId]=:id`](./payments.md) | Оплаты заказа — сумма, платёжная система, статус «оплачено / возврат». | | Статусы заказов | [`GET /v1/order-statuses?filter[type]=O`](./order-statuses.md) | Каталог статусов для заполнения `statusId`. Тип `O` — статусы заказа, `D` — статусы доставки. | ## Типичный сценарий Обработка нового заказа из внешней системы (CMS, маркетплейс): 1. Получить список статусов заказов: [`GET /v1/order-statuses?filter[type]=O`](./order-statuses/list.md) — найти ID нужного статуса (например, `N` — «Принят»). 2. Создать заказ: [`POST /v1/orders`](./orders/create.md) с минимумом полей (`lid`, `personTypeId`, `currency`, `price`, `statusId`, `userId`). 3. Добавить позиции корзины: [`POST /v1/basket-items`](./basket-items/create.md) — по одной позиции на товар (`orderId`, `productId`, `quantity`, `price`). 4. Зарегистрировать оплату: [`POST /v1/payments`](./payments/create.md) — указав `orderId`, `paySystemId`, `sum`. 5. По мере выполнения — обновить статус: [`PATCH /v1/orders/:id`](./orders/update.md) с новым `statusId`. ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Автоматическая пагинация | включается при `limit > 50` | | `offset` на больших выборках | рекомендуется `limit ≤ 500` при `offset ≥ 2500` | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Частота запросов | общая для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Позиции корзины](./basket-items.md) - [Оплаты](./payments.md) - [Статусы заказов](./order-statuses.md) - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Справочник сущностей](/docs/entities-index) --- # Entity: Pages # Страницы Управление страницами лендингов и интернет-магазинов на платформе Битрикс24: создание, получение, обновление, удаление. Страница всегда принадлежит сайту и наследует от него тип `PAGE` или `STORE`. Битрикс24 API: `landing.landing.*` Скоуп: `landing` ## Операции - [Создать страницу](./pages/create.md) — `POST /v1/pages` - [Список страниц](./pages/list.md) — `GET /v1/pages` - [Получить страницу](./pages/get.md) — `GET /v1/pages/:id` - [Обновить страницу](./pages/update.md) — `PATCH /v1/pages/:id` - [Удалить страницу](./pages/delete.md) — `DELETE /v1/pages/:id` - [Поиск страниц](./pages/search.md) — `POST /v1/pages/search` - [Поля страницы](./pages/fields.md) — `GET /v1/pages/fields` - [Агрегация страниц](./pages/aggregate.md) — `POST /v1/pages/aggregate` ## Ключевые поля | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор страницы (только чтение) | | `title` | string | Название страницы, до 255 символов. Обязательно при создании | | `code` | string | Символьный код страницы в URL. Если не передавать — генерируется из `title`. Не должен содержать `/`. Внутри сайта или папки должен быть уникальным — иначе автоматически добавляется числовой суффикс | | `siteId` | number | Идентификатор сайта, которому принадлежит страница. Источник: [`GET /v1/sites`](/docs/entities/sites/list). Обязательно при создании | | `active` | boolean | Опубликована ли страница. Только для чтения: новые страницы создаются неактивными, публикация — отдельными вызовами `POST /v1/pages/:id/publication` и `POST /v1/pages/:id/unpublish` | | `description` | string \| null | Произвольное описание страницы. Приходит `null`, если не задано (в операционных доках [get](./pages/get.md) / [list](./pages/list.md) тип уже `string \| null` — здесь приведено к ним для единообразия) | | `createdById` | number | Идентификатор создавшего сотрудника (только чтение). Источник: [`GET /v1/users`](/docs/entities/users) | | `dateCreate` | datetime | Дата создания (только чтение) | | `dateModify` | datetime | Дата последнего изменения (только чтение) | ## Что нужно знать перед работой 1. **Тело запроса плоское.** При создании и обновлении передавайте поля прямо в корне JSON: `{"title": "...", "code": "...", "siteId": 3}`. Обёртка `fields` не нужна. 2. **Минимум для создания:** `title` + `siteId`. Остальные поля опциональны. 3. **Публикация — отдельные вызовы, поле `active` в теле не принимается.** При создании страница получает `active: false`. Передача `active` в `POST` или `PATCH` отклоняется с `400 READONLY_FIELD`, причём вместе с ним не применяется и остальное тело запроса. Опубликовать страницу — `POST /v1/pages/:id/publication`, снять с публикации — `POST /v1/pages/:id/unpublish`. Для страниц базы знаний, рабочих групп и главных страниц обоим вызовам нужен параметр `scope` со значением `KNOWLEDGE`, `GROUP` или `MAINPAGE` — без него страница не находится и приходит `404`. Обычным страницам сайта параметр не нужен. 4. **Полный список полей — [`GET /v1/pages/fields`](./pages/fields.md).** Эндпоинт возвращает карту всех полей страницы с типом, признаком `readonly`, подписью и — у девяти полей, которые могут прийти со значением `null`, — признаком `nullable`. Ключевые поля приведены в разделе «Ключевые поля» выше, полный перечень из 27 полей — на странице [Поля страницы](./pages/fields.md). 5. **Ответ может содержать дополнительные поля Битрикс24 — в camelCase.** Помимо ключевых полей, по умолчанию возвращаются дополнительные — в **camelCase**, **не** в `UPPER_CASE`: `deleted`, `xmlId`, `tplId`, `sitemap`, `folder`, `folderId`, `searchContent`, `modifiedById`, `domainId`, `initiatorAppCode`, `rule`, `public`, `sys`, `views`, `tplCode`, `version`, `historyStep`, `datePublic` и другие. Чтение по документированному имени `data[].XML_ID` / `MODIFIED_BY_ID` вернёт `undefined` — используйте camelCase. Чтобы получить только ключевые поля, передавайте параметр `select` в `GET /v1/pages`: `?select=id,title,code,siteId,active,description,createdById,dateCreate,dateModify`. См. примеры в [Списке страниц](./pages/list.md). Для `GET /v1/pages/:id` параметр `select` не применяется — отбор полей доступен только в списке. - Поле `datePublic` приходит `null`, если у Битрикс24 нет даты публикации по странице, — это обычный случай и для опубликованной страницы, поэтому признаком публикации оно не является. Публикацию определяйте по `active` или `public`. Описание поля — в [Полях страницы](./pages/fields.md). 6. **`offset` для постраничного перехода поддерживается.** Вайбкод возвращает запрошенное окно `[offset, offset + limit)`. Значение `meta.total` — точное число записей под фильтром. Для больших выборок также работает `limit > 50`. 7. **Сортировка поддерживается.** `?order[поле]=asc|desc` или короткая форма `?sort=-поле` (по убыванию), в теле [`POST /v1/pages/search`](./pages/search.md) — поле `sort`. Без параметра выборка идёт по возрастанию `id`. Для подсчёта количества страниц используйте `meta.total` из [Списка страниц](./pages/list.md): `GET /v1/pages?filter[siteId]=3&limit=1` вернёт `meta.total` без выгрузки записей. 8. **Формат дат — локаль-зависимый, не ISO 8601.** Поля `dateCreate`, `dateModify` и `datePublic` приходят строкой в локальном формате портала: на RU-локали — `ДД.ММ.ГГГГ ЧЧ:ММ:СС` (`30.12.2021 12:30:52`), на EN-локали — `MM/DD/YYYY hh:mm:ss am/pm` (`12/30/2021 12:30:52 pm`). Значение возвращается как есть, одинаково в списке и в карточке. `new Date(value)` вернёт `Invalid Date` либо перепутает день и месяц — не разбирайте дату по фиксированному шаблону. Тот же формат нужен и в фильтре: значение в формате другой локали или в ISO Битрикс24 не распознаёт и возвращает пустой список с кодом 200. ## Связанные сущности | Сущность | Эндпоинт | Назначение | |----------|----------|-----------| | Сайты | [`GET /v1/sites`](/docs/entities/sites) | Контейнеры страниц. Источник `siteId` для создания страницы. Удалить сайт можно только после удаления всех его страниц. | ## Типичный сценарий 1. Найти сайт: [`GET /v1/sites`](/docs/entities/sites/list). 2. Посмотреть его страницы: [`GET /v1/pages?filter[siteId]=3`](./pages/list.md). 3. Создать новую или обновить существующую: [`POST /v1/pages`](./pages/create.md) / [`PATCH /v1/pages/:id`](./pages/update.md). 4. Удалить ненужные: [`DELETE /v1/pages/:id`](./pages/delete.md). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Постраничный переход | через `offset` — окно `[offset, offset + limit)` | | `offset` | поддерживается — окно `[offset, offset + limit)` применяется на стороне Вайбкод | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Сайты](/docs/entities/sites) - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Справочник сущностей](/docs/entities-index) --- # Entity: Payments # Оплаты Управление оплатами заказов: создание, получение, обновление, удаление, поиск, агрегация. Оплата — отдельная сущность, привязанная к заказу по полю `orderId`. У одного заказа может быть несколько оплат (например, частичная предоплата + доплата при доставке), каждая со своей платёжной системой и статусом. Битрикс24 API: `sale.payment.*` Скоуп: `sale` ## Операции - [Создать оплату](./payments/create.md) — `POST /v1/payments` - [Список оплат](./payments/list.md) — `GET /v1/payments` - [Получить оплату](./payments/get.md) — `GET /v1/payments/:id` - [Обновить оплату](./payments/update.md) — `PATCH /v1/payments/:id` - [Удалить оплату](./payments/delete.md) — `DELETE /v1/payments/:id` - [Поиск оплат](./payments/search.md) — `POST /v1/payments/search` - [Поля оплаты](./payments/fields.md) — `GET /v1/payments/fields` - [Агрегация оплат](./payments/aggregate.md) — `POST /v1/payments/aggregate` ## Ключевые поля | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор оплаты (только чтение) | | `accountNumber` | string | Порядковый номер оплаты на портале (только чтение) | | `orderId` | number | Идентификатор заказа. Источник: [`GET /v1/orders`](./orders/list.md) | | `paySystemId` | number | Идентификатор платёжной системы. На каждом портале свой набор систем. Узнать ID можно из существующих оплат: `GET /v1/payments` или `POST /v1/payments/aggregate` с `groupBy: "paySystemId"` | | `paySystemName` | string | Название платёжной системы (только чтение, приходит из карточки платёжной системы) | | `sum` | number | Сумма оплаты | | `currency` | string | Валюта оплаты. Список: [`GET /v1/currencies`](/docs/entities/currencies) | | `paid` | boolean | Помечена ли оплата как поступившая | | `datePaid` | datetime | Дата отметки оплаты | | `dateBill` | datetime | Дата выставления счёта | | `responsibleId` | number | Ответственный сотрудник. Источник: [`GET /v1/users`](/docs/entities/users) | | `isReturn` | string | Признак возврата: `"N"` (обычная оплата), `"Y"` (возврат), `"P"` (частичный возврат) | | `comments` | string | Комментарий к оплате | | `xmlId` | string | Внешний идентификатор для синхронизации | Полный список полей — [Поля оплаты](./payments/fields.md). ## Что нужно знать перед работой 1. **Оплата всегда привязана к заказу.** Поле `orderId` обязательно при создании — без существующего заказа оплату создать нельзя, сначала вызовите [`POST /v1/orders`](./orders/create.md). На один заказ можно зарегистрировать несколько оплат (предоплата, доплата при доставке) — каждая отдельным `POST /v1/payments`. 2. **Тело запроса плоское.** При создании и обновлении передавайте поля прямо в корне JSON: `{"orderId": 19, "paySystemId": 11, ...}`. Обёртка `fields` не нужна. 3. **Поле `isReturn` — строка, а не boolean.** Принимает три значения: `"N"` (обычная оплата), `"Y"` (возврат) и `"P"` (частичный возврат) — фильтр и обновление работают по этим строкам. 4. **Сумма заказа не пересчитывается при создании оплаты.** Регистрация оплаты не меняет статус заказа (`orders.payed`, `orders.statusId`) — обновите их отдельным [`PATCH /v1/orders/:id`](./orders/update.md), если нужно отметить заказ как оплаченный. ## Связанные сущности | Сущность | Эндпоинт | Назначение | |----------|----------|-----------| | Заказы | [`GET /v1/orders/:id`](./orders/get.md) | Родительский заказ — `orderId` указывается при создании оплаты. | | Позиции корзины | [`GET /v1/basket-items?filter[orderId]=:id`](./basket-items/list.md) | Товары в том же заказе. | | Сотрудники | [`GET /v1/users`](/docs/entities/users) | Источник `responsibleId`. | ## Типичный сценарий Регистрация оплаты от внешнего платёжного шлюза: 1. Найти заказ: [`GET /v1/orders?filter[xmlId]=:externalOrderId`](./orders/list.md) — например, по внешнему идентификатору заказа. 2. Создать оплату: [`POST /v1/payments`](./payments/create.md) с `orderId`, `paySystemId`, `sum`, `paid: true`, `xmlId` платёжной транзакции. 3. Обновить статус заказа после оплаты: [`PATCH /v1/orders/:id`](./orders/update.md) с `payed: true`, `statusId: "F"` (или другим финальным статусом). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Автоматическая пагинация | включается при `limit > 50` | | `offset` на больших выборках | рекомендуется `limit ≤ 500` при `offset ≥ 2500` | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Частота запросов | общая для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Поля оплаты](./payments/fields.md) - [Заказы](./orders.md) - [Позиции корзины](./basket-items.md) - [Статусы заказов](./order-statuses.md) - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Справочник сущностей](/docs/entities-index) --- # Entity: Product Sections # Разделы товаров Управление разделами каталога товаров CRM: создание, получение, обновление, удаление и поиск. Раздел группирует товары внутри каталога и может быть вложенным. Битрикс24 API: `crm.productsection.*` Скоуп: `crm` **Методы `/v1/product-sections` устарели.** Для новых интеграций используйте [Разделы каталога](/docs/entities/catalog-sections). ## Операции - [Создать раздел](./product-sections/create.md) — `POST /v1/product-sections` - [Список разделов](./product-sections/list.md) — `GET /v1/product-sections` - [Получить раздел](./product-sections/get.md) — `GET /v1/product-sections/:id` - [Обновить раздел](./product-sections/update.md) — `PATCH /v1/product-sections/:id` - [Удалить раздел](./product-sections/delete.md) — `DELETE /v1/product-sections/:id` - [Поиск разделов](./product-sections/search.md) — `POST /v1/product-sections/search` - [Поля раздела](./product-sections/fields.md) — `GET /v1/product-sections/fields` ## Ключевые поля | Поле | Описание | |------|---------| | `name` | Название раздела | | `catalogId` | ID каталога. Список: `GET /v1/catalogs` | | `sectionId` | ID родительского раздела для вложенности. У корневого раздела — `null` | | `code` | Символьный код раздела | | `xmlId` | Внешний идентификатор | Полный список полей — [`GET /v1/product-sections/fields`](./product-sections/fields.md). ## Что нужно знать перед работой 1. **Это те же разделы, что и в каталоге.** Раздел с тем же `id` доступен через [`GET /v1/catalog-sections`](/docs/entities/catalog-sections). `catalogId` здесь соответствует `iblockId` там. 2. **Тело запроса плоское.** Поля передаются в корне JSON, без обёртки `fields`. 3. **Для создания нужно только `name`.** `catalogId` по умолчанию равен каталогу CRM портала, `code` формируется из названия. 4. **Вложенность задаётся через `sectionId`.** Это ID родительского раздела. У разделов верхнего уровня `sectionId` равен `null`. 5. **Поля ответа в camelCase.** Соответствие исходным именам Битрикс24 — в [Полях раздела](./product-sections/fields.md). ## Типичный сценарий 1. Посмотреть разделы каталога: [`GET /v1/product-sections?filter[catalogId]=25`](./product-sections/list.md). 2. Создать новый раздел: [`POST /v1/product-sections`](./product-sections/create.md). 3. Привязать товары к разделу: [`PATCH /v1/products/:id`](/docs/entities/products) с полем `sectionId`. ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | `offset` на больших выборках | рекомендуется `limit ≤ 500` при `offset ≥ 2500` | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Справочник сущностей](/docs/entities-index) - [Товары](/docs/entities/products) - [Разделы каталога](/docs/entities/catalog-sections) --- # Entity: Products # Товары Управление товарами CRM-каталога: создание, получение, обновление, удаление, поиск и агрегация. Товар описывает позицию каталога — название, цену, валюту, раздел и пользовательские свойства. Битрикс24 API: `crm.product.*` Скоуп: `crm` **Методы `/v1/products` устарели.** Для новых интеграций используйте [Товары каталога](/docs/entities/catalog-products) — модель с остатками, ценами и вариациями. ## Операции - [Создать товар](./products/create.md) — `POST /v1/products` - [Список товаров](./products/list.md) — `GET /v1/products` - [Получить товар](./products/get.md) — `GET /v1/products/:id` - [Обновить товар](./products/update.md) — `PATCH /v1/products/:id` - [Удалить товар](./products/delete.md) — `DELETE /v1/products/:id` - [Поиск товаров](./products/search.md) — `POST /v1/products/search` - [Поля товара](./products/fields.md) — `GET /v1/products/fields` - [Агрегация товаров](./products/aggregate.md) — `POST /v1/products/aggregate` ## Ключевые поля | Поле | Описание | |------|---------| | `name` | Название товара. Отдельного поля `title` у товара нет | | `price` | Цена товара. Валюта — в `currency` | | `currency` | Валюта цены. Список: `GET /v1/currencies` | | `active` | Активен ли товар | | `sectionId` | Раздел каталога. Список: `GET /v1/product-sections` | | `catalogId` | ID каталога. Список: `GET /v1/catalogs` | | `measure` | ID единицы измерения | Полный список полей — [`GET /v1/products/fields`](./products/fields.md). ## Что нужно знать перед работой 1. **Это те же товары, что и в каталоге.** Товар с тем же `id` доступен через [`GET /v1/catalog-products`](/docs/entities/catalog-products), где у него больше полей — остатки, склад, вариации. `catalogId` здесь соответствует `iblockId` там. 2. **Тело запроса плоское.** При создании и обновлении передавайте поля прямо в корне JSON: `{"name": "...", "price": 100}`. Обёртка `fields` не нужна. 3. **Для создания нужно только `name`.** Без названия запрос возвращает `422 BITRIX_ERROR`. Остальные поля опциональны: `catalogId` по умолчанию равен каталогу CRM портала, `code` формируется из названия. 4. **Поля ответа в camelCase.** Соответствие исходным именам Битрикс24 — в [Полях товара](./products/fields.md). 5. **Пользовательские свойства товара.** Поля вида `PROPERTY_` приходят в ответах `get` и `fields` — это свойства, настроенные для каталога на портале. У свойств-списков поле возвращает только ID выбранного элемента, без названия. Название элемента отдаёт [`GET /v1/catalog-products`](/docs/entities/catalog-products) — там у того же свойства приходит и ID, и текст значения. 6. **Доступ из веб-интерфейса.** По `catalogId` и `id` товар открывается в магазине портала по адресу `https://<портал>.bitrix24.ru/shop/catalog//product//`. Доступ ограничен правами сотрудника. ## Типичный сценарий 1. Посмотреть разделы каталога: [`GET /v1/product-sections`](/docs/entities/product-sections). 2. Список товаров раздела: [`GET /v1/products?filter[sectionId]=19`](./products/list.md). 3. Создать новый или обновить существующий: [`POST /v1/products`](./products/create.md) / [`PATCH /v1/products/:id`](./products/update.md). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | `offset` на больших выборках | рекомендуется `limit ≤ 500` при `offset ≥ 2500` | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Справочник сущностей](/docs/entities-index) - [Разделы товаров](/docs/entities/product-sections) - [Товары каталога](/docs/entities/catalog-products) --- # Entity: Quotes # Предложения Управление коммерческими предложениями CRM: создание, получение, обновление, удаление, товарные позиции. Bitrix24 API: `crm.quote.*` Скоуп: `crm` ## Операции - [Создать предложение](./quotes/create.md) — `POST /v1/quotes` - [Список предложений](./quotes/list.md) — `GET /v1/quotes` - [Получить предложение](./quotes/get.md) — `GET /v1/quotes/:id` - [Обновить предложение](./quotes/update.md) — `PATCH /v1/quotes/:id` - [Удалить предложение](./quotes/delete.md) — `DELETE /v1/quotes/:id` - [Поиск предложений](./quotes/search.md) — `POST /v1/quotes/search` - [Поля предложения](./quotes/fields.md) — `GET /v1/quotes/fields` - [Агрегация предложений](./quotes/aggregate.md) — `POST /v1/quotes/aggregate` - [Получить товары](./quotes/products-get.md) — `GET /v1/quotes/:id/products` - [Установить товары](./quotes/products-set.md) — `PUT /v1/quotes/:id/products` - [Добавить товар](./quotes/products-add.md) — `POST /v1/quotes/:id/products` - [Удалить товар](./quotes/products-delete.md) — `DELETE /v1/quotes/:id/products/:rowId` - [Получить товар](./quotes/products-get-single.md) — `GET /v1/quotes/:id/products/:rowId` - [Обновить товар](./quotes/products-update.md) — `PATCH /v1/quotes/:id/products/:rowId` - [Поля товаров](./quotes/products-fields.md) — `GET /v1/quotes/:id/products/fields` - [Импорт записей](../import.md) — `POST /v1/quotes/import` --- # Entity: Requisite Links # Связи реквизитов Указывает, какой реквизит компании и какой банковский счёт использовать в счёте, предложении или сделке. Нужно компаниям, у которых несколько реквизитов. У связи нет отдельного числового `id`: она задаётся парой значений — тип владельца `entityTypeId` и его ID `entityId`. Битрикс24 API: `crm.requisite.link.*` Скоуп: `crm` ## Операции - [Зарегистрировать связь](./requisite-links/register.md) — `POST /v1/requisite-links` - [Список связей](./requisite-links/list.md) — `GET /v1/requisite-links` - [Получить связь](./requisite-links/get.md) — `GET /v1/requisite-links/:entityTypeId/:entityId` - [Обновить связь](./requisite-links/update.md) — `PATCH /v1/requisite-links/:entityTypeId/:entityId` - [Удалить связь](./requisite-links/unregister.md) — `DELETE /v1/requisite-links/:entityTypeId/:entityId` - [Поиск связей](./requisite-links/search.md) — `POST /v1/requisite-links/search` - [Поля связи](./requisite-links/fields.md) — `GET /v1/requisite-links/fields` ## Ключевые поля | Поле | Тип | Описание | |------|-----|---------| | `entityTypeId` | number | Тип владельца связи — сделка, счёт, предложение, элемент смарт-процесса. Справочник значений — [Поля связи](./requisite-links/fields.md) | | `entityId` | number | ID владельца | | `requisiteId` | number | ID привязываемого реквизита клиента, `0` — не привязывать | | `bankDetailId` | number | ID привязываемого банковского реквизита клиента, `0` — не привязывать | | `mcRequisiteId` | number | ID реквизита вашей компании, `0` — не привязывать | | `mcBankDetailId` | number | ID банковского реквизита вашей компании, `0` — не привязывать | Полный список полей — [`GET /v1/requisite-links/fields`](./requisite-links/fields.md). ## Что нужно знать перед работой 1. **У связи нет отдельного числового `id`.** Связь определяется парой значений владельца — `entityTypeId` и `entityId`. Получение, обновление и удаление используют их в пути, регистрация передаёт их в теле. 2. **Регистрация требует все шесть полей.** `entityTypeId`, `entityId`, `requisiteId`, `bankDetailId`, `mcRequisiteId`, `mcBankDetailId` — передавайте `0` для тех, что не нужно привязывать. 3. **`0` означает пустую привязку, а не объект с нулевым ID.** Связь, у которой все четыре идентификатора равны `0`, — это заведённая связь без единой привязки. Она отличается от отсутствующей связи: на отсутствующую пару получение отвечает `404`. 4. **Владельцем может быть не только сделка или счёт.** Тот же набор полей работает для предложений и элементов смарт-процессов. Справочник значений `entityTypeId` — [Поля связи](./requisite-links/fields.md). 5. **Реквизит клиента должен принадлежать клиенту сделки.** Привязать `requisiteId` к сделке можно, только если у сделки выбран контакт или компания, которому этот реквизит принадлежит. Реквизиты вашей компании от клиента сделки не зависят. 6. **Связи вызываются собственными маршрутами.** Пара значений владельца вместо числового `id` не укладывается в общую форму Entity API, поэтому операции идут по путям `/v1/requisite-links/...` — по одному вызову на связь. В сводном [`POST /v1/batch`](/docs/batch) сущность `requisite-links` не участвует: такой вызов отклоняется до Битрикс24 с кодом `UNKNOWN_ENTITY` в `data.errors` по идентификатору вызова. Если в пакете есть другие рабочие вызовы, ответ остаётся `200`, а `400` приходит только когда отклонены все. ## Связанные сущности | Сущность | Эндпоинт | Назначение | |----------|----------|-----------| | Реквизиты | `GET /v1/requisites` | Источник `requisiteId` для связи. | | Банковские реквизиты | `GET /v1/bank-details` | Источник `bankDetailId` для связи. | | Шаблоны реквизитов | `GET /v1/requisite-presets` | Шаблон набора полей реквизита. | ## Типичный сценарий 1. Получить реквизит компании-клиента: [`GET /v1/requisites?filter[entityTypeId]=4&filter[entityId]=15`](./requisites/list.md). 2. Получить его банковский реквизит: [`GET /v1/bank-details`](./bank-details/list.md). 3. Зарегистрировать связь на счёт или сделку: [`POST /v1/requisite-links`](./requisite-links/register.md) с `requisiteId` и `bankDetailId`. ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Реквизиты компании для генерации документа](/docs/recipes/document-requisites) - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Справочник сущностей](/docs/entities-index) --- # Entity: Requisite Presets # Шаблоны реквизитов Шаблоны наборов полей реквизитов: «Организация», «ИП», «Физ. лицо», «Иностранное юрлицо». Шаблон определяет, какие поля доступны у реквизита, и служит источником `presetId` для создания реквизита через `POST /v1/requisites`. Битрикс24 API: `crm.requisite.preset.*` Скоуп: `crm` ## Операции - [Создать шаблон](./requisite-presets/create.md) — `POST /v1/requisite-presets` - [Список шаблонов](./requisite-presets/list.md) — `GET /v1/requisite-presets` - [Получить шаблон](./requisite-presets/get.md) — `GET /v1/requisite-presets/:id` - [Обновить шаблон](./requisite-presets/update.md) — `PATCH /v1/requisite-presets/:id` - [Удалить шаблон](./requisite-presets/delete.md) — `DELETE /v1/requisite-presets/:id` - [Поиск шаблонов](./requisite-presets/search.md) — `POST /v1/requisite-presets/search` - [Поля шаблонов](./requisite-presets/fields.md) — `GET /v1/requisite-presets/fields` - [Список полей шаблона](./requisite-presets/preset-fields/list.md) — `GET /v1/requisite-presets/:presetId/fields` - [Получить поле шаблона](./requisite-presets/preset-fields/get.md) — `GET /v1/requisite-presets/:presetId/fields/:id` - [Добавить поле в шаблон](./requisite-presets/preset-fields/create.md) — `POST /v1/requisite-presets/:presetId/fields` - [Обновить поле шаблона](./requisite-presets/preset-fields/update.md) — `PATCH /v1/requisite-presets/:presetId/fields/:id` - [Удалить поле шаблона](./requisite-presets/preset-fields/delete.md) — `DELETE /v1/requisite-presets/:presetId/fields/:id` - [Поля, доступные для добавления](./requisite-presets/preset-fields/available.md) — `GET /v1/requisite-presets/:presetId/fields/available` - [Схема поля шаблона](./requisite-presets/preset-fields/schema.md) — `GET /v1/requisite-presets/:presetId/fields/schema` ## Ключевые поля | Поле | Описание | |------|---------| | `name` | Название шаблона («Организация», «ИП», «Физ. лицо») | | `entityTypeId` | Тип сущности набора — всегда `8`, реквизит | | `countryId` | Страна набора полей, `1` — Россия | | `active` | Активен ли шаблон | | `sort` | Порядок сортировки в списке | Полный список полей — [`GET /v1/requisite-presets/fields`](./requisite-presets/fields.md). ## Что нужно знать перед работой 1. **Шаблон — это шаблон набора полей.** У шаблона «Организация» один набор (ИНН, КПП, ОГРН, директор), у «Физ. лица» — другой (ФИО, паспорт). Сам по себе шаблон не хранит значения — он задаёт структуру. 2. **`presetId` нужен для создания реквизита.** При `POST /v1/requisites` поле `presetId` обязательно и неизменяемо после создания. Список доступных шаблонов отдаёт `GET /v1/requisite-presets`. 3. **Состав полей шаблона настраивается отдельно.** Операции «полей шаблона» по пути `/v1/requisite-presets/:presetId/fields` добавляют и убирают поля в шаблоне. Эндпоинт `available` показывает, какие поля ещё можно добавить, `schema` — структуру строки поля. 4. **Формат ответов единый.** И сам шаблон (`name`, `entityTypeId`), и строки его полей (`id`, `fieldName`, `fieldTitle`, `inShortList`, `sort`) возвращаются в camelCase. Флаг `inShortList` приходит как `true`/`false`. Значения `fieldName` — это либо системные имена реквизитов Битрикс24 в верхнем регистре (`RQ_INN`, `RQ_COMPANY_NAME`), либо пользовательские поля (`UF_CRM_*`). ## Связанные сущности | Сущность | Эндпоинт | Назначение | |----------|----------|-----------| | Реквизиты | `POST /v1/requisites` | Используют `presetId` шаблона при создании — шаблон задаёт набор доступных полей реквизита. | | Банковские реквизиты | `GET /v1/bank-details?filter[entityId]=:requisiteId` | Банковские счета реквизита: Р/с, БИК, к/с, SWIFT, IBAN. | | Адреса | `GET /v1/addresses?filter[entityTypeId]=8&filter[entityId]=:requisiteId` | Адреса реквизита: юридический, фактический, для корреспонденции, доставки. | | Связи реквизитов | `POST /v1/requisite-links` | Привязка реквизита (и опционально банка) к счёту или предложению. | ## Типичный сценарий 1. Получить список шаблонов: [`GET /v1/requisite-presets`](./requisite-presets/list.md) — выбрать подходящий `id`. 2. Создать реквизит с этим шаблоном: [`POST /v1/requisites`](./requisites/create.md) с `presetId`. 3. При необходимости настроить состав полей шаблона: [`POST /v1/requisite-presets/:presetId/fields`](./requisite-presets/preset-fields/create.md) — добавить поле из [доступных](./requisite-presets/preset-fields/available.md). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | Список полей шаблона | `limit`/`offset` применяются на стороне Вайбкод | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Реквизиты компании для генерации документа](/docs/recipes/document-requisites) - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Справочник сущностей](/docs/entities-index) --- # Entity: Requisites # Реквизиты Управление реквизитами CRM: создание, получение, обновление, удаление, фильтрация. Реквизиты всегда привязаны к контакту или компании и содержат юридическую информацию (название, ИНН/КПП/ОГРН, директор, бухгалтер и т. д.). Битрикс24 API: `crm.requisite.*` Скоуп: `crm` ## Операции - [Создать реквизит](./requisites/create.md) — `POST /v1/requisites` - [Список реквизитов](./requisites/list.md) — `GET /v1/requisites` - [Получить реквизит](./requisites/get.md) — `GET /v1/requisites/:id` - [Обновить реквизит](./requisites/update.md) — `PATCH /v1/requisites/:id` - [Удалить реквизит](./requisites/delete.md) — `DELETE /v1/requisites/:id` - [Поиск реквизитов](./requisites/search.md) — `POST /v1/requisites/search` - [Поля реквизита](./requisites/fields.md) — `GET /v1/requisites/fields` - [Агрегация реквизитов](./requisites/aggregate.md) — `POST /v1/requisites/aggregate` ## Ключевые поля | Поле | Описание | |------|---------| | `entityTypeId` | Тип родительской сущности: `3` — контакт, `4` — компания | | `entityId` | ID контакта или компании, которому принадлежит реквизит | | `presetId` | ID [шаблона реквизитов](/docs/entities/requisite-presets) (задаёт набор доступных полей, неизменяем после создания) | | `rqName` / `rqInn` / `rqKpp` / `rqOgrn` | Основные реквизиты юрлица | | `rqCompanyName` / `rqCompanyFullName` / `rqDirector` / `rqAccountant` | Название и руководство | | `rqOkpo` / `rqOkved` / `rqOktmo` / `rqVatPayer` | Классификаторы и НДС | Полный список полей — [`GET /v1/requisites/fields`](./requisites/fields.md). ## Что нужно знать перед работой 1. **Шаблон определяет набор полей.** У шаблона «Организация» одни поля — ИНН, КПП, ОГРН, директор, у шаблона «Физ. лицо» другие — ФИО, паспорт, дата рождения. 2. **Для создания нужны 4 поля:** `entityTypeId`, `entityId`, `presetId`, `name`. `presetId` получается из [`GET /v1/requisite-presets`](/docs/entities/requisite-presets) — программное создание реквизита больше не требует копирования ID из UI Битрикса. 3. **Поля схемы возвращаются в camelCase.** Это касается и полей международных шаблонов — `rqEdrpou`, `rqKbe`, `rqRegon`, `rqSiret`, `rqCnpj`. Фильтр и сортировка идут по camelCase-имени. Пользовательские поля `UF_CRM_*` возвращаются в исходном регистре Битрикс24. См. [Поля реквизита](./requisites/fields.md). Чтобы получить только поля своего шаблона — добавьте `?presetId=N` к `GET /v1/requisites/fields`. ## Связанные сущности Полноценная работа с реквизитами (счета, договоры, печатные формы) требует сопутствующих сущностей — все обёрнуты в API Вайбкод: | Сущность | Эндпоинт | Назначение | |----------|----------|-----------| | [Шаблоны реквизитов](/docs/entities/requisite-presets) | `GET /v1/requisite-presets` | Шаблоны реквизитов — «Организация», «ИП», «Физ. лицо», «Иностранное юрлицо». Источник `presetId` для создания реквизита. На странице шаблона — состав его полей. | | [Банковские реквизиты](/docs/entities/bank-details) | `GET /v1/bank-details?filter[entityId]=:requisiteId` | Р/с, БИК, к/с, SWIFT, IBAN. Без них нельзя выставить счёт на оплату. | | [Адреса](/docs/entities/addresses) | `GET /v1/addresses?filter[entityTypeId]=8&filter[entityId]=:requisiteId` | Юридический, фактический, для корреспонденции, доставки. Композитный ключ `(typeId, entityTypeId, entityId)`. | | [Связи реквизитов](/docs/entities/requisite-links) | `POST /v1/requisite-links` | Привязка конкретного реквизита (и опционально банка) к счёту/предложению. Нужно компаниям с несколькими реквизитами. | | Пользовательские UF-поля | `POST /v1/userfields/requisites` | UF_CRM_* поля на реквизитах — добавить, изменить, удалить. | ## Типичный сценарий 1. Найти контакт или компанию: [`GET /v1/contacts`](/docs/entities/contacts) / [`GET /v1/companies`](/docs/entities/companies). 2. Посмотреть её реквизиты: [`GET /v1/requisites?filter[entityTypeId]=4&filter[entityId]=15`](./requisites/list.md). 3. Создать новый или обновить существующий: [`POST /v1/requisites`](./requisites/create.md) / [`PATCH /v1/requisites/:id`](./requisites/update.md). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | `offset` на больших выборках | рекомендуется `limit ≤ 500` при `offset ≥ 2500` | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Реквизиты компании для генерации документа](/docs/recipes/document-requisites) - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Справочник сущностей](/docs/entities-index) --- # Entity: Sites # Сайты Управление сайтами на платформе Битрикс24: создание, получение, обновление, удаление, поиск, агрегация. Сайт — это контейнер страниц одного типа: `PAGE` — лендинг, `STORE` — интернет-магазин, `KNOWLEDGE` — база знаний 2.0. У каждого сайта свой домен или поддомен на портале, символьный код, шаблон и набор страниц. База знаний 2.0 создаётся и управляется через те же методы с дополнительным параметром `scope: "KNOWLEDGE"` (см. [создание](./sites/create.md)). Битрикс24 API: `landing.site.*` Скоуп: `landing` ## Операции - [Создать сайт](./sites/create.md) — `POST /v1/sites` - [Список сайтов](./sites/list.md) — `GET /v1/sites` - [Получить сайт](./sites/get.md) — `GET /v1/sites/:id` - [Обновить сайт](./sites/update.md) — `PATCH /v1/sites/:id` - [Удалить сайт](./sites/delete.md) — `DELETE /v1/sites/:id` - [Поиск сайтов](./sites/search.md) — `POST /v1/sites/search` - [Поля сайта](./sites/fields.md) — `GET /v1/sites/fields` - [Агрегация сайтов](./sites/aggregate.md) — `POST /v1/sites/aggregate` ## Поля ### Изменяемые поля Принимаются при [создании](./sites/create.md) и [обновлении](./sites/update.md). | Поле | Тип | Описание | |------|-----|---------| | `title` | string | Название сайта, до 255 символов | | `code` | string | Символьный код сайта в URL. Если оставить пустым при создании — генерируется из `title`. Если код состоит только из цифр, добавляется префикс `site` | | `type` | string | Тип сайта: `PAGE` — лендинг, `STORE` — интернет-магазин, `KNOWLEDGE` — база знаний 2.0. Для `KNOWLEDGE` при создании и изменении нужен `scope: "KNOWLEDGE"`. В ответах у сайтов, созданных вне API, встречаются и другие значения — см. «Что нужно знать перед работой» | | `active` | boolean | Только для чтения: через API не устанавливается, запрос с этим полем отклоняется с `400 READONLY_FIELD`. Новый сайт неактивен, активируется при публикации в интерфейсе портала Битрикс24 | | `domainId` | number | Идентификатор домена. Если не передать при создании — адрес формируется из `code` | | `description` | string \| null | Описание сайта, до 255 символов. В ответе приходит `null`, если не задано | | `xmlId` | string \| null | Внешний идентификатор, до 255 символов. В ответе приходит `null`, если не задан | | `landingIdIndex` | number \| null | Идентификатор главной страницы. Задаётся только в обновлении — после создания страниц. `null`, если главная не назначена | | `landingId404` | number \| null | Идентификатор страницы ошибки 404. Задаётся только в обновлении. Если не назначена — `0` или `null` | | `landingId503` | number \| null | Идентификатор страницы ошибки 503. Задаётся только в обновлении. Если не назначена — `0` или `null` | ### Только для чтения Приходят в ответе, но не принимаются при создании и обновлении. | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор сайта | | `deleted` | string | Признак нахождения в корзине: `"Y"` / `"N"`. Доступен в фильтре (`filter[deleted]=Y`) | | `createdById` | number | Идентификатор создавшего пользователя | | `modifiedById` | number | Идентификатор пользователя, изменившего сайт последним | | `dateCreate` | datetime | Дата создания. Формат локали Битрикс24, не ISO 8601 — см. «Что нужно знать перед работой» | | `dateModify` | datetime | Дата последнего изменения. Формат локали Битрикс24, не ISO 8601 | | `tplId` | number | Идентификатор шаблона сайта | | `tplCode` | string \| null | Символьный код шаблона сайта. `null`, если у шаблона нет кода | | `smnSiteId` | string \| null | Идентификатор связанного сайта «Управление сайтом» типа `SMN`. `null` у обычных сайтов | | `lang` | string \| null | Код языка сайта, например `ru`. `null`, если язык не задан | | `special` | string | Служебный признак Битрикс24: `"Y"` / `"N"` | | `version` | number | Версия внутренней структуры сайта | ## Что нужно знать перед работой 1. **Тело запроса плоское.** При создании и обновлении передавайте поля прямо в корне JSON: `{"title": "...", "code": "..."}`. Обёртка `fields` не нужна. 2. **Удалить можно только пустой сайт.** Если у сайта есть хотя бы одна страница (включая страницы в корзине), `DELETE /v1/sites/:id` вернёт ошибку `BITRIX_ERROR` с описанием «Сайт содержит страницы». Сначала удалите страницы, затем сам сайт. 3. **Видимость зависит от прав пользователя.** Список и агрегация возвращают только те сайты, к которым у владельца API-ключа есть право «просмотр». Если на портале есть сайты, но ответ пустой — проверьте права пользователя, под которым выпущен ключ. 4. **Корзина — `filter[deleted]=Y`.** По умолчанию удалённые сайты не возвращаются. Чтобы получить сайты в корзине, добавьте в фильтр `deleted=Y`. Значения — `Y` или `N`. 5. **Полный список полей — [`GET /v1/sites/fields`](./sites/fields.md).** Эндпоинт возвращает карту всех 22 полей с типом, признаком `readonly`, подписью, описанием и признаком `nullable` у полей, которые могут прийти со значением `null`. У поля `type` дополнительно приходит перечень допустимых значений `enum`. Рядом с картой полей возвращается список `aggregatable` — поля, по которым доступна группировка в агрегации. Перечень с описаниями приведён в разделе «Поля» выше. 6. **Формат дат — локаль-зависимый, не ISO 8601.** Поля `dateCreate` и `dateModify` приходят строкой в локальном формате портала: на RU-локали — `ДД.ММ.ГГГГ ЧЧ:ММ:СС` (`30.12.2021 12:30:52`), на EN-локали — `MM/DD/YYYY hh:mm:ss am/pm` (`04/22/2020 02:39:17 pm`). Значение возвращается как есть, без приведения к ISO. `new Date(value)` вернёт `Invalid Date` либо перепутает день и месяц — не разбирайте дату по фиксированному шаблону, ориентируйтесь на региональные настройки портала. 7. **Поле `type` в ответах шире, чем при создании.** Через API создаются сайты типов `PAGE`, `STORE`, `KNOWLEDGE`. В ответах у сайтов, собранных другими средствами, встречаются и другие значения — `VIBE` (сайт из конструктора) и `SMN` (связка с модулем «Управление сайтом»). Эти два типа возвращаются только для чтения. Полный перечень значений теперь покрыт схемой — [`GET /v1/sites/fields`](./sites/fields.md) отдаёт их в `type.enum` с подписями. 8. **Отсутствие значения — `null` или `0`.** Значение может отсутствовать у восьми полей — у них в схеме стоит `nullable`. Строковые `description`, `xmlId`, `tplCode`, `smnSiteId`, `lang` приходят как `null`. Числовые идентификаторы страниц `landingIdIndex`, `landingId404`, `landingId503` — как `0` или `null`. Проверяйте оба варианта. 9. **Фильтр по `code` — со слешами.** В фильтре значение `code` сравнивается с хранимой формой, обрамлённой слешами: `filter[code]=/my-code/` находит сайт, голое `filter[code]=my-code` — нет. Используйте то значение `code`, которое сайт отдаёт в ответе. ## Связанные сущности | Сущность | Эндпоинт | Назначение | |----------|----------|-----------| | Страницы | [`GET /v1/pages`](/docs/entities/pages) | Страницы сайта. Получите список страниц с `filter[siteId]=:id` перед удалением сайта или для редактирования содержимого. | ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Постраничный переход | через `offset` — окно `[offset, offset + limit)` | | `offset` | поддерживается, вместе с `limit` задаёт окно выборки | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Справочник сущностей](/docs/entities-index) --- # Entity: Smart Processes # Типы смарт-процессов Управление типами смарт-процессов: создание, получение, обновление, удаление, поиск. Тип — это шаблон (определение сущности), а не запись в нём. Для работы с элементами внутри типа используйте [`/v1/items/:entityTypeId`](/docs/entities/items). Битрикс24 API: `crm.type.*` Скоуп: `crm` ## Операции - [Создать тип](./smart-processes/create.md) — `POST /v1/smart-processes` - [Список типов](./smart-processes/list.md) — `GET /v1/smart-processes` - [Получить тип](./smart-processes/get.md) — `GET /v1/smart-processes/:entityTypeId` - [Обновить тип](./smart-processes/update.md) — `PATCH /v1/smart-processes/:entityTypeId` - [Удалить тип](./smart-processes/delete.md) — `DELETE /v1/smart-processes/:entityTypeId` - [Поиск типов](./smart-processes/search.md) — `POST /v1/smart-processes/search` - [Поля типа](./smart-processes/fields.md) — `GET /v1/smart-processes/fields` - [Агрегация типов](./smart-processes/aggregate.md) — `POST /v1/smart-processes/aggregate` ## Ключевые поля | Поле | Описание | |------|---------| | `entityTypeId` | **Главный идентификатор типа.** Используется во всех запросах к элементам через `/v1/items/:entityTypeId`. Генерируется при создании автоматически, неизменяем | | `title` | Название типа, которое видят пользователи в интерфейсе Битрикс24 | | `isCategoriesEnabled` | Включены ли свои воронки и туннели продаж | | `isStagesEnabled` | Включены ли свои стадии и канбан | | `isClientEnabled` | Есть ли поле «Клиент» (контакты и компании) | | `isLinkWithProductsEnabled` | Можно ли привязывать товары каталога | | `relations` | Связи с другими сущностями CRM (сделки, контакты, другие смарт-процессы) | Полный список из 27 полей — [Поля типа](./smart-processes/fields.md). ## Что нужно знать перед работой 1. **Тип ≠ элемент.** `/v1/smart-processes` управляет **определениями** (шаблонами). Для записей внутри типа — `/v1/items/:entityTypeId`. 2. **`entityTypeId` — ключ связи с элементами.** После создания типа сохраните его и передавайте во все запросы к элементам. Изменить `entityTypeId` нельзя. 3. **Новый тип не инициализирован.** Сразу после `POST /v1/smart-processes` поле `isInitialized: false`. Для готовности к работе добавьте воронки и стадии через [`/v1/categories/:entityTypeId`](/docs/entities/categories). 4. **`relations` двунаправленные.** Связь, созданная в `parent` одного типа, автоматически появится в `child` у связанной сущности. ## Типичный сценарий 1. Посмотреть, какие типы уже есть: [`GET /v1/smart-processes`](./smart-processes/list.md). 2. Создать новый тип со всеми нужными возможностями: [`POST /v1/smart-processes`](./smart-processes/create.md) с флагами `isStagesEnabled`, `isCategoriesEnabled` и т. д. 3. Сохранить `entityTypeId` из ответа — он понадобится для всех дальнейших вызовов. 4. Настроить воронки для типа: [`POST /v1/categories/:entityTypeId`](/docs/entities/categories). 5. Работать с элементами внутри типа: [`/v1/items/:entityTypeId`](/docs/entities/items) — CRUD, поиск, товары, пользовательские поля. ## Лимиты | Лимит | Значение | |-------|----------| | Максимум типов на портал | Зависит от тарифа Битрикс24 (при превышении — `CREATE_DYNAMIC_TYPE_RESTRICTED`) | | Диапазон `entityTypeId` при автогенерации | Чётные числа `≥ 1030` | | Диапазон `entityTypeId` при явной передаче | от `128` до `191` — `≥ 128` и `< 192` | | Удаление типа с элементами | Запрещено — сначала удалите элементы через [`DELETE /v1/items/:entityTypeId/:id`](/docs/entities/items) | | Ограничение частоты | Общее для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Элементы смарт-процессов](/docs/entities/items) - [Воронки и стадии](/docs/entities/categories) - [Пользовательские поля](/docs/userfields) - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entities-index) --- # Entity: Statuses # Справочники CRM Стадии сделок, источники, типы контактов, отрасли и другие классификаторы. Центральная сущность для enum-значений всей CRM. Bitrix24 API: `crm.status.*` Скоуп: `crm` Для получения конкретного типа используйте фильтр: `?filter[entityId]=DEAL_STAGE` ## Операции - [Создать запись](./statuses/create.md) — `POST /v1/statuses` - [Список записей](./statuses/list.md) — `GET /v1/statuses` - [Получить запись](./statuses/get.md) — `GET /v1/statuses/:id` - [Обновить запись](./statuses/update.md) — `PATCH /v1/statuses/:id` - [Удалить запись](./statuses/delete.md) — `DELETE /v1/statuses/:id` - [Поиск записей справочника](./statuses/search.md) — `POST /v1/statuses/search` - [Поля справочника](./statuses/fields.md) — `GET /v1/statuses/fields` - [Агрегация записей справочника](./statuses/aggregate.md) — `POST /v1/statuses/aggregate` ## Типы справочников (entityId) | entityId | Описание | |----------|----------| | `STATUS` | Статусы лидов | | `SOURCE` | Источники | | `CONTACT_TYPE` | Типы контактов | | `COMPANY_TYPE` | Типы компаний | | `INDUSTRY` | Отрасли | | `DEAL_STAGE` | Стадии общей воронки (categoryId 0) | | `DEAL_STAGE_{N}` | Стадии воронки N (напр. `DEAL_STAGE_3`) | | `QUOTE_STATUS` | Статусы предложений | | `HONORIFIC` | Обращения (контакты) | | `EMPLOYEES` | Количество сотрудников (компании) | | `DEAL_TYPE` | Типы сделок | --- # Entity: Storages # Хранилища Доступ к хранилищам Битрикс24.Диска: личные диски сотрудников, диски рабочих групп и общий диск портала. Раздел только для чтения: хранилища создаются и удаляются на стороне Битрикс24.Диска, через API доступны список, поиск, получение по идентификатору и схема полей. Битрикс24 API: `disk.storage.*` Скоуп: `disk` ## Операции - [Список хранилищ](./storages/list.md) — `GET /v1/storages` - [Получить хранилище](./storages/get.md) — `GET /v1/storages/:id` - [Поиск хранилищ](./storages/search.md) — `POST /v1/storages/search` - [Поля хранилища](./storages/fields.md) — `GET /v1/storages/fields` ## Ключевые поля | Поле | Описание | |------|---------| | `id` | Идентификатор хранилища | | `name` | Название хранилища | | `entityType` | Тип владельца: `user`, `group`, `common` | | `entityId` | Идентификатор владельца. Строка — у общего диска нечисловая, например `shared_files_s1` | | `rootFolderId` | Идентификатор корневой папки хранилища | Полный список полей — [`GET /v1/storages/fields`](./storages/fields.md). ## Что нужно знать перед работой 1. **Раздел только для чтения.** Хранилища создаются и удаляются на стороне Битрикс24.Диска: личный диск есть у каждого сотрудника, диск рабочей группы создаётся вместе с группой, общий диск один на портал. Операций создания, обновления и удаления через API нет — доступны список, поиск, получение по идентификатору и схема полей. 2. **Тип владельца — поле `entityType`.** Значения: `user` — личный диск сотрудника, `group` — диск рабочей группы, `common` — общий диск портала. Поле `entityId` указывает на владельца этого типа. 3. **`entityId` — строка, не число.** У личных дисков и дисков групп это числовой идентификатор в виде строки, у общего диска значение нечисловое, например `shared_files_s1`. Не приводите его к числу. 4. **`rootFolderId` — корневая папка хранилища.** От неё доступно остальное содержимое Диска — папки и файлы. Имена полей в ответе приходят в camelCase. Поле `code` на проверенных порталах приходит как `null`. ## Типичный сценарий 1. Получить список хранилищ: [`GET /v1/storages`](./storages/list.md). Сузить по типу владельца — `filter[entityType]=group`. 2. Открыть конкретное хранилище по идентификатору: [`GET /v1/storages/:id`](./storages/get.md). 3. Взять `rootFolderId` и получить содержимое: [`GET /v1/folders?parentId={rootFolderId}`](/docs/entities/folders) — папки, затем [`GET /v1/files?folderId={folderId}`](/docs/entities/files) — файлы в папке. ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей за ответ | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | Полная выборка | выборки больше 5000 записей читаются постранично через `offset` | | Сортировка | порядок меняют `id`, `name`, `entityType`, `entityId`, `rootFolderId`. Поля `code` и `module` метод принимает, но на проверенных аккаунтах у всех хранилищ там одно значение, поэтому порядок по ним не меняется | | Порядок по умолчанию | без сортировки — по возрастанию `id`; к вашей сортировке `id` добавляется последним ключом, поэтому постраничный обход не теряет строки | | Фильтрация | по точному совпадению значений полей | | Batch-запросы | до 50 операций чтения в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Справочник сущностей](/docs/entities-index) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Папки](/docs/entities/folders) - [Файлы](/docs/entities/files) --- # Entity: Task Comments # Комментарии задач Комментарии — вложенный ресурс задачи. У каждого комментария есть автор, текст и время создания. Базовый путь — `/v1/tasks/:taskId/comments`. Все операции требуют существующей задачи (`:taskId`) на портале. Битрикс24 API: `tasks.task.chat.message.*`, `task.commentitem.*` Скоуп: `task` ## Операции - [Создать комментарий](./task-comments/create.md) — `POST /v1/tasks/:taskId/comments` - [Список комментариев](./task-comments/list.md) — `GET /v1/tasks/:taskId/comments` - [Получить комментарий](./task-comments/get.md) — `GET /v1/tasks/:taskId/comments/:id` - [Обновить комментарий](./task-comments/update.md) — `PATCH /v1/tasks/:taskId/comments/:id` - [Удалить комментарий](./task-comments/delete.md) — `DELETE /v1/tasks/:taskId/comments/:id` - [Поля комментария](./task-comments/fields.md) — `GET /v1/tasks/:taskId/comments/fields` - [Пакет операций](./task-comments/comments-batch.md) — `POST /v1/tasks/:taskId/comments/batch` ## Ключевые поля | Поле | Описание | |------|---------| | `id` | Идентификатор комментария | | `taskId` | ID родительской задачи (берётся из пути URL) | | `authorId` | Автор. Список сотрудников: `GET /v1/users` | | `message` | Текст комментария, до 65 535 символов. Поддерживает BB-код `[USER=ID]Имя[/USER]`, `[B]...[/B]`, `[QUOTE]...[/QUOTE]` и другие | | `createdAt` | Дата и время создания, UTC ISO 8601 | Полный список полей — [`GET /v1/tasks/:taskId/comments/fields`](./task-comments/fields.md). ## Что нужно знать перед работой 1. **У задачи две карточки.** В Битрикс24 параллельно живут две версии карточки задачи: «новая» (на базе чата) и «старая» (с блоком комментариев внутри самой карточки). Вызов одинаковый, но под капотом API сам выбирает рабочий путь в зависимости от того, как настроен портал. Различия видны в PATCH/DELETE — см. ниже — и в списке комментариев: фильтр и сортировка по `AUTHOR_NAME` или `AUTHOR_EMAIL` принимаются только на старой карточке, а `offset` учитывается и `meta.truncated` приходит только на новой при запросе с `filter` или сортировкой не по `ID`. Подробности — [Список комментариев](./task-comments/list.md). 2. **PATCH и DELETE на новой карточке возвращают 410 GONE.** На новой карточке Битрикс24 нет публичного API обновления / удаления комментариев — он отправляет только новые сообщения. На порталах со старой карточкой обновление и удаление продолжают работать без изменений. API возвращает `410 GONE` с текстом и подсказкой, если попал на новую карточку, и `200`/`204` — на старой. 3. **POST возвращает реальный `id` сообщения.** На новой карточке после отправки комментария API выполняет дополнительный поиск по чату задачи и возвращает фактический идентификатор. В редком случае (OAuth-приложение + несколько одинаковых сообщений подряд в одном чате) `id` может прийти как `null` — тогда найдите комментарий через `GET /v1/tasks/:taskId/comments`. 4. **Системные сообщения не возвращаются.** Чат задачи содержит уведомления типа «задача поставлена», «срок изменён» — `GET /v1/tasks/:taskId/comments` их пропускает. В списке только пользовательские комментарии. 5. **`meta.total` считается двумя способами.** На запросе без `filter` и с сортировкой по `ID` это оценка: если в текущей странице меньше элементов, чем `limit`, то `total` равен числу элементов, иначе — `+1`. Опирайтесь на `meta.hasMore` для пагинации. На новой карточке с `filter` или сортировкой не по `ID` — точное число подошедших под фильтр комментариев в пределах просмотренного окна, а `meta.truncated: true` говорит, что окно исчерпано и за его границей осталась часть истории. 6. **Плоский путь `/v1/task-comments` не существует.** Все операции — только в виде `/v1/tasks/:taskId/comments/...`. Вызов без префикса вернёт `400 WRONG_PATH` с подсказкой. ## Типичный сценарий 1. Найти задачу: [`GET /v1/tasks`](./tasks/list.md) или прямой ID из создания задачи. 2. Добавить комментарий: [`POST /v1/tasks/:taskId/comments`](./task-comments/create.md) с `message`. 3. Показать обсуждение: [`GET /v1/tasks/:taskId/comments`](./task-comments/list.md) — поддерживает `limit`, сортировку и фильтр по `ID`, `AUTHOR_ID` или `POST_DATE` на обеих карточках. 4. Если нужно массовое добавление — [`POST /v1/tasks/:taskId/comments/batch`](./task-comments/comments-batch.md) (до 50 сообщений). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум символов в `message` | 65 535 | | Максимум элементов в одном batch-вызове | 50 | | Размер страницы `limit` | до 200 | | Rate limit | общий для API — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Задачи](./tasks.md) - [Учёт времени задач](./tasks/time.md) - [Сотрудники](/docs/entities/users) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Entity: Tasks # Задачи Управление задачами портала: создание, чтение, обновление, удаление, фильтрация, агрегация. Задача — единица работы с ответственным, постановщиком, сроком и статусом. У одной задачи могут быть комментарии и записи учёта времени — это отдельные вложенные ресурсы. Битрикс24 API: `tasks.task.*` Скоуп: `tasks` ## Операции - [Создать задачу](./tasks/create.md) — `POST /v1/tasks` - [Список задач](./tasks/list.md) — `GET /v1/tasks` - [Получить задачу](./tasks/get.md) — `GET /v1/tasks/:id` - [Обновить задачу](./tasks/update.md) — `PATCH /v1/tasks/:id` - [Удалить задачу](./tasks/delete.md) — `DELETE /v1/tasks/:id` - [Поиск задач](./tasks/search.md) — `POST /v1/tasks/search` - [Поля задачи](./tasks/fields.md) — `GET /v1/tasks/fields` - [Агрегация задач](./tasks/aggregate.md) — `POST /v1/tasks/aggregate` - [Добавить в избранное](./tasks/favorite.md) — `POST /v1/tasks/:taskId/favorite` - [Убрать из избранного](./tasks/unfavorite.md) — `DELETE /v1/tasks/:taskId/favorite` - [Закрепить задачу](./tasks/pin.md) — `POST /v1/tasks/:taskId/pin` - [Открепить задачу](./tasks/unpin.md) — `DELETE /v1/tasks/:taskId/pin` У задачи есть вложенные ресурсы со своими CRUD-операциями: [Комментарии задач](./task-comments.md) (`/v1/tasks/:taskId/comments`), [Учёт времени задач](./tasks/time.md) (`/v1/tasks/:taskId/time`) и [Чат задачи](./tasks/chat.md) (`GET /v1/tasks/:taskId/chat/messages`). Скрам-размещение задачи (бэклог/спринт, эпик, story points) — отдельный раздел [Scrum API](/docs/scrum). История изменений задачи и текущие стадии канбана доступны отдельными эндпоинтами для чтения: [История изменений задачи](/docs/task-history) (`GET /v1/tasks/:taskId/history`) и [Стадии канбана задач](/docs/task-stages) (`GET /v1/tasks/stages/:entityId`). ## Ключевые поля | Поле | Описание | |------|---------| | `title` | Название задачи | | `description` | Текст задачи (поддерживает BB-код, флаг `descriptionInBbcode`) | | `responsibleId` | Ответственный. Список сотрудников: `GET /v1/users` | | `createdBy` | Постановщик. По умолчанию — пользователь ключа. Можно передать и при создании, и при обновлении, в пределах прав B24-пользователя. Список сотрудников: `GET /v1/users` | | `status` | Статус задачи (число). Расшифровка значений: `GET /v1/tasks/fields` → `fields.status.enum` | | `priority` | Приоритет (число). Расшифровка значений: `GET /v1/tasks/fields` → `fields.priority.enum` | | `deadline` | Крайний срок (ISO 8601) | | `groupId` | Рабочая группа. Список: `GET /v1/workgroups` | Полный список полей — [`GET /v1/tasks/fields`](./tasks/fields.md). ## Что нужно знать перед работой 1. **Минимум для создания:** `title` и `responsibleId`. Если ответственный не указан, портал возвращает ошибку «Не указан исполнитель». 2. **Статус и приоритет — числовые коды**, а не строки. Полная таблица соответствий приходит в ответе `GET /v1/tasks/fields` в поле `fields.status.enum` / `fields.priority.enum`. Например, `status: 2` — задача ждёт выполнения, `status: 5` — завершена. 3. **`realStatus` — имя только для ФИЛЬТРА, в ответах его нет.** `status` (виртуальный) приходит и в списке, и в карточке. `subStatus` приходит **только в списке** — карточка `GET /v1/tasks/:id` его НЕ возвращает (под-статус просрочки `-1`/`-2`/`-3` читается только из списка). Для просроченных и почти просроченных задач `status`/`subStatus` принимают значения `-1` / `-2` / `-3` поверх реальных `1..7`. `REAL_STATUS` — фильтруемое поле B24 (реальный хранимый статус, всегда `1..7`). Ключа `realStatus` в JSON-ответе не бывает — читайте `status` + `subStatus`. Из этого выходит ловушка фильтрации: запрос `?filter[STATUS][]=2&filter[STATUS][]=3&filter[STATUS][]=4` тихо теряет просроченные задачи — у них `STATUS = -2`, хотя `REAL_STATUS` всё ещё `2`. Рецепты по сценариям: - «Активные без просроченных»: `filter[STATUS][]=2&filter[STATUS][]=3&filter[STATUS][]=4`. - «Активные включая просроченные»: `filter[REAL_STATUS][]=2&filter[REAL_STATUS][]=3&filter[REAL_STATUS][]=4`. - «Только просроченные»: `filter[STATUS]=-2`. 4. **Числовые поля сериализуются строками.** В ответах списка и одиночной задачи поля-идентификаторы (`id`, `responsibleId`, `createdBy`, `groupId`) и числовые перечисления (`status`, `priority`) приходят как строки, например `"id": "289"`, `"status": "2"`. Конвертация на стороне клиента — простой `Number(...)`. 5. **Даты в собственном часовом поясе портала.** Поля `createdDate`, `changedDate`, `closedDate`, `deadline` и подобные приходят в формате ISO 8601 со смещением (`2026-05-12T11:46:12+03:00`), а не в UTC. Для расчётов приводите к `Date` или `Date.parse`. 6. **Пользователи внутри задачи.** Поля `creator` и `responsible` приходят встроенно как объекты вида `{ id, name, link, icon, workPosition }` — отдельный запрос на профили не нужен. 7. **`accomplices` и `auditors` — массивы строковых идентификаторов** пользователей (соисполнители и наблюдатели). Если задача только что создана и в ней нет соисполнителей и наблюдателей, поля приходят пустыми массивами. ## Типичный сценарий 1. Найти ответственного: [`GET /v1/users`](/docs/entities/users) (или фильтрованный поиск с нужным именем). 2. Создать задачу: [`POST /v1/tasks`](./tasks/create.md) с `title` и `responsibleId`. 3. Дополнить детали: [`PATCH /v1/tasks/:id`](./tasks/update.md) — `deadline`, `priority`, `description`, `auditors`. 4. Зафиксировать прогресс — комментарий: [`POST /v1/tasks/:taskId/comments`](./task-comments/create.md). 5. Учесть время: [`POST /v1/tasks/:taskId/time`](./tasks/time/create.md). 6. Закрыть задачу: [`PATCH /v1/tasks/:id`](./tasks/update.md) → `status: 5`. ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | `offset` на больших выборках | рекомендуется `limit ≤ 500` при `offset ≥ 2500` | | Разбиение по временны́м окнам для больших выборок | `POST /v1/tasks/search` с `autoWindow: true` | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Комментарии задач](./task-comments.md) - [Учёт времени задач](./tasks/time.md) - [Чек-лист задачи](./tasks/checklist.md) - [История изменений задачи](/docs/task-history) - [Стадии канбана задач](/docs/task-stages) - [Справочник сущностей](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Entity: Timelines # Комментарии таймлайна Управление комментариями таймлайна CRM: запись заметок оператора, истории переговоров и прочего контекста к сделкам, лидам, контактам, компаниям и другим сущностям. Каждый комментарий привязан к конкретной записи CRM через пару `entityType` + `entityId`. Битрикс24 API: `crm.timeline.comment.*` Скоуп: `crm` ## Операции - [Добавить комментарий](./timelines/create.md) — `POST /v1/timelines` - [Список комментариев](./timelines/list.md) — `GET /v1/timelines` - [Получить комментарий](./timelines/get.md) — `GET /v1/timelines/:id` - [Обновить комментарий](./timelines/update.md) — `PATCH /v1/timelines/:id` - [Удалить комментарий](./timelines/delete.md) — `DELETE /v1/timelines/:id` - [Поиск комментариев](./timelines/search.md) — `POST /v1/timelines/search` - [Поля комментария](./timelines/fields.md) — `GET /v1/timelines/fields` - [Скачать вложение](./timelines/file-download.md) — `GET /v1/timelines/:commentId/files/:fileRef/download` ## Закрепление, привязки, заметки Операции Bitrix24 семейств `crm.timeline.item.*`, `crm.timeline.bindings.*`, `crm.timeline.note.*` универсальны — работают с любым элементом таймлайна по `id + ownerTypeId + ownerId`. Поэтому к комментариям применимы те же действия, что и к лог-записям. Ниже — копии 8 эндпоинтов из раздела [`/v1/timeline-logs`](/docs/timeline-logs), смонтированные на корне `/v1/timelines`: | Метод | Путь | B24-метод | Назначение | |------|------|-----------|------------| | POST | `/v1/timelines/:id/pin` | `crm.timeline.item.pin` | Закрепить комментарий поверх таймлайна | | POST | `/v1/timelines/:id/unpin` | `crm.timeline.item.unpin` | Снять закрепление | | POST | `/v1/timelines/:id/bind` | `crm.timeline.bindings.bind` | Дополнительно привязать комментарий к другой сущности (например, контакту) | | POST | `/v1/timelines/:id/unbind` | `crm.timeline.bindings.unbind` | Снять одну из привязок | | GET | `/v1/timelines/:id/bindings` | `crm.timeline.bindings.list` | Получить все привязки комментария | | POST | `/v1/timelines/:id/note` | `crm.timeline.note.save` | Сохранить заметку (текстовое примечание) на комментарии | | GET | `/v1/timelines/:id/note` | `crm.timeline.note.get` | Прочитать заметку | | DELETE | `/v1/timelines/:id/note` | `crm.timeline.note.delete` | Удалить заметку | Полные сигнатуры запросов / ответов и примеры — в зеркале раздела [`/v1/timeline-logs`](/docs/timeline-logs): [pins](/docs/timeline-logs/pins), [bindings](/docs/timeline-logs/bindings), [notes](/docs/timeline-logs/notes). Тело запроса, формат ответа и коды ошибок идентичны — отличается только префикс пути. ## Ключевые поля | Поле | Описание | |------|---------| | `entityType` | Тип родительской записи CRM: `deal`, `lead`, `contact`, `company` или `DYNAMIC_` для смарт-процессов (например `DYNAMIC_174`). Обязателен при создании и в фильтре | | `entityId` | ID родительской записи. Источник зависит от типа: `GET /v1/deals`, `GET /v1/leads`, `GET /v1/contacts`, `GET /v1/companies`, `GET /v1/items/:entityTypeId` (элементы смарт-процессов). Обязателен при создании и в фильтре | | `comment` | Текст комментария. Обязателен при создании | | `authorId` | ID автора. Данные пользователя по ID: `GET /v1/users/:id` | | `createdAt` | Дата создания (только чтение) | Полный список полей — [`GET /v1/timelines/fields`](./timelines/fields.md). ## Что нужно знать перед работой 1. **Фильтр по `entityType` + `entityId` обязателен.** Список комментариев выбирается только в контексте конкретной родительской записи — глобального списка «всех комментариев портала» нет. Запрос без этих полей возвращает `400 MISSING_REQUIRED_FILTER`. 2. **Для создания нужно 3 поля:** `entityType`, `entityId`, `comment`. Автор проставляется по владельцу API-ключа, дата — сервером. 3. **Комментарий обновляется по `id`**, а `entityType` и `entityId` фиксируются при создании и после обновлению не подлежат. 4. **Значения `entityType` — строковые идентификаторы CRM-типов.** Числовые коды CRM (`entityTypeId`) для `entityType` не подходят: они возвращают `BITRIX_ERROR Access denied.`. Используйте `deal`, `lead`, `contact`, `company` или `DYNAMIC_` для смарт-процессов (например, `DYNAMIC_174` для смарт-процесса с `entityTypeId: 174` из [`GET /v1/smart-processes`](/docs/entities/smart-processes/list)). В ответе API `entityType` возвращается в нижнем регистре (`dynamic_174`). ## Типичный сценарий 1. Найти родительскую запись: [`GET /v1/deals`](/docs/entities/deals/list), [`GET /v1/leads`](/docs/entities/leads/list), [`GET /v1/contacts`](/docs/entities/contacts), [`GET /v1/companies`](/docs/entities/companies) или [`GET /v1/items/:entityTypeId`](/docs/entities/items/list) для элементов смарт-процессов. 2. Посмотреть её комментарии: [`GET /v1/timelines?filter[entityType]=deal&filter[entityId]=741`](./timelines/list.md). 3. Добавить новый комментарий: [`POST /v1/timelines`](./timelines/create.md). 4. При необходимости изменить текст: [`PATCH /v1/timelines/:id`](./timelines/update.md), удалить: [`DELETE /v1/timelines/:id`](./timelines/delete.md). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | `offset` на больших выборках | рекомендуется `limit ≤ 500` при `offset ≥ 2500` | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Сделки](./deals.md) - [Лиды](./leads.md) - [Контакты](./contacts.md) - [Компании](./companies.md) - [Таймлайн CRM](/docs/timeline-logs) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Справочник сущностей](/docs/entities-index) --- # Entity: Users # Пользователи Управление сотрудниками портала: список, получение по ID, приглашение нового, обновление, деактивация. Сущность хранит контактные данные, должность, отдел и пользовательские поля (UF) сотрудника. Битрикс24 API: `user.*` Скоуп: `user` ## Операции - [Создать сотрудника](./users/create.md) — `POST /v1/users` - [Пригласить сотрудника](./users/invite.md) — `POST /v1/users/invite` - [Список сотрудников](./users/list.md) — `GET /v1/users` - [Получить сотрудника](./users/get.md) — `GET /v1/users/:id` - [Обновить сотрудника](./users/update.md) — `PATCH /v1/users/:id` - [Деактивировать сотрудника](./users/delete.md) — `DELETE /v1/users/:id` - [Поиск сотрудников](./users/search.md) — `POST /v1/users/search` - [Поля сотрудника](./users/fields.md) — `GET /v1/users/fields` - [Агрегация сотрудников](./users/aggregate.md) — `POST /v1/users/aggregate` ## Ключевые поля | Поле | Описание | |------|---------| | `id` | Идентификатор сотрудника | | `name` / `lastName` / `secondName` | Имя, фамилия, отчество | | `email` | Email — обязательно при создании, должен быть уникальным среди всех сотрудников портала | | `active` | Признак активности: `true` — работает, `false` — деактивирован | | `workPosition` | Должность | | `departmentId` | Массив ID отделов сотрудника. Список: `GET /v1/departments` | | `personalPhone` / `personalMobile` / `workPhone` | Телефоны | | `isAdmin` | Признак администратора портала (только чтение). Наполняется **только в `GET /v1/users/me`**, трёхзначно: `true` — админ, `false` — не админ, `null` — определить не удалось (временный сбой; профиль всё равно возвращается, это не ошибка) — пригоден для серверной проверки прав. **В `GET /v1/users/:id` и списке `GET /v1/users` поле недоступно**: `user.get` его не возвращает (`data.isAdmin` = `undefined`), вердикт отдаётся только для текущего пользователя сессии. | Полный список полей — [`GET /v1/users/fields`](/docs/entities/users/fields). ## Что нужно знать перед работой 1. **Создание требует email.** Поле `email` обязательное и должно быть уникальным для всего портала. Дубль вернёт `BITRIX_ERROR: wrong_email` без явного указания причины — этот код Битрикс24 использует для нескольких разных кейсов (см. ниже). 2. **Два эндпоинта для создания.** [`POST /v1/users`](/docs/entities/users/create) — обычная entity-форма, проксирует ошибки Битрикс24 как есть. [`POST /v1/users/invite`](/docs/entities/users/invite) — обёртка с предзаполнением `departmentId: [1]` для штатных сотрудников и явной валидацией email на стороне Вайбкод (`EMAIL_REQUIRED`, `EMAIL_INVALID`). Для интеграций предпочтительнее `/invite` — у него понятные коды ошибок. 3. **PATCH и DELETE требуют прав администратора портала.** Битрикс24 применяет обновление сотрудника только если у владельца ключа есть админские права на портале. Без них Битрикс24 возвращает `result: false`, Вайбкод оборачивает это в `403 UPDATE_FAILED` с подсказкой в поле `hint`. 4. **`DELETE /v1/users/:id` — это деактивация.** Эндпоинт снимает у сотрудника доступ к порталу, но сохраняет всю запись и её связи (ответственный за сделки, автор комментариев, участник чатов). Под капотом маппится на обновление поля активности (`active: false`), в ответе явный маркер `deactivated: true`. Восстановить доступ — `PATCH /v1/users/:id { active: true }`. Данные не теряются. 5. **Поля только для чтения.** `id`, `isOnline`, `isAdmin`, `lastLogin`, `dateRegister`, `lastActivityDate`, `userType`, `timestampX` заполняются системой. Попытка передать их в `PATCH /v1/users/:id` отклоняется заранее с `400 READONLY_FIELD` — вызов Битрикс24 не происходит. 6. **`WORK_*` / `PERSONAL_*` обычно не приходят, а пустые поля Битрикс24 опускает.** Стандартные заполненные поля (`name`, `email`, `active`, `departmentId`, `timeZone`, `userType` и др.) — `camelCase`. Поля `WORK_COMPANY`, `WORK_DEPARTMENT`, `PERSONAL_STATE`, `PERSONAL_ZIP` и аналогичные на практике в ответе **отсутствуют** (Битрикс24 не возвращает незаполненные поля); если такое поле всё же приходит — оно сохраняет исходное имя `UPPER_SNAKE_CASE` (не камелкейсится). То есть ключа может **не быть вовсе** — не полагайтесь на его присутствие. 7. **«Пусто» в datetime-полях закодировано тремя способами.** `timestampX` и `lastActivityDate` (объявлены `datetime`) приходят **пустым объектом `{}`**, а не строкой/`null` (`new Date(u.timestampX)` → `Invalid Date`; `if (u.lastActivityDate)` — **истинно** даже без активности). `lastActivityDate` к тому же может **отсутствовать** как ключ. `lastLogin` отдаёт `null`, когда входа не было. `dateRegister` — ISO-строка всегда (полночь UTC). Проверяйте «активность была» сравнением типа (`typeof x === 'string'`), а не truthy-проверкой. 8. **Внешние сотрудники (extranet).** При создании пользователя экстранета `EXTRANET: "Y"` обязательное поле `SONET_GROUP_ID` (массив ID рабочих групп) вместо `departmentId`. `/invite` явно отдаёт `400 SONET_GROUP_ID_REQUIRED`, если оба не переданы. ## Типичный сценарий 1. Найти сотрудника по части имени или email: [`GET /v1/users?filter[NAME]=Иван`](/docs/entities/users/list). 2. Получить полные данные одного: [`GET /v1/users/:id`](/docs/entities/users/get). 3. Пригласить нового через Вайбкод-обёртку: [`POST /v1/users/invite`](/docs/entities/users/invite). 4. Обновить должность или отдел: [`PATCH /v1/users/:id`](/docs/entities/users/update). 5. Если сотрудник уволился — деактивировать: [`DELETE /v1/users/:id`](/docs/entities/users/delete). Восстановить — `PATCH /v1/users/:id { active: true }`. ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | `offset` на больших выборках | рекомендуется `limit ≤ 500` при `offset ≥ 2500` | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Отделы](/docs/entities/departments) - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Справочник сущностей](/docs/entities-index) --- # Entity: Warehouses # Склады Склады портала и товарные остатки на них. Склад — это точка хранения или выдачи товаров каталога: физический склад, магазин или пункт выдачи. Склады можно создавать, изменять и удалять. Остатки товаров доступны только для чтения — по отдельному складу или сводно по всем складам. Битрикс24 API: `catalog.store.*`, `catalog.storeproduct.*` Скоуп: `catalog` ## Операции - [Создать склад](./warehouses/create.md) — `POST /v1/warehouses` - [Список складов](./warehouses/list.md) — `GET /v1/warehouses` - [Получить склад](./warehouses/get.md) — `GET /v1/warehouses/:id` - [Обновить склад](./warehouses/update.md) — `PATCH /v1/warehouses/:id` - [Удалить склад](./warehouses/delete.md) — `DELETE /v1/warehouses/:id` - [Остатки склада](./warehouses/stock.md) — `GET /v1/warehouses/:id/stock` - [Сводные остатки по товарам](./warehouses/stock-totals.md) — `GET /v1/warehouses/stock/totals` ## Поля ### Изменяемые поля Принимаются при [создании](./warehouses/create.md) и [обновлении](./warehouses/update.md). Передаются в корне JSON. | Поле | Тип | Описание | |------|-----|---------| | `title` | string | Название склада. Обязательно при создании | | `address` | string | Адрес склада. Обязательно при создании | | `active` | string | Активность: `"Y"` или `"N"`. По умолчанию `"Y"` | | `issuingCenter` | string | Признак пункта выдачи заказов: `"Y"` или `"N"`. По умолчанию `"N"` | | `description` | string | Описание склада | | `phone` | string | Контактный телефон | | `email` | string | Контактная почта | | `schedule` | string | Режим работы — произвольный текст | | `sort` | number | Порядок сортировки. По умолчанию `100` | | `code` | string | Символьный код | | `xmlId` | string | Внешний идентификатор для синхронизации с внешними системами | | `gpsN` | number | Географическая широта | | `gpsS` | number | Географическая долгота | | `userId` | number | Ответственный сотрудник — идентификатор из [`GET /v1/users`](/docs/entities/users) | ### Только для чтения Приходят в ответе, но не принимаются при создании и обновлении. | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор склада | | `imageId` | object \| null | Изображение склада в формате `{ "id": number, "url": string }` либо `null` | | `modifiedBy` | number \| null | ID пользователя, изменившего склад последним. `null` у системных складов, заполняется при создании через API | | `dateCreate` | datetime \| null | Дата создания. `null` у части системных складов (например, маркетплейсов) | | `dateModify` | datetime | Дата последнего изменения | ## Что нужно знать перед работой 1. **Тело запроса плоское.** При создании и обновлении передавайте поля прямо в корне JSON: `{"title": "...", "address": "..."}`. Обёртка `fields` не нужна. 2. **Для создания обязательны два поля.** Без `title` или `address` ответ — `400 MISSING_PARAMS`. Остальные поля необязательны: при отсутствии заполняются значениями по умолчанию (`active: "Y"`, `sort: 100`, `issuingCenter: "N"`). 3. **Несуществующий склад — ошибка `422`.** Получение, обновление или удаление склада по неизвестному `id` возвращает `422` с кодом `BITRIX_ERROR`, а не `404`. Проверить наличие склада можно через [список складов](./warehouses/list.md). 4. **Остатки доступны только для чтения.** Количество товаров на складе нельзя изменить через этот раздел: [остатки склада](./warehouses/stock.md) и [сводные остатки](./warehouses/stock-totals.md) — операции получения. Остатки меняются документами складского учёта на стороне портала. 5. **Сводные остатки агрегируются по товару.** [`GET /v1/warehouses/stock/totals`](./warehouses/stock-totals.md) складывает количество одного товара по всем складам и возвращает список складов (`storeIds`), где этот товар представлен. ## Типичный сценарий 1. Получить список складов: [`GET /v1/warehouses`](./warehouses/list.md) — взять `id` нужного склада. 2. Посмотреть остатки на складе: [`GET /v1/warehouses/:id/stock`](./warehouses/stock.md). 3. Свести остатки одного товара по всем складам: [`GET /v1/warehouses/stock/totals?productId=200`](./warehouses/stock-totals.md). ## Связанные сущности | Сущность | Эндпоинт | Назначение | |----------|----------|-----------| | Товары каталога | [`GET /v1/catalog-products`](/docs/entities/catalog-products) | Товары, остатки которых учитываются на складах. Поле `productId` в [остатках](./warehouses/stock.md) и [сводных остатках](./warehouses/stock-totals.md) ссылается на товар каталога. | ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | `offset` на больших выборках | рекомендуется `limit ≤ 500` при `offset ≥ 2500` | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Товары каталога](/docs/entities/catalog-products) - [Каталоги](/docs/entities/catalogs) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entities-index) --- # Entity: Workgroups # Рабочие группы Управление рабочими группами и проектами портала: создание, получение, обновление, удаление, поиск. Рабочая группа объединяет сотрудников вокруг общей темы или проекта — у неё есть владелец, тема, флаги открытости и архивирования, а также счётчик участников. Битрикс24 API: `sonet_group.*` Скоуп: `sonet_group` ## Операции - [Создать рабочую группу](./workgroups/create.md) — `POST /v1/workgroups` - [Список рабочих групп](./workgroups/list.md) — `GET /v1/workgroups` - [Получить рабочую группу](./workgroups/get.md) — `GET /v1/workgroups/:id` - [Обновить рабочую группу](./workgroups/update.md) — `PATCH /v1/workgroups/:id` - [Удалить рабочую группу](./workgroups/delete.md) — `DELETE /v1/workgroups/:id` - [Поиск рабочих групп](./workgroups/search.md) — `POST /v1/workgroups/search` - [Поля рабочей группы](./workgroups/fields.md) — `GET /v1/workgroups/fields` - [Агрегация рабочих групп](./workgroups/aggregate.md) — `POST /v1/workgroups/aggregate` ## Ключевые поля | Поле | Описание | |------|---------| | `name` | Название рабочей группы | | `ownerId` | Идентификатор владельца. Источник: [`GET /v1/users`](/docs/entities/users) | | `subjectId` | Идентификатор темы. Список допустимых значений отдаётся в ответах [`GET /v1/workgroups`](./workgroups/list.md) в поле `subjectName` рядом с `subjectId` | | `opened` | Признак открытости — может ли вступить любой сотрудник портала | | `isProject` | Признак проекта — у проектов отдельная семантика в задачах и отчётах | | `archived` | Признак архива — группа скрыта из активных списков, но сохранена | | `membersCount` | Текущее количество участников группы | Полный список полей — [`GET /v1/workgroups/fields`](./workgroups/fields.md). ## Что нужно знать перед работой 1. **Булевы поля имеют разный формат на входе и в ответе.** В URL-фильтрах (`?filter[active]=...`) булевы поля передаются как `Y` или `N`. В теле запросов `POST` / `PATCH` и в body `POST /v1/workgroups/search` работают и `Y` / `N`, и нативные JSON `true` / `false`. В ответах всех эндпоинтов — всегда `true` / `false`. 2. **`archived` и `active` — разные признаки.** `archived: true` означает, что группа перенесена в архив и не отображается в активных списках. `active: false` означает, что группа выключена. Это два независимых состояния. 3. **`isProject: true` — отдельная семантика.** Проектные группы по-другому ведут себя в задачах и отчётах Битрикс24. Чтобы создать обычную рабочую группу без проектной логики, оставьте `isProject` пустым или передайте `false`. 4. **Темы задаются на стороне портала.** Перечень допустимых `subjectId` настраивается администратором Битрикс24 и не редактируется через API рабочих групп. Сопоставление `subjectId` ↔ `subjectName` возвращается в каждом элементе списка рабочих групп. ## Типичный сценарий 1. Найти будущего владельца группы: [`GET /v1/users?filter[name]=Иван`](/docs/entities/users). 2. Создать рабочую группу: [`POST /v1/workgroups`](./workgroups/create.md) с `name`, `ownerId`, `subjectId`, `opened`. 3. Получить список рабочих групп сотрудника: [`GET /v1/workgroups?filter[ownerId]=15`](./workgroups/list.md). 4. Обновить параметры: [`PATCH /v1/workgroups/:id`](./workgroups/update.md) — например, переключить `opened` или изменить `description`. 5. Перенести группу в архив: [`PATCH /v1/workgroups/:id`](./workgroups/update.md) с `archived: true`. ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 5000 (`limit ≤ 5000`) | | Авто-пагинация | включается при `limit > 50` | | `offset` на больших выборках | рекомендуется `limit ≤ 500` при `offset ≥ 2500` | | Batch-запросы | до 50 операций в [`POST /v1/batch`](/docs/batch) | | Ограничение частоты запросов | общее для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Справочник сущностей](/docs/entities-index) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Сотрудники](/docs/entities/users) - [Отделы](/docs/entities/departments) --- # Activities: Aggregate ## Агрегация дел `POST /v1/activities/aggregate` Подсчёт количества дел с фильтрацией и группировкой. > **Агрегации по делам нужен сужающий фильтр.** Битрикс24 не успевает посчитать все дела аккаунта за отведённое на вызов время, поэтому запрос без сужения на большом аккаунте не отвечает вообще — сколько бы раз его ни повторяли. Достаточно **одного** из трёх сужений: пара `ownerTypeId` + `ownerId`, либо `responsibleId`, либо граница по дате на `createdAt` / `updatedAt` / `deadline`. Актуальный список сужений и то, требует ли их аккаунт прямо сейчас, — в `data.aggregateFilterRequirement` ответа [GET /v1/activities/fields](/docs/entities/activities/fields). **Стандартные поля:** - `typeId` — тип активности (для `groupBy`) - `ownerTypeId` — тип родительской сущности (для `groupBy`) - `responsibleId` — ответственный (для `groupBy`) - `completed` — статус выполнения (для `groupBy`) Все поля в `aggregatable` — категориальные идентификаторы, поэтому основной сценарий — `count` с группировкой. Числовые функции `sum`/`avg`/`min`/`max` применяются редко. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций. Каждый элемент: `{ "field": "*", "function": "count" }`. Без массива — только `count` | | `filter` | object | да | Фильтрация по полям `GET /v1/activities/fields`. Обязан содержать одно из сужений (см. врезку выше). [Синтаксис фильтрации](/docs/filtering) | | `groupBy` | string \| string[] | нет | Поле или массив полей для группировки (максимум 5). Допустимые значения — из списка выше | ## Примеры ### curl — личный ключ Количество дел по сделке (`ownerTypeId: 2` — сделка), сгруппированное по типу активности: ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/activities/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "ownerTypeId": 2, "ownerId": 741, "completed": "Y" }, "groupBy": "typeId" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/activities/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "ownerTypeId": 2, "ownerId": 741, "completed": "Y" }, "groupBy": "typeId" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { ownerTypeId: 2, ownerId: 741, completed: 'Y' }, groupBy: 'typeId', }), }) const { success, data } = await res.json() console.log('Всего завершённых дел по сделке:', data.count) console.log('Распределение по типу:', data.groups) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { ownerTypeId: 2, ownerId: 741, completed: 'Y' }, groupBy: 'typeId', }), }) const { success, data } = await res.json() ``` > Для группировки по нескольким полям передайте массив: `"groupBy": ["typeId", "completed"]` (максимум 5). ## Другие сценарии Количество дел за период — граница по дате считается сужением: ```json { "filter": { ">=createdAt": "2026-07-01", "1 — лид
2 — сделка
3 — контакт
4 — компания
7 — предложение
31 — счёт
≥128 — смарт-процесс, его код — в [`GET /v1/smart-processes`](/docs/entities/smart-processes/list) | | **`entityId`** | number | да | ID сущности, к которой привязываем | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/activities/3631/bindings \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "entityTypeId": 3, "entityId": 9 }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/activities/3631/bindings \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "entityTypeId": 3, "entityId": 9 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities/3631/bindings', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ entityTypeId: 3, entityId: 9 }), }) const { data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities/3631/bindings', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ entityTypeId: 3, entityId: 9 }), }) const { data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.activityId` | number | ID дела | | `data.entityTypeId` | number | Числовой код типа привязанной сущности | | `data.entityId` | number | ID привязанной сущности | | `data.bound` | boolean | Всегда `true` — подтверждение привязки | ## Пример ответа ```json { "success": true, "data": { "activityId": 3631, "entityTypeId": 3, "entityId": 9, "bound": true } } ``` ## Пример ответа при ошибке 422 — сущность уже привязана: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Дело уже привязано к этой сущности" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `activityId`, `entityTypeId` или `entityId` не положительное целое число | | 404 | `ENTITY_NOT_FOUND` | Дела с указанным `activityId` не существует | | 422 | `BITRIX_ERROR` | Дело уже привязано к этой паре `entityTypeId` + `entityId`, либо такой сущности нет | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `crm` | | 401 | `TOKEN_MISSING` | У ключа нет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Привязка не идемпотентна.** Повторный запрос к уже привязанной паре возвращает `422`, а не `200`. Это значит «уже привязано», а не сбой — повторять запрос не нужно, дубликат в списке не появляется. ## Смотрите также - [Отвязать](/docs/entities/activities/bindings/unbind) - [Список привязок](/docs/entities/activities/bindings/list) - [Дела](/docs/entities/activities) --- # Activities: List ## Список привязок `GET /v1/activities/:activityId/bindings` Возвращает все CRM-сущности, к которым привязано дело. Минимум одна привязка есть всегда — сущность-владелец, указанная при создании дела. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `activityId` (path) | number | да | ID дела. Список: `GET /v1/activities` | ## Примеры ### curl — личный ключ ```bash curl https://vibecode.bitrix24.tech/v1/activities/3631/bindings \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl https://vibecode.bitrix24.tech/v1/activities/3631/bindings \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities/3631/bindings', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() data.forEach(b => console.log(`${b.entityTypeId}:${b.entityId}`)) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities/3631/bindings', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив привязок | | `data[].entityTypeId` | number | Числовой код типа CRM-сущности:
1 — лид
2 — сделка
3 — контакт
4 — компания
7 — предложение
31 — счёт
≥128 — смарт-процесс, его код — в [`GET /v1/smart-processes`](/docs/entities/smart-processes/list) | | `data[].entityId` | number | ID привязанной сущности | ## Пример ответа ```json { "success": true, "data": [ { "entityTypeId": 2, "entityId": 4219 }, { "entityTypeId": 3, "entityId": 9 } ] } ``` ## Пример ответа при ошибке 404 — дело не существует: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `activityId` не положительное целое число | | 404 | `ENTITY_NOT_FOUND` | Дела с указанным `activityId` не существует | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `crm` | | 401 | `TOKEN_MISSING` | У ключа нет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Привязать](/docs/entities/activities/bindings/bind) - [Переместить привязку](/docs/entities/activities/bindings/move) - [Дела](/docs/entities/activities) --- # Activities: Move ## Переместить привязку `POST /v1/activities/:activityId/bindings/move` Переносит привязку дела с одной CRM-сущности на другую того же типа: старая привязка снимается, новая создаётся одним вызовом. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `activityId` (path) | number | да | ID дела. Список: `GET /v1/activities` | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | **`sourceEntityTypeId`** | number | да | Числовой код типа исходной сущности:
1 — лид
2 — сделка
3 — контакт
4 — компания
7 — предложение
31 — счёт
≥128 — смарт-процесс, его код — в [`GET /v1/smart-processes`](/docs/entities/smart-processes/list) | | **`sourceEntityId`** | number | да | ID исходной сущности | | **`targetEntityTypeId`** | number | да | Числовой код типа целевой сущности. Должен совпадать с `sourceEntityTypeId` | | **`targetEntityId`** | number | да | ID целевой сущности | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/activities/3631/bindings/move \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "sourceEntityTypeId": 3, "sourceEntityId": 9, "targetEntityTypeId": 3, "targetEntityId": 17 }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/activities/3631/bindings/move \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "sourceEntityTypeId": 3, "sourceEntityId": 9, "targetEntityTypeId": 3, "targetEntityId": 17 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities/3631/bindings/move', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ sourceEntityTypeId: 3, sourceEntityId: 9, targetEntityTypeId: 3, targetEntityId: 17, }), }) const { data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities/3631/bindings/move', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ sourceEntityTypeId: 3, sourceEntityId: 9, targetEntityTypeId: 3, targetEntityId: 17, }), }) const { data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.activityId` | number | ID дела | | `data.sourceEntityTypeId` | number | Числовой код типа исходной сущности | | `data.sourceEntityId` | number | ID исходной сущности | | `data.targetEntityTypeId` | number | Числовой код типа целевой сущности | | `data.targetEntityId` | number | ID целевой сущности | | `data.moved` | boolean | Всегда `true` — подтверждение переноса | ## Пример ответа ```json { "success": true, "data": { "activityId": 3631, "sourceEntityTypeId": 3, "sourceEntityId": 9, "targetEntityTypeId": 3, "targetEntityId": 17, "moved": true } } ``` ## Пример ответа при ошибке 422 — исходная и целевая сущности разного типа: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Source and target entity types are not equal" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `activityId` или любое из полей `source*` / `target*` не положительное целое число | | 404 | `ENTITY_NOT_FOUND` | Дела с указанным `activityId` не существует | | 422 | `BITRIX_ERROR` | Тип исходной сущности не совпадает с типом целевой | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `crm` | | 401 | `TOKEN_MISSING` | У ключа нет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Перенос работает только в пределах одного типа.** Чтобы перенести дело на сущность другого типа, `move` не подходит — сделайте это в два шага: 1. Привяжите дело ко второй сущности — [`POST /v1/activities/:activityId/bindings`](/docs/entities/activities/bindings/bind). 2. Снимите привязку к первой — [`DELETE /v1/activities/:activityId/bindings`](/docs/entities/activities/bindings/unbind). Такой порядок не нарушает запрет на снятие последней привязки — дело всё время остаётся привязанным минимум к одной сущности. ## Смотрите также - [Привязать](/docs/entities/activities/bindings/bind) - [Отвязать](/docs/entities/activities/bindings/unbind) - [Список привязок](/docs/entities/activities/bindings/list) --- # Activities: Unbind ## Отвязать `DELETE /v1/activities/:activityId/bindings` Снимает привязку дела к указанной CRM-сущности. В её таймлайне дело больше не отображается, но остаётся в таймлайнах остальных привязанных сущностей. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `activityId` (path) | number | да | ID дела. Список: `GET /v1/activities` | | `entityTypeId` (query) | number | да | Числовой код типа сущности:
1 — лид
2 — сделка
3 — контакт
4 — компания
7 — предложение
31 — счёт
≥128 — смарт-процесс, его код — в [`GET /v1/smart-processes`](/docs/entities/smart-processes/list) | | `entityId` (query) | number | да | ID сущности, от которой отвязываем | `entityTypeId` и `entityId` можно передать как query-параметры или в теле запроса. ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/activities/3631/bindings?entityTypeId=3&entityId=9" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/activities/3631/bindings?entityTypeId=3&entityId=9" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities/3631/bindings?entityTypeId=3&entityId=9', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities/3631/bindings?entityTypeId=3&entityId=9', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.activityId` | number | ID дела | | `data.entityTypeId` | number | Числовой код типа отвязанной сущности | | `data.entityId` | number | ID отвязанной сущности | | `data.deleted` | boolean | Всегда `true` — подтверждение, что привязка снята | ## Пример ответа ```json { "success": true, "data": { "activityId": 3631, "entityTypeId": 3, "entityId": 9, "deleted": true } } ``` ## Пример ответа при ошибке 422 — попытка снять единственную привязку: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Нельзя удалять единственную привязку дела к сущности" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `activityId`, `entityTypeId` или `entityId` не положительное целое число | | 404 | `ENTITY_NOT_FOUND` | Дела с указанным `activityId` не существует | | 422 | `BITRIX_ERROR` | Попытка снять единственную оставшуюся привязку дела | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `crm` | | 401 | `TOKEN_MISSING` | У ключа нет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Нельзя снять последнюю привязку.** Дело должно оставаться привязанным минимум к одной сущности — попытка отвязать единственную возвращает `422`, привязка сохраняется. **Перенос дела на другую запись.** Чтобы перенести дело, не нарушив запрет на снятие последней привязки, см. [Переместить привязку](/docs/entities/activities/bindings/move) — там описан безопасный порядок и перенос одним вызовом в пределах одного типа. ## Смотрите также - [Привязать](/docs/entities/activities/bindings/bind) - [Переместить привязку](/docs/entities/activities/bindings/move) - [Список привязок](/docs/entities/activities/bindings/list) --- # Activities: Configurable # Конфигурируемые дела Конфигурируемое дело — запись в таймлайне CRM-сущности с собственным оформлением: иконкой, заголовком, блоками тела и кнопками. Внешний вид задаёт структура `layout`. Подходит для интеграций, которые показывают в таймлайне сделки, лида, контакта или компании карточку звонка, заявки, доставки или другого внешнего события. Раздел содержит только создание, чтение и обновление. Удаление и список — через общий API дел: [`DELETE /v1/activities/:id`](/docs/entities/activities) и [`GET /v1/activities`](/docs/entities/activities). Битрикс24 API: `crm.activity.configurable.*` Скоуп: `crm` ## Операции - [Создать дело](./configurable/create.md) — `POST /v1/activity-configurable` - [Получить дело](./configurable/get.md) — `GET /v1/activity-configurable/:id` - [Обновить дело](./configurable/update.md) — `PATCH /v1/activity-configurable/:id` ## Когда использовать - Звонок из внешней телефонии показывается в таймлайне сделки карточкой с кнопкой действия. - Заявка из внешнего сервиса отображается с действиями «Подтвердить» и «Отклонить». - Доставка или внешнее событие появляется в карточке лида с собственной иконкой и ссылкой. ## Требования к OAuth-приложению Методы работают только в контексте приложения: нужен ключ авторизации `vibe_app_*` с токеном сессии в заголовке `Authorization: Bearer`. Персональный API-ключ `vibe_api_*` Битрикс24 отклоняет с `ERROR_WRONG_CONTEXT`. Изменить дело может только то приложение, которое его создало. Пользовательские типы дел `crm.activity.type.*` регистрируются в Битрикс24 — отдельного эндпоинта в API Вайбкод для них нет. Без своего типа дело создаётся с типом `CONFIGURABLE`. ## Смотрите также - [Дела](/docs/entities/activities) - [Привязки дел](/docs/entities/activities/bindings) - [Лог таймлайна](/docs/timeline-logs) - [Ключи и авторизация](/docs/keys-auth) --- # Activities: Create ## Создать дело `POST /v1/activity-configurable` Создаёт конфигурируемое дело в таймлайне CRM-сущности. Набор полей дела задаёт `fields`, внешний вид — `layout`. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | **`ownerTypeId`** | number | да | Тип CRM-сущности:
1 — лид
2 — сделка
3 — контакт
4 — компания
7 — предложение
31 — счёт
≥128 — смарт-процесс, id типа — в [`GET /v1/smart-processes`](/docs/entities/smart-processes/list) | | **`ownerId`** | number | да | ID сущности, в таймлайне которой создаётся дело | | **`fields`** | object | да | Поля дела | | `fields.typeId` | string | нет | Тип дела. По умолчанию `CONFIGURABLE`. Свой тип регистрируется в Битрикс24 как конфигурируемый в контексте того же приложения | | `fields.completed` | boolean | нет | Дело закрыто. Принимает `true`/`false`, `1`/`0`, `Y`/`N` | | `fields.deadline` | string | нет | Крайний срок исполнения, ISO 8601. Несовместим с `fields.isIncomingChannel` | | `fields.pingOffsets` | number[] | нет | Смещения в минутах относительно `fields.deadline`, в которые формируются напоминания | | `fields.isIncomingChannel` | boolean | нет | Дело создано из входящего канала. Принимает `true`/`false`, `1`/`0`, `Y`/`N` | | `fields.responsibleId` | number | нет | ID ответственного сотрудника. Список: `GET /v1/users` | | `fields.badgeCode` | string | нет | Код значка дела на канбане | | `fields.originatorId` | string | нет | ID внешнего источника данных | | `fields.originId` | string | нет | ID записи во внешнем источнике | | **`layout`** | object | да | Оформление дела в таймлайне | | `layout.icon.code` | string | да | Код иконки дела | | `layout.header.title` | string | да | Заголовок дела | | `layout.body.logo.code` | string | да | Код логотипа в теле. Тело без `logo` Битрикс24 отклоняет | | `layout.body.blocks` | object | нет | Именованные блоки тела | | `layout.footer.buttons` | object | нет | Кнопки футера | Блок в `layout.body.blocks` имеет `type` и `properties`. Основные типы блоков: - `text` — значение - `link` — ссылка с действием - `lineOfBlocks` — строка из вложенных блоков - `withTitle` — блок с подписью Действие у ссылок и кнопок задаёт поле `type`: - `redirect` — переход по адресу из поля `uri` - `openRestApp` — открытие приложения с параметрами `actionParams` - `restEvent` — событие приложению по `id`, для пунктов меню ## Примеры Примеры приведены только для OAuth-приложения. ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/activity-configurable \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "ownerTypeId": 1, "ownerId": 999, "fields": { "typeId": "CONFIGURABLE", "completed": true, "responsibleId": 1, "badgeCode": "CUSTOM" }, "layout": { "icon": { "code": "call-completed" }, "header": { "title": "Входящий звонок" }, "body": { "logo": { "code": "call-incoming" }, "blocks": { "phone": { "type": "text", "properties": { "value": "+7 999 888 7777" } } } }, "footer": { "buttons": { "startCall": { "title": "О клиенте", "type": "primary", "action": { "type": "openRestApp", "actionParams": { "clientId": 456 } } } } } } }' ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activity-configurable', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ ownerTypeId: 1, ownerId: 999, fields: { typeId: 'CONFIGURABLE', completed: true, responsibleId: 1, badgeCode: 'CUSTOM' }, layout: { icon: { code: 'call-completed' }, header: { title: 'Входящий звонок' }, body: { logo: { code: 'call-incoming' }, blocks: { phone: { type: 'text', properties: { value: '+7 999 888 7777' } }, }, }, footer: { buttons: { startCall: { title: 'О клиенте', type: 'primary', action: { type: 'openRestApp', actionParams: { clientId: 456 } }, }, }, }, }, }), }) const { data } = await res.json() console.log('Activity ID:', data.activity.id) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.activity.id` | number | ID созданного дела | ## Пример ответа ```json { "success": true, "data": { "activity": { "id": 8053 } } } ``` ## Пример ответа при ошибке 422 — не заполнен `logo` в теле: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Поле logo в BodyDto должно быть заполнено." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `VALIDATION_ERROR` | Не передан `ownerTypeId`, `ownerId`, `fields` или `layout` | | 422 | `BITRIX_ERROR` | Битрикс24 отклонил запрос: пустой `layout`, не заполнен `layout.body.logo`, вызов вне контекста приложения, входящее дело с `deadline` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `crm` | | 401 | `TOKEN_MISSING` | Ключ авторизации передан без токена сессии в заголовке `Authorization: Bearer` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Только в контексте приложения.** Нужен ключ авторизации `vibe_app_*` с токеном сессии в заголовке `Authorization: Bearer`. Персональный API-ключ `vibe_api_*` Битрикс24 отклоняет с `ERROR_WRONG_CONTEXT`. ## Смотрите также - [Получить дело](/docs/entities/activities/configurable/get) - [Обновить дело](/docs/entities/activities/configurable/update) - [Конфигурируемые дела](/docs/entities/activities/configurable) - [Дела](/docs/entities/activities) --- # Activities: Get ## Получить дело `GET /v1/activity-configurable/:id` Возвращает конфигурируемое дело по ID: его поля и структуру оформления. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID дела. Получен при создании | ## Примеры Примеры приведены только для OAuth-приложения. ### curl — OAuth-приложение ```bash curl https://vibecode.bitrix24.tech/v1/activity-configurable/8053 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activity-configurable/8053', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() console.log(data.activity.fields.typeId, data.activity.layout) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.activity.id` | number | ID дела | | `data.activity.ownerTypeId` | number | Тип CRM-сущности:
1 — лид
2 — сделка
3 — контакт
4 — компания
7 — предложение
31 — счёт
≥128 — смарт-процесс, id типа — в [`GET /v1/smart-processes`](/docs/entities/smart-processes/list) | | `data.activity.ownerId` | number | ID сущности-владельца | | `data.activity.fields.typeId` | string | Тип дела. Для дел без своего типа — `CONFIGURABLE` | | `data.activity.fields.completed` | boolean | Дело закрыто | | `data.activity.fields.deadline` | string | Крайний срок исполнения, ISO 8601. `null`, если не задан | | `data.activity.fields.pingOffsets` | number[] | Смещения в минутах относительно `deadline`, в которые сформированы напоминания. Пустой массив, если напоминаний нет | | `data.activity.fields.isIncomingChannel` | boolean | Дело создано из входящего канала | | `data.activity.fields.responsibleId` | number | ID ответственного сотрудника | | `data.activity.fields.badgeCode` | string | Код значка дела на канбане. Пустая строка, если не задан | | `data.activity.fields.originatorId` | string | ID внешнего источника данных. `null`, если не задан | | `data.activity.fields.originId` | string | ID записи во внешнем источнике. `null`, если не задан | | `data.activity.layout.icon` | object | Иконка дела — поле `code` | | `data.activity.layout.header` | object | Шапка — `title`. Битрикс24 может добавить пометки `tags` | | `data.activity.layout.body` | object | Тело — логотип `logo` и именованные блоки `blocks` | | `data.activity.layout.footer` | object | Футер — кнопки `buttons` и меню `menu` | ## Пример ответа ```json { "success": true, "data": { "activity": { "id": 8053, "ownerTypeId": 1, "ownerId": 2975, "fields": { "typeId": "CONFIGURABLE", "completed": false, "deadline": "2025-02-01T01:00:00+03:00", "pingOffsets": [], "isIncomingChannel": false, "responsibleId": 1, "badgeCode": "", "originatorId": null, "originId": null }, "layout": { "icon": { "code": "call-completed" }, "header": { "title": "Входящий звонок" }, "body": { "logo": { "code": "call-incoming" }, "blocks": {} }, "footer": { "buttons": {} } } } } } ``` ## Пример ответа при ошибке 404 — дело не найдено: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `VALIDATION_ERROR` | `id` в пути не является числом | | 404 | `ENTITY_NOT_FOUND` | Дела с указанным `id` не существует | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `crm` | | 401 | `TOKEN_MISSING` | Ключ авторизации передан без токена сессии в заголовке `Authorization: Bearer` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Только в контексте приложения.** Нужен ключ авторизации `vibe_app_*` с токеном сессии в заголовке `Authorization: Bearer`. Персональный API-ключ `vibe_api_*` Битрикс24 отклоняет с `ERROR_WRONG_CONTEXT`. ## Смотрите также - [Создать дело](/docs/entities/activities/configurable/create) - [Обновить дело](/docs/entities/activities/configurable/update) - [Конфигурируемые дела](/docs/entities/activities/configurable) --- # Activities: Update ## Обновить дело `PATCH /v1/activity-configurable/:id` Перезаписывает конфигурируемое дело. `fields` и `layout` передаются целиком — метод заменяет дело, а не обновляет отдельные поля. Незаданные значения сбрасываются. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID дела. Получен при создании | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | **`fields`** | object | да | Поля дела | | `fields.typeId` | string | нет | Тип дела. По умолчанию `CONFIGURABLE` | | `fields.completed` | boolean | нет | Дело закрыто. Принимает `true`/`false`, `1`/`0`, `Y`/`N` | | `fields.deadline` | string | нет | Крайний срок исполнения, ISO 8601. Несовместим с `fields.isIncomingChannel` | | `fields.pingOffsets` | number[] | нет | Смещения в минутах относительно `fields.deadline`, в которые формируются напоминания | | `fields.isIncomingChannel` | boolean | нет | Дело создано из входящего канала. Принимает `true`/`false`, `1`/`0`, `Y`/`N` | | `fields.responsibleId` | number | нет | ID ответственного сотрудника. Список: `GET /v1/users` | | `fields.badgeCode` | string | нет | Код значка дела на канбане | | `fields.originatorId` | string | нет | ID внешнего источника данных | | `fields.originId` | string | нет | ID записи во внешнем источнике | | **`layout`** | object | да | Оформление дела | | `layout.icon.code` | string | да | Код иконки дела | | `layout.header.title` | string | да | Заголовок дела | | `layout.body.logo.code` | string | да | Код логотипа в теле. Тело без `logo` Битрикс24 отклоняет | | `layout.body.blocks` | object | нет | Именованные блоки тела | | `layout.footer.buttons` | object | нет | Кнопки футера | Блок в `layout.body.blocks` имеет `type` и `properties`. Основные типы блоков: - `text` — значение - `link` — ссылка с действием - `lineOfBlocks` — строка из вложенных блоков - `withTitle` — блок с подписью Действие у ссылок и кнопок задаёт поле `type`: - `redirect` — переход по адресу из поля `uri` - `openRestApp` — открытие приложения с параметрами `actionParams` - `restEvent` — событие приложению по `id`, для пунктов меню ## Примеры Примеры приведены только для OAuth-приложения. ### curl — OAuth-приложение ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/activity-configurable/8053 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "fields": { "typeId": "CONFIGURABLE", "completed": true, "responsibleId": 5 }, "layout": { "icon": { "code": "call-completed" }, "header": { "title": "Звонок обработан" }, "body": { "logo": { "code": "call-incoming" }, "blocks": {} }, "footer": { "buttons": {} } } }' ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activity-configurable/8053', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ fields: { typeId: 'CONFIGURABLE', completed: true, responsibleId: 5 }, layout: { icon: { code: 'call-completed' }, header: { title: 'Звонок обработан' }, body: { logo: { code: 'call-incoming' }, blocks: {} }, footer: { buttons: {} }, }, }), }) const { data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.activity.id` | number | ID обновлённого дела | ## Пример ответа ```json { "success": true, "data": { "activity": { "id": 8053 } } } ``` ## Пример ответа при ошибке 404 — дело не найдено: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `VALIDATION_ERROR` | `id` в пути не число, либо не передан `fields` или `layout` | | 404 | `ENTITY_NOT_FOUND` | Дела с указанным `id` не существует | | 422 | `BITRIX_ERROR` | Битрикс24 отклонил запрос: дело создано другим приложением `ERROR_WRONG_APPLICATION`, не заполнен `layout.body.logo`, пустой `layout` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `crm` | | 401 | `TOKEN_MISSING` | Ключ авторизации передан без токена сессии в заголовке `Authorization: Bearer` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Только в контексте приложения.** Нужен ключ авторизации `vibe_app_*` с токеном сессии в заголовке `Authorization: Bearer`. Персональный API-ключ `vibe_api_*` Битрикс24 отклоняет с `ERROR_WRONG_CONTEXT`. **Обновляет только приложение-автор.** Изменить дело может лишь то приложение, которое его создало. Чужое дело Битрикс24 отклоняет с `ERROR_WRONG_APPLICATION`. ## Смотрите также - [Создать дело](/docs/entities/activities/configurable/create) - [Получить дело](/docs/entities/activities/configurable/get) - [Конфигурируемые дела](/docs/entities/activities/configurable) --- # Activities: Create ## Создать дело `POST /v1/activities` Создаёт новое CRM-дело: звонок, встречу, задачу или email. Дело привязывается к CRM-сущности через `ownerTypeId` + `ownerId`. ## Поля запроса (body) Минимальный набор для создания дела — `subject`, `typeId`, `communications` плюс **привязка** к CRM-сущности. Привязку задаёт **либо** пара `ownerTypeId` + `ownerId`, **либо** поля `entityTypeId` + `entityId` внутри элемента `communications`. Если не задано ни одно из двух, Bitrix24 не может привязать коммуникацию и возвращает ошибку про `communications`. | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `subject` | string | да | Тема дела | | `typeId` | number | да | Тип: `1` — встреча, `2` — звонок, `3` — задача, `4` — письмо, `5` — действие, `6` — пользовательское действие | | `communications` | object[] | да | Коммуникации дела. Массив объектов: `[{ "value": "+7…", "entityTypeId": 3, "entityId": 17 }]`. Вложенные ключи принимаются в camelCase (`type`, `value`, `entityTypeId`, `entityId`) — как и во всём остальном API — либо в ВЕРХНЕМ регистре Bitrix24 (`TYPE`, `VALUE`, `ENTITY_TYPE_ID`, `ENTITY_ID`). `value` — телефон/e-mail; `entityTypeId` + `entityId` — CRM-сущность, которой принадлежит коммуникация (задаёт привязку, если не переданы `ownerTypeId`/`ownerId`). Когда владелец указан, достаточно `[{ "value": "+7…" }]` | | `ownerTypeId` | number | да¹ | Тип родительской сущности: `1` — лид, `2` — сделка, `3` — контакт, `4` — компания | | `ownerId` | number | да¹ | ID родительской сущности. Поиск: `GET /v1/deals`, `GET /v1/leads`, `GET /v1/contacts`, `GET /v1/companies` | | `responsibleId` | number | | Ответственный. По умолчанию — текущий пользователь. Список: `GET /v1/users` | | `description` | string | | Описание | | `priority` | number | | Приоритет: `1` — низкий, `2` — средний, `3` — высокий | | `direction` | number | | Направление: `1` — входящее, `2` — исходящее | | `completed` | boolean | | Завершена | | `startTime` | datetime | | Дата начала | | `endTime` | datetime | | Дата окончания | | `deadline` | datetime | | Крайний срок. **На создании Bitrix24 игнорирует переданное значение и вычисляет `deadline` из `startTime`/`endTime`** — отдельно задать его при `POST` нельзя | ¹ Пара `ownerTypeId` + `ownerId` нужна вместе и **только если** привязка не задана через `entityTypeId`/`entityId` внутри `communications`. Если привязка идёт через коммуникацию — оба поля можно опустить. > ℹ️ Вложенные ключи `communications` принимаются в двух формах: camelCase (`type`, `value`, `entityTypeId`, `entityId`) — единообразно с остальным API — и в ВЕРХНЕМ регистре Bitrix24 (`TYPE`, `VALUE`, `ENTITY_TYPE_ID`, `ENTITY_ID`). Если в одном объекте заданы обе формы одного ключа, приоритет у ВЕРХНЕГО регистра. Полный список полей: [GET /v1/activities/fields](/docs/entities/activities/fields). ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/activities \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "typeId": 2, "ownerTypeId": 3, "ownerId": 17, "subject": "Звонок клиенту", "description": "Обсудить условия поставки", "responsibleId": 1, "priority": 2, "direction": 2, "communications": [ { "value": "+7 999 123-45-67", "entityTypeId": 3, "entityId": 17 } ], "startTime": "2026-04-16T10:00:00+03:00", "endTime": "2026-04-16T10:15:00+03:00" }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/activities \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "typeId": 2, "ownerTypeId": 3, "ownerId": 17, "subject": "Звонок клиенту", "description": "Обсудить условия поставки", "responsibleId": 1, "priority": 2, "direction": 2, "communications": [ { "value": "+7 999 123-45-67", "entityTypeId": 3, "entityId": 17 } ], "startTime": "2026-04-16T10:00:00+03:00", "endTime": "2026-04-16T10:15:00+03:00" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ typeId: 2, ownerTypeId: 3, ownerId: 17, subject: 'Звонок клиенту', description: 'Обсудить условия поставки', responsibleId: 1, priority: 2, direction: 2, communications: [ { value: '+7 999 123-45-67', entityTypeId: 3, entityId: 17 }, ], startTime: '2026-04-16T10:00:00+03:00', endTime: '2026-04-16T10:15:00+03:00', }), }) const { success, data } = await res.json() console.log('Activity ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ typeId: 2, ownerTypeId: 3, ownerId: 17, subject: 'Звонок клиенту', description: 'Обсудить условия поставки', responsibleId: 1, priority: 2, direction: 2, communications: [ { value: '+7 999 123-45-67', entityTypeId: 3, entityId: 17 }, ], startTime: '2026-04-16T10:00:00+03:00', endTime: '2026-04-16T10:15:00+03:00', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID созданного дела | | `typeId` | number | Тип дела | | `ownerTypeId` | number | Тип родительской сущности | | `ownerId` | number | ID родительской сущности | | `subject` | string | Тема | | `responsibleId` | number | Ответственный | | `createdAt` | datetime | Дата создания | | `updatedAt` | datetime | Дата изменения | Ответ содержит все поля дела. ## Пример ответа ```json { "success": true, "data": { "id": 3894, "typeId": 2, "ownerTypeId": 3, "ownerId": 17, "subject": "Звонок клиенту", "description": "Обсудить условия поставки", "responsibleId": 1, "priority": 2, "direction": 2, "completed": false, "startTime": "2026-04-16T10:00:00+03:00", "endTime": "2026-04-16T10:15:00+03:00", "deadline": "2026-04-16T10:00:00+03:00", "createdAt": "2026-04-15T14:30:00+03:00", "updatedAt": "2026-04-15T14:30:00+03:00" } } ``` ## Пример ответа при ошибке 400 — не передано обязательное поле (`subject`, `typeId` или `communications`): ```json { "success": false, "error": { "code": "MISSING_REQUIRED_FIELDS", "message": "Body field \"communications\" is required to create activity." } } ``` 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_FIELDS` | Не передано одно из обязательных полей: `subject`, `typeId`, `communications` (проверяется до вызова Bitrix24) | | 400 | `INVALID_REQUEST` | Некорректные значения полей | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список дел](/docs/entities/activities/list) - [Поля дела](/docs/entities/activities/fields) - [Сделки](/docs/entities/deals) - [Лиды](/docs/entities/leads) - [Entity API](/docs/entity-api) - [Лимиты и оптимизация](/docs/optimization) --- # Activities: Delete ## Удалить дело `DELETE /v1/activities/:id` Удаляет дело по ID. Восстановить удалённое дело через API нельзя — создавайте новое при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID дела | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/activities/3894" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/activities/3894" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities/3894', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Дело удалено') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities/3894', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 422 — дело не найдено: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Activity is not found." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Дело не найдено или нет прав на удаление | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список дел](/docs/entities/activities/list) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Activities: Fields ## Поля дела `GET /v1/activities/fields` Возвращает полный список доступных полей дела. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/activities/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/activities/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | RO | Описание | |------|-----|:--:|---------| | `id` | number | да | ID дела | | `typeId` | number | | Тип: `1` — встреча, `2` — звонок, `3` — задача, `4` — письмо, `5` — действие, `6` — пользовательское действие (**обязательно** при создании) | | `ownerTypeId` | number | | Тип родительской сущности: `1` — лид, `2` — сделка, `3` — контакт, `4` — компания | | `ownerId` | number | | ID родительской сущности. Поиск зависит от `ownerTypeId`: `GET /v1/deals`, `GET /v1/leads`, `GET /v1/contacts`, `GET /v1/companies` | | `associatedEntityId` | number | да | ID связанной сущности (звонок/письмо/встреча в b24-модуле). Заполняется автоматически после создания дела соответствующим провайдером | | `subject` | string | | Тема дела (**обязательно** при создании) | | `communications` | object[] | | Коммуникации дела (**обязательно** при создании). Массив объектов: `[{ "value": "+7…", "entityTypeId": 3, "entityId": 17 }]` — вложенные ключи в camelCase или ВЕРХНЕМ регистре Битрикс24. Подробнее — [Создать дело](/docs/entities/activities/create) | | `description` | string | | Описание | | `descriptionType` | number | | Тип описания: `1` — plain text, `3` — BBCode/HTML | | `responsibleId` | number | | Ответственный. Список: `GET /v1/users` | | `authorId` | number | да | Автор записи. Заполняется b24 на основании текущего пользователя при создании | | `editorId` | number | да | Последний редактор. Обновляется b24 при каждом изменении | | `priority` | number | | Приоритет: `1` — низкий, `2` — средний, `3` — высокий | | `direction` | number | | Направление: `1` — входящее, `2` — исходящее | | `location` | string | | Место проведения (для встреч) | | `completed` | boolean | | Завершена | | `status` | number | | Статус дела: `1` — ожидается, `2` — завершено, `3` — завершено автоматически | | `startTime` | datetime | | Дата начала | | `endTime` | datetime | | Дата окончания | | `deadline` | datetime | | Крайний срок. У дел без срока возвращается значение-заглушка `9999-12-30T21:00:00.000Z` — не реальная дата. Фильтр по меньшей дате `filter[` такие дела не выбирает, просроченными они не считаются | | `createdAt` | datetime | да | Дата создания | | `updatedAt` | datetime | да | Дата изменения | | `notifyType` | number | | Тип напоминания: `0` — выкл., `1` — за минуты, `2` — за часы, `3` — за дни | | `notifyValue` | number | | Значение напоминания (в единицах из `notifyType`) | | `providerId` | string | | ID провайдера дела (`CRM_CALL_LIST`, `IMOL`, `CRM_REQUEST` и т.п.) | | `providerTypeId` | string | | Подтип провайдера (зависит от `providerId`) | | `providerGroupId` | string | | Идентификатор группы провайдера (например, по треду e-mail) | | `providerParams` | object | | Произвольные параметры провайдера (структура зависит от `providerId`) | | `providerData` | string | | Сериализованные данные провайдера (XML/JSON в строке) | | `settings` | object | | Дополнительные настройки дела (структура зависит от `typeId` и `providerId`) | | `originId` | string | | Внешний ID, если дело пришло из стороннего канала (CTI, email) | | `originatorId` | string | | ID источника-инициатора (приложение/коннектор) | | `resultStatus` | number | | Статус результата дела (числовой код) | | `resultStream` | number | | Поток обработки результата | | `resultSourceId` | string | | Источник результата | | `resultMark` | number | | Оценка/маркер результата | | `resultValue` | number | | Численное значение результата | | `resultSum` | number | | Сумма по результату (например, чек) | | `resultCurrencyId` | string | | Валюта результата (`RUB`, `USD`, …) | | `autocompleteRule` | number | | Правило автозавершения дела (числовой код) | | `isIncomingChannel` | boolean | да | Дело пришло из входящего канала (open-line/звонок/письмо). Только чтение | | `bindings` | object | | Дополнительные привязки дела к сущностям CRM. Управление привязками после создания — через `/v1/activities/:activityId/bindings` | | `files` | object | | Прикреплённые файлы диска. Возвращается только при явном указании в `select` | | `webdavElements` | object | | Прикреплённые файлы диска (устаревший WebDAV). Возвращается только при явном указании в `select` | | `originVersion` | string | | Версия синхронизации с внешней системой — защищает от случайной перезаписи данных внешней интеграцией | > **Обязательные при создании** (`POST /v1/activities`): `subject`, `typeId`, `communications`. Поля помечены `required: true` в ответе `/fields`. Плюс **привязка** к CRM-сущности — через `ownerTypeId` + `ownerId` **или** через `entityTypeId`/`entityId` внутри `communications`. Детали — [Создать дело](/docs/entities/activities/create). ## Значения typeId | Значение | Тип дела | |----------|---------------| | `1` | Встреча | | `2` | Звонок | | `3` | Задача | | `4` | Письмо | | `5` | Действие | | `6` | Пользовательское действие | ## Значения ownerTypeId | Значение | Родительская сущность | Поиск | |----------|----------------------|-------| | `1` | Лид | `GET /v1/leads` | | `2` | Сделка | `GET /v1/deals` | | `3` | Контакт | `GET /v1/contacts` | | `4` | Компания | `GET /v1/companies` | ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "ID", "description": "Уникальный числовой идентификатор дела." }, "subject": { "type": "string", "readonly": false, "required": true, "label": "Тема", "description": "Тема дела. Обязательна при создании." }, "communications": { "type": "object", "readonly": false, "required": true, "label": "Коммуникации", "description": "Коммуникации дела. Обязательны при создании. Массив объектов с ключами в ВЕРХНЕМ регистре: [{ \"VALUE\": \"+7…\", \"ENTITY_TYPE_ID\": 3, \"ENTITY_ID\": 17 }]." }, "responsibleId": { "type": "number", "readonly": false, "label": "Ответственный", "description": "ID пользователя, ответственного за дело." } }, "batch": ["create", "update", "delete"] } } ``` Показаны 3 из множества полей. Полный список в таблице выше. ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать дело](/docs/entities/activities/create) - [Entity API](/docs/entity-api) - [Лимиты и оптимизация](/docs/optimization) --- # Activities: File Download ## Скачать файл дела `GET /v1/activities/:activityId/files/:fileId/download` Скачивает файл, прикреплённый к делу CRM — в том числе запись звонка. Ответ — бинарный поток с заголовком `Content-Disposition`. Этот эндпоинт нужен потому, что файл дела **не является файлом Диска**. `GET /v1/activities/:id` отдаёт каждый файл как `{ id, url }`, где `id` живёт в отдельном пространстве идентификаторов, пересекающемся с идентификаторами объектов Диска. Передать такой `id` в [скачивание файла Диска](/docs/entities/files/download) нельзя: с некоторой вероятностью придёт другой файл. А адрес из поля `url` приходит с пустым параметром авторизации, поэтому запрос по нему возвращает страницу входа с кодом `200` — не файл. Этот эндпоинт добавляет авторизацию сам и отдаёт содержимое. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `activityId` | path | number | да | ID дела. Получить: [`GET /v1/activities`](/docs/entities/activities/list) | | `fileId` | path | number | да | ID файла из массива `files` дела. Получить: [`GET /v1/activities/:id`](/docs/entities/activities/get) с `select`, включающим `files` | Тело запроса пустое. ## Примеры ### curl — личный ключ ```bash # Сохранить с исходным именем из заголовка Content-Disposition curl -OJ -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/activities/4257/files/5387/download # Указать имя файла явно curl -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/activities/4257/files/5387/download \ -o call-record.mp3 ``` ### curl — OAuth-приложение ```bash curl -OJ \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ https://vibecode.bitrix24.tech/v1/activities/4257/files/5387/download ``` ### JavaScript — личный ключ ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/activities/4257/files/5387/download', { headers: { 'X-Api-Key': 'YOUR_API_KEY' } }, ) if (!res.ok) { const { error } = await res.json() throw new Error(`${error.code}: ${error.message}`) } const audio = await res.arrayBuffer() console.log('получено байт:', audio.byteLength) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/activities/4257/files/5387/download', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }, ) const audio = await res.arrayBuffer() ``` ## Заголовки ответа При успехе возвращается бинарное содержимое файла (HTTP 200). Секции `## Поля ответа` нет — тело ответа не является JSON. | Заголовок | Пример значения | Описание | |-----------|-----------------|----------| | `Content-Type` | `audio/mpeg` | Тип содержимого, как его отдал Битрикс24 | | `Content-Disposition` | `attachment; filename="call-record.mp3"` | Имя файла для сохранения | | `Content-Length` | `22509` | Размер в байтах, если Битрикс24 его сообщил | ## Пример ответа при ошибке 404 — файл не принадлежит этому делу: ```json { "success": false, "error": { "code": "NOT_FOUND", "message": "File 999999 does not belong to activity 4257" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_PARAMS` | `activityId` или `fileId` не является положительным целым числом | | 401 | `TOKEN_MISSING` | У ключа не настроены токены Битрикс24 | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `crm` | | 404 | `NOT_FOUND` | Дела не существует, файл не принадлежит этому делу, либо у файла нет адреса для скачивания | | 502 | `DOWNLOAD_FAILED` | Битрикс24 назвал адрес за пределами домена аккаунта (по такому адресу запрос не уходит) либо не отдал файл. В том числе когда он ответил страницей вместо содержимого — значит ключ не удалось авторизовать для этого файла | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Файл обязан принадлежать названному делу.** Иначе — `404`, даже если файл существует. Проверка нужна не для строгости: Битрикс24 на чужой файл отвечает `200` со страницей входа, и без проверки вы получили бы HTML под видом файла. - **Права не обходятся.** Чтение дела — это и есть проверка доступа: если у ключа нет прав на дело, запрос завершится отказом. Битрикс24 дополнительно сверяет доступ пользователя к делу на своей стороне. - **Адрес наружу не отдаётся.** В адресе для скачивания содержится код авторизации, поэтому эндпоинт отдаёт только поток байтов. - **Файлы приходят в ответе дела не всегда.** В [списке дел](/docs/entities/activities/list) поле `files` возвращается только при явном указании в `select`. У [одного дела](/docs/entities/activities/get) оно приходит без дополнительных условий. ## Смотрите также - [Получить дело](/docs/entities/activities/get) - [Скачать вложение комментария таймлайна](/docs/entities/timelines/file-download) - [Скачать файл Диска](/docs/entities/files/download) - [Дела](/docs/entities/activities) --- # Activities: Get ## Получить дело `GET /v1/activities/:id` Возвращает дело по ID со всеми полями. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID дела | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/activities/3894" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/activities/3894" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities/3894', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Дело:', data.subject, '— завершена:', data.completed) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities/3894', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа Объект дела со всеми полями — см. [Поля дела](/docs/entities/activities/fields). ## Пример ответа ```json { "success": true, "data": { "id": 3894, "typeId": 1, "ownerTypeId": 2, "ownerId": 741, "subject": "Встреча по проекту", "description": "Обсуждение условий поставки", "responsibleId": 1, "priority": 2, "direction": 2, "completed": false, "startTime": "2026-04-16T10:00:00+03:00", "endTime": "2026-04-16T11:00:00+03:00", "deadline": "2026-04-16T11:00:00+03:00", "createdAt": "2026-04-15T14:30:00+03:00", "updatedAt": "2026-04-15T14:30:00+03:00" } } ``` ## Пример ответа при ошибке 404 — дело не найдено: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Дело с таким ID не найдено | | 403 | `ACCESS_DENIED` | Нет доступа к делу | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Обновить дело](/docs/entities/activities/update) - [Список дел](/docs/entities/activities/list) - [Поля дела](/docs/entities/activities/fields) - [Лимиты и оптимизация](/docs/optimization) --- # Activities: List ## Список дел `GET /v1/activities` Возвращает список CRM-дел с поддержкой фильтрации, сортировки и авто-пагинации. Фильтр по `ownerId` + `ownerTypeId` возвращает дела конкретной сделки, лида или контакта. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` авто-пагинация | | `offset` | number | `0` | Пропустить N записей. При `offset > 0` рекомендуется `limit ≤ 500` | | `select` | string | — | Выборка полей: `?select=id,subject,typeId,completed` | | `order` | object | — | Сортировка: `?order[deadline]=asc` | | `filter` | object | — | Фильтрация по полям `GET /v1/activities/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[ownerTypeId]=2&filter[ownerId]=741` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/activities?filter[ownerTypeId]=2&filter[ownerId]=741&limit=10&select=id,subject,typeId,completed" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/activities?filter[ownerTypeId]=2&filter[ownerId]=741&limit=10&select=id,subject,typeId,completed" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities?filter[ownerTypeId]=2&filter[ownerId]=741&limit=10&select=id,subject,typeId,completed', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} дел`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities?filter[ownerTypeId]=2&filter[ownerId]=741&limit=10&select=id,subject,typeId,completed', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив дел (поля — см. [Поля](/docs/entities/activities/fields)) | | `meta.total` | number | Общее количество записей | | `meta.hasMore` | boolean | Есть ещё записи | ## Пример ответа ```json { "success": true, "data": [ { "id": 3894, "typeId": 1, "ownerTypeId": 2, "ownerId": 741, "subject": "Встреча по проекту", "responsibleId": 1, "priority": 2, "direction": 2, "completed": false, "deadline": "2026-04-16T11:00:00+03:00", "createdAt": "2026-04-15T14:30:00+03:00", "updatedAt": "2026-04-15T14:30:00+03:00" } ], "meta": { "total": 84, "hasMore": true } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Авто-пагинация:** при `limit > 50` Вайбкод автоматически запрашивает несколько страниц. **Фильтр по сущности:** для получения дел конкретной сделки используйте `filter[ownerTypeId]=2&filter[ownerId]=741`. Значения `ownerTypeId`: `1` — лид, `2` — сделка, `3` — контакт, `4` — компания. **Поля для группировки и агрегации:** `typeId`, `ownerTypeId`, `responsibleId`, `authorId`, `editorId`, `completed`, `status`, `direction`, `providerId`, `providerTypeId`. Используются в `POST /v1/activities/aggregate` (см. [Агрегация](/docs/entities/activities/aggregate)). **Дела без срока:** у дел без установленного `deadline` поле возвращается со значением-заглушкой `9999-12-30T21:00:00.000Z` — не реальная дата. Фильтр по меньшей дате, например `filter[[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[ownerTypeId]=2&filter[ownerId]=741` | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки» | | `order` | object | — | Сортировка: `{ "deadline": "asc" }` | | `select` | string[] | — | Выборка полей: `["id", "subject", "typeId", "completed"]` | | `autoWindow` | boolean | `true` | Разбивать выборку по недельным окнам при фильтре по диапазону дат шире 14 дней. `false` отключает разбиение | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/activities/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "ownerTypeId": 2, "ownerId": 741, "completed": false }, "limit": 20, "order": { "deadline": "asc" } }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/activities/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "ownerTypeId": 2, "ownerId": 741, "completed": false }, "limit": 20, "order": { "deadline": "asc" } }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { ownerTypeId: 2, ownerId: 741, completed: false }, limit: 20, order: { deadline: 'asc' }, }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { ownerTypeId: 2, ownerId: 741, completed: false }, limit: 20, order: { deadline: 'asc' }, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив дел (поля — см. [Поля](/docs/entities/activities/fields)) | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временны́м окнам | | `meta.windowCount` | number | Число окон. Приходит при `autoWindowed: true` | | `meta.batchWaves` | number | Число волн параллельных запросов. Приходит при `autoWindowed: true` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа ```json { "success": true, "data": [ { "id": 3894, "typeId": 1, "ownerTypeId": 2, "ownerId": 741, "subject": "Встреча по проекту", "responsibleId": 1, "completed": false, "deadline": "2026-04-16T11:00:00+03:00", "createdAt": "2026-04-15T14:30:00+03:00" } ], "meta": { "total": 3, "hasMore": false, "durationMs": 336 } } ``` С фильтром по диапазону дат шире 14 дней в `meta` дополнительно приходят `autoWindowed`, `windowCount` и `batchWaves`: ```json { "success": true, "data": [ /* ... */ ], "meta": { "total": 269, "hasMore": true, "autoWindowed": true, "windowCount": 131, "batchWaves": 3, "durationMs": 1139 } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Разбиение по временны́м окнам.** Фильтр по диапазону дат шире 14 дней автоматически разбивается на недельные окна, которые выполняются параллельными волнами — так выборка обходит потолок в 5000 записей на один вызов. В `meta` тогда приходят `autoWindowed: true`, число окон `windowCount` и число волн `batchWaves`. Отключает разбиение параметр `autoWindow: false`. При активном разбиении `offset` больше нуля отклоняется с `UNSTABLE_OFFSET_PAGINATION`. **Поля для группировки и агрегации:** `typeId`, `ownerTypeId`, `responsibleId`, `authorId`, `editorId`, `completed`, `status`, `direction`, `providerId`, `providerTypeId`. Используются в `POST /v1/activities/aggregate` (см. [Агрегация](/docs/entities/activities/aggregate)). ## Смотрите также - [Список дел](/docs/entities/activities/list) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Activities: Transcript # Расшифровки звонков CRM `GET /v1/activities/:activityId/transcript` Возвращает готовую AI-расшифровку звонка клиента, зафиксированного в CRM как дело типа «Звонок» и обработанного на портале с помощью BitrixGPT. Метод только читает уже готовую расшифровку — генерацию не запускает. Битрикс24 API: `crm.activity.call.getTranscript` Скоуп: `crm` ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `activityId` (path) | number | да | ID дела-звонка. Список: [`GET /v1/activities`](/docs/entities/activities/list) | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/activities/12345/transcript" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/activities/12345/transcript" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities/12345/transcript', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { data } = await res.json() if (data.transcription === null) { // расшифровки ещё нет — это не ошибка } else { console.log(data.transcription) } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities/12345/transcript', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `transcription` | string \| null | Полный текст расшифровки. Значение `null` приходит со статусом `200`, когда расшифровки для звонка ещё нет — звонок не обработан или обработка не завершилась. Проверяйте `data.transcription === null` | ## Пример ответа Расшифровка готова: ```json { "success": true, "data": { "transcription": "Здравствуйте, чем могу помочь?" } } ``` Расшифровки пока нет — `transcription` равно `null`, статус остаётся `200`: ```json { "success": true, "data": { "transcription": null } } ``` ## Пример ответа при ошибке 403 — нет доступа к расшифровке: ```json { "success": false, "error": { "code": "BITRIX_ACCESS_DENIED", "message": "Доступ запрещён", "hint": "Access denied to this call transcript. Two possible causes: (1) the API key owner lacks read access to a CRM entity bound to this call activity, or (2) AI call processing is not enabled on this portal. Verify the user's CRM permissions, and confirm AI call processing (transcription) is turned on." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `BITRIX_ACCESS_DENIED` | Один код на два повода: нет прав на CRM-сущность, к которой привязан звонок, либо на портале выключена AI-обработка звонков. Поле `hint` называет оба | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 400 | `INVALID_PARAMS` | `activityId` не положительное целое число | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 404 | `ENTITY_NOT_FOUND` | Дело с таким `activityId` не найдено или не имеет CRM-привязок | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - Расшифровка доступна, если у ключа есть права на чтение хотя бы одной CRM-сущности — сделки, лида, контакта или компании, к которой привязан звонок. Дополнительно на портале должна быть включена AI-обработка звонков (BitrixGPT). - Расшифровка появляется не сразу: портал формирует её после завершения звонка. Пока обработка не закончена, `transcription` равно `null` со статусом `200`. Повторите запрос позже. ## Смотрите также - [Получить дело](/docs/entities/activities/get) - [Список дел](/docs/entities/activities/list) - [Привязки дел](/docs/entities/activities/bindings) - [Лимиты и оптимизация](/docs/optimization) --- # Activities: Update ## Обновить дело `PATCH /v1/activities/:id` Обновляет поля существующей дела. Передайте только изменяемые поля. Полный список в [справочнике полей](/docs/entities/activities/fields). ## Часто обновляемые поля | Параметр | Тип | Описание | |----------|-----|---------| | `completed` | boolean | Отметить завершённой | | `subject` | string | Тема | | `deadline` | datetime | Крайний срок | | `responsibleId` | number | Ответственный. Список: `GET /v1/users` | | `priority` | number | Приоритет: `1` — низкий, `2` — средний, `3` — высокий | | `description` | string | Описание | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/activities/3894" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "completed": true, "subject": "Встреча по проекту (завершена)" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/activities/3894" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "completed": true, "subject": "Встреча по проекту (завершена)" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities/3894', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ completed: true, subject: 'Встреча по проекту (завершена)', }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/activities/3894', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ completed: true, subject: 'Встреча по проекту (завершена)', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | object | Обновлённый объект дела со всеми полями — см. [Поля](/docs/entities/activities/fields) | Обновлённый объект дела — см. [Поля дела](/docs/entities/activities/fields). ## Пример ответа ```json { "success": true, "data": { "id": 100, "subject": "Обновлённая тема", "completed": true, "responsibleId": 1, "createdAt": "2026-04-15T12:00:00.000Z", "updatedAt": "2026-04-15T13:00:00.000Z" } } ``` ## Пример ответа при ошибке 404 — дело не найдено: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Дело не найдено | | 403 | `ACCESS_DENIED` | Нет доступа | | 400 | `INVALID_REQUEST` | Некорректные поля | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить дело](/docs/entities/activities/get) - [Поля дела](/docs/entities/activities/fields) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Addresses: Create ## Создать адрес `POST /v1/addresses` Создаёт адрес и привязывает его к владельцу. Три значения — `typeId`, `entityTypeId` и `entityId` — передаются в теле запроса вместе с полями адреса. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `typeId` | number | да | Тип адреса. Список: `GET /v1/addresses/fields` (поле `typeId`). Примеры: `1` — фактический, `6` — юридический, `8` — для корреспонденции, `11` — доставки | | `entityTypeId` | number | да | Тип владельца адреса. `8` — реквизит. Другие значения возможны для контактов, компаний, лидов | | `entityId` | number | да | ID владельца адреса. Для реквизита — ID из `GET /v1/requisites` | | `address1` | string | нет | Улица и дом | | `address2` | string | нет | Дополнительная строка адреса | | `city` | string | нет | Город | | `region` | string | нет | Район или регион | | `province` | string | нет | Область или штат | | `postalCode` | string | нет | Почтовый индекс | | `country` | string | нет | Страна (текстовое название) | | `countryCode` | string | нет | Двухбуквенный код страны (например `RU`). В документации REST Битрикс24 поле помечено как неиспользуемое и оставленное для обратной совместимости — значение сохраняется как передано, поэтому не стоит рассчитывать, что оно на что-то влияет | Полный список полей — [`GET /v1/addresses/fields`](./fields.md). ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/addresses" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "typeId": 11, "entityTypeId": 8, "entityId": 1, "city": "Москва", "address1": "ул. Ленина, 10", "postalCode": "101000" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/addresses" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "typeId": 11, "entityTypeId": 8, "entityId": 1, "city": "Москва", "address1": "ул. Ленина, 10" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/addresses', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ typeId: 11, entityTypeId: 8, entityId: 1, city: 'Москва', address1: 'ул. Ленина, 10', postalCode: '101000', }), }) const { success, data } = await res.json() console.log('Создан адрес:', data.typeId, data.entityTypeId, data.entityId) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/addresses', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ typeId: 11, entityTypeId: 8, entityId: 1, city: 'Москва', address1: 'ул. Ленина, 10', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Три значения ключа созданного адреса: `typeId`, `entityTypeId`, `entityId` | | `data.typeId` | number | Тип адреса из запроса | | `data.entityTypeId` | number | Тип владельца из запроса | | `data.entityId` | number | ID владельца из запроса | Ответ возвращает только ключ. Поля адреса — `city`, `address1`, `postalCode` и другие — в ответ не включаются. Прочитать сохранённый адрес — [`GET /v1/addresses/:typeId/:entityTypeId/:entityId`](./get.md). ## Пример ответа HTTP-статус: `201 Created` ```json { "success": true, "data": { "typeId": 11, "entityTypeId": 8, "entityId": 1 } } ``` ## Пример ответа при ошибке 400 — не передан один из ключевых параметров: ```json { "success": false, "error": { "code": "MISSING_COMPOSITE_KEY", "message": "POST /v1/addresses requires typeId, entityTypeId and entityId in the body. Example: { \"typeId\": 1, \"entityTypeId\": 8, \"entityId\": 42, \"city\": \"...\" }" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_COMPOSITE_KEY` | Не передан один или несколько из ключевых параметров `typeId`, `entityTypeId`, `entityId` | | 400 | `INVALID_REQUEST` | Тело запроса не является объектом | | 422 | `BITRIX_ERROR` | Битрикс24 отклонил запрос — неверный `typeId`, несуществующий `entityId` или другая ошибка на стороне Битрикс24 | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `crm`. This endpoint requires 'crm' scope | | 401 | `TOKEN_MISSING` | Не передан `X-Api-Key` или ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Ключ — в теле, не в пути.** В отличие от обновления и удаления, при создании три значения — `typeId`, `entityTypeId`, `entityId` — передаются в теле запроса, а не в URL. **Ответ — только ключ.** Ответ `201` возвращает только переданные `typeId`, `entityTypeId` и `entityId`. Сохранённых полей адреса в нём нет. ## Смотрите также - [Получить адрес](/docs/entities/addresses/get) - [Обновить адрес](/docs/entities/addresses/update) - [Список адресов](/docs/entities/addresses/list) - [Поля адреса](/docs/entities/addresses/fields) - [Реквизиты](/docs/entities/requisites) - [Batch](/docs/batch) --- # Addresses: Delete ## Удалить адрес `DELETE /v1/addresses/:typeId/:entityTypeId/:entityId` Удаляет адрес по трём значениям ключа: `typeId`, `entityTypeId`, `entityId`. Восстановить удалённый адрес через API нельзя — создавайте новый при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `typeId` (path) | number | да | Тип адреса. Примеры: `1` — фактический, `6` — юридический, `8` — для корреспонденции, `11` — доставки | | `entityTypeId` (path) | number | да | Тип владельца: `8` — реквизит, `3` — контакт, `4` — компания, `1` — лид | | `entityId` (path) | number | да | ID владельца адреса. Для реквизита — ID из `GET /v1/requisites` | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/addresses/11/8/1" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/addresses/11/8/1" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/addresses/11/8/1', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() if (success && data.deleted) { console.log('Адрес удалён') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/addresses/11/8/1', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Подтверждение удаления с эхом ключа | | `data.typeId` | number | Тип адреса из пути | | `data.entityTypeId` | number | Тип владельца из пути | | `data.entityId` | number | ID владельца из пути | | `data.deleted` | boolean | Всегда `true` при успешном удалении | ## Пример ответа ```json { "success": true, "data": { "typeId": 11, "entityTypeId": 8, "entityId": 1, "deleted": true } } ``` ## Пример ответа при ошибке 403 — нет скоупа `crm`: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_COMPOSITE_KEY` | Один или несколько параметров пути `typeId`, `entityTypeId`, `entityId` не являются положительными целыми числами | | 404 | `NOT_FOUND` | Адрес с таким составным ключом не найден | | 422 | `BITRIX_ERROR` | Битрикс24 отклонил удаление существующего адреса | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `crm`. This endpoint requires 'crm' scope | | 401 | `TOKEN_MISSING` | Не передан `X-Api-Key` или ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Ответ — `200 JSON`, не `204`.** Удаление адреса возвращает `200 OK` с JSON-телом, где `data.deleted` равно `true`, а не `204 No Content`. **Адрес компании или контакта хранится в реквизите.** Для компании (`4`) и контакта (`3`) адрес привязан к их реквизиту. Удаление по составному ключу компании или контакта автоматически удаляет адрес из нужного реквизита, поэтому удалять адрес можно по тому же ключу, по которому он был создан и читается. Для реквизита (`8`) и лида (`1`) ключ совпадает с местом хранения. **Адрес не найден — `404`.** Если адреса с таким составным ключом нет, эндпоинт возвращает `404 NOT_FOUND` и не выполняет удаление. ## Смотрите также - [Создать адрес](/docs/entities/addresses/create) - [Список адресов](/docs/entities/addresses/list) - [Получить адрес](/docs/entities/addresses/get) - [Реквизиты](/docs/entities/requisites) - [Batch](/docs/batch) --- # Addresses: Fields ## Поля адреса `GET /v1/addresses/fields` Возвращает схему полей адреса — список всех допустимых полей с типами, признаками обязательности и доступности для записи. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/addresses/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/addresses/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/addresses/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() const fieldNames = Object.keys(data.fields) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/addresses/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Битрикс24 | Тип | RO | Описание | |------|-----------|-----|----|---------| | `typeId` | `TYPE_ID` | number | — | Тип адреса. Обязательный, неизменяемый после создания | | `entityTypeId` | `ENTITY_TYPE_ID` | number | — | Тип владельца адреса. Обязательный, неизменяемый после создания | | `entityId` | `ENTITY_ID` | number | — | ID владельца адреса. Обязательный, неизменяемый после создания | | `address1` | `ADDRESS_1` | string | — | Улица, дом, корпус, строение | | `address2` | `ADDRESS_2` | string | — | Квартира, офис | | `city` | `CITY` | string | — | Город | | `postalCode` | `POSTAL_CODE` | string | — | Почтовый индекс | | `region` | `REGION` | string | — | Район | | `province` | `PROVINCE` | string | — | Область | | `country` | `COUNTRY` | string | — | Страна | | `countryCode` | `COUNTRY_CODE` | string | — | Код страны | | `locAddrId` | `LOC_ADDR_ID` | number | — | Идентификатор адреса местоположения | | `anchorTypeId` | `ANCHOR_TYPE_ID` | number | да | Тип сущности, к которой привязан адрес | | `anchorId` | `ANCHOR_ID` | number | да | ID сущности, к которой привязан адрес | RO — поле доступно только для чтения. Колонка «Битрикс24» — имя того же поля в Битрикс24. Каждое поле в `data.fields` описано объектом. Кроме признаков `type`, `isRequired`, `isReadOnly`, `isImmutable`, `isMultiple` и `isDynamic` там приходят три текстовых ключа: | Ключ | Описание | |------|---------| | `title` | Короткая подпись поля. Большинство подписей приходит из Битрикс24, они на языке портала. Там, где Битрикс24 вместо подписи отдаёт имя поля, например `TYPE_ID` или `COUNTRY_CODE`, подпись подставляет Вайбкод, и она приходит на русском языке | | `label` | Та же подпись, что в `title`. Приходит рядом с ним, потому что у остальных сущностей подпись лежит именно в `label` — так подписи можно читать одним способом на любой сущности | | `description` | Расширенное описание на русском языке: назначение поля, расшифровка кодов, поведение при записи. Приходит у тех полей, у которых есть что добавить к подписи | ## Пример ответа ```json { "success": true, "data": { "fields": { "typeId": { "type": "integer", "isRequired": true, "isReadOnly": false, "isImmutable": true, "isMultiple": false, "isDynamic": false, "title": "Тип адреса", "label": "Тип адреса", "description": "Код типа адреса. Битрикс24 определяет двенадцать, с 1 по 12: 1 — фактический (в англоязычном интерфейсе Битрикс24 — Street address), 2 — второй, 3 — третий, 4 — адрес регистрации, 5 — рабочий, 6 — юридический, 7 — дополнительный, 8 — для корреспонденции, 9 — бенефициара, 10 — адрес банка, 11 — доставки, 12 — платёжный. Какие из них доступны порталу, зависит от его страновой зоны, поэтому часть кодов конкретный портал может не вернуть никогда. Входит в составной ключ адреса и неизменяем после создания." }, "entityTypeId": { "type": "integer", "isRequired": true, "isReadOnly": false, "isImmutable": true, "isMultiple": false, "isDynamic": false, "title": "Тип владельца", "label": "Тип владельца", "description": "Код типа сущности-владельца: 1 — лид, 3 — контакт, 4 — компания, 8 — реквизит. Входит в составной ключ адреса и неизменяем после создания." }, "entityId": { "type": "integer", "isRequired": true, "isReadOnly": false, "isImmutable": true, "isMultiple": false, "isDynamic": false, "title": "ID владельца", "label": "ID владельца", "description": "Идентификатор сущности-владельца адреса. Входит в составной ключ адреса и неизменяем после создания." }, "address1": { "type": "string", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Улица, дом, корпус, строение", "label": "Улица, дом, корпус, строение" }, "address2": { "type": "string", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Квартира / офис", "label": "Квартира / офис" }, "city": { "type": "string", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Город", "label": "Город" }, "postalCode": { "type": "string", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Почтовый индекс", "label": "Почтовый индекс" }, "region": { "type": "string", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Район", "label": "Район" }, "province": { "type": "string", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Область", "label": "Область" }, "country": { "type": "string", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Страна", "label": "Страна" }, "countryCode": { "type": "string", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Код страны", "label": "Код страны", "description": "Двухбуквенный код страны. В документации REST Битрикс24 поле помечено как неиспользуемое и оставленное для обратной совместимости — значение сохраняется как передано, поэтому не стоит рассчитывать, что оно на что-то влияет." }, "locAddrId": { "type": "integer", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Идентификатор адреса местоположения", "label": "Идентификатор адреса местоположения" }, "anchorTypeId": { "type": "integer", "isRequired": false, "isReadOnly": true, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Тип якорной сущности", "label": "Тип якорной сущности", "description": "Код типа сущности, к которой привязан адрес: 3 — контакт, 4 — компания. Только для чтения." }, "anchorId": { "type": "integer", "isRequired": false, "isReadOnly": true, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "ID якорной сущности", "label": "ID якорной сущности", "description": "Идентификатор сущности, к которой привязан адрес. Только для чтения." } } } } ``` ## Пример ответа при ошибке 403 — у API-ключа нет скоупа `crm`: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Поля `typeId`, `entityTypeId`, `entityId` — неизменяемые.** Флаг `isImmutable: true` означает, что после создания адреса эти поля нельзя изменить. Они задают составной ключ и не передаются в теле запросов на обновление. ## Смотрите также - [Получить адрес](/docs/entities/addresses/get) - [Список адресов](/docs/entities/addresses/list) - [Поля реквизита](/docs/entities/requisites/fields) - [Адреса](/docs/entities/addresses) --- # Addresses: Get ## Получить адрес `GET /v1/addresses/:typeId/:entityTypeId/:entityId` Возвращает один адрес по составному ключу из трёх параметров: тип адреса, тип владельца и ID владельца. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `typeId` (path) | number | да | Тип адреса, коды с `1` по `12`: `1` — фактический (в англоязычном интерфейсе Битрикс24 — Street address), `2` — второй, `3` — третий, `4` — адрес регистрации, `5` — рабочий, `6` — юридический, `7` — дополнительный, `8` — для корреспонденции, `9` — бенефициара, `10` — адрес банка, `11` — доставки, `12` — платёжный. Какие из них доступны порталу, зависит от его страновой зоны, поэтому часть кодов конкретный портал может не вернуть никогда | | `entityTypeId` (path) | number | да | Тип владельца: `8` — реквизит, `3` — контакт, `4` — компания, `1` — лид | | `entityId` (path) | number | да | ID владельца адреса. Для реквизита — ID из `GET /v1/requisites` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/addresses/1/3/9" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/addresses/1/3/9" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/addresses/1/3/9', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Город:', data.city, 'Индекс:', data.postalCode) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/addresses/1/3/9', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект адреса | | `data.typeId` | number | Тип адреса | | `data.entityTypeId` | number | Тип владельца | | `data.entityId` | number | ID владельца | | `data.address1` | string \| null | Улица, дом, корпус, строение | | `data.address2` | string \| null | Квартира, офис | | `data.city` | string \| null | Город | | `data.postalCode` | string \| null | Почтовый индекс | | `data.region` | string \| null | Район | | `data.province` | string \| null | Область | | `data.country` | string \| null | Страна | | `data.countryCode` | string \| null | Код страны | | `data.locAddrId` | number | Идентификатор адреса местоположения | | `data.anchorTypeId` | number | Тип сущности, к которой привязан адрес (только чтение) | | `data.anchorId` | number | ID сущности, к которой привязан адрес (только чтение) | ## Пример ответа ```json { "success": true, "data": { "typeId": 1, "entityTypeId": 3, "entityId": 9, "address1": null, "address2": null, "city": null, "postalCode": null, "region": null, "province": null, "country": null, "countryCode": null, "locAddrId": 0, "anchorTypeId": 3, "anchorId": 9 } } ``` ## Пример ответа при ошибке 404 — адрес не найден: ```json { "success": false, "error": { "code": "NOT_FOUND", "message": "Address (typeId=1, entityTypeId=3, entityId=99999999) not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `NOT_FOUND` | Адрес с таким составным ключом не найден | | 400 | `INVALID_COMPOSITE_KEY` | Один из параметров пути не является положительным целым числом | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Поля адреса](/docs/entities/addresses/fields) - [Список адресов](/docs/entities/addresses/list) - [Обновить адрес](/docs/entities/addresses/update) - [Реквизиты](/docs/entities/requisites) - [Лимиты и оптимизация](/docs/optimization) --- # Addresses: List ## Список адресов `GET /v1/addresses` Возвращает список адресов CRM-сущностей с поддержкой фильтрации, сортировки и авто-пагинации. У адреса нет отдельного числового `id`: чтобы получить один адрес, используйте три значения — `typeId`, `entityTypeId` и `entityId`. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` Вайбкод автоматически запрашивает несколько страниц у Битрикс24 | | `offset` | number | `0` | Пропустить N записей. При `offset ≥ 2500` рекомендуется `limit ≤ 500` | | `sort` / `order` | string / object | — | Сортировка: `?sort=typeId` или `?order[typeId]=desc` | | `filter` | object | — | Фильтрация по полям `GET /v1/addresses/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[entityTypeId]=8&filter[entityId]=42` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/addresses?filter[entityTypeId]=8&filter[entityId]=42" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/addresses?filter[entityTypeId]=8&filter[entityId]=42" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/addresses?filter[entityTypeId]=8&filter[entityId]=42', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, } ) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} адресов`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/addresses?filter[entityTypeId]=8&filter[entityId]=42', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, } ) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив адресов (все поля — см. [Поля адреса](/docs/entities/addresses/fields)) | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | ## Пример ответа ```json { "success": true, "data": [ { "typeId": 1, "entityTypeId": 3, "entityId": 9, "address1": null, "address2": null, "city": null, "postalCode": null, "region": null, "province": null, "country": null, "countryCode": null, "locAddrId": 0, "anchorTypeId": 3, "anchorId": 9 }, { "typeId": 1, "entityTypeId": 3, "entityId": 17, "address1": null, "address2": null, "city": null, "postalCode": null, "region": null, "province": null, "country": null, "countryCode": null, "locAddrId": 0, "anchorTypeId": 3, "anchorId": 17 } ], "meta": { "total": 185, "hasMore": true } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 400 | `INVALID_FILTER` | Ошибка в синтаксисе фильтра | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **У адреса нет отдельного числового `id`.** Каждый адрес определяется тремя значениями: `typeId` (тип адреса), `entityTypeId` (тип владельца) и `entityId` (ID владельца). Чтобы получить один адрес, используйте `GET /v1/addresses/:typeId/:entityTypeId/:entityId`. **Авто-пагинация.** При `limit > 50` Вайбкод автоматически запрашивает несколько страниц у Битрикс24 и возвращает все записи в одном ответе. ## Смотрите также - [Получить адрес](/docs/entities/addresses/get) - [Поиск адресов](/docs/entities/addresses/search) - [Поля адреса](/docs/entities/addresses/fields) - [Синтаксис фильтрации](/docs/filtering) - [Entity API](/docs/entity-api) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Addresses: Search ## Поиск адресов `POST /v1/addresses/search` Поиск адресов с фильтрами и авто-пагинацией. Аналогичен `GET /v1/addresses`, но параметры передаются в теле запроса — подходит для сложных фильтров с большим количеством условий и для программной сборки запросов. ## Поля запроса (body) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям `GET /v1/addresses/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "entityTypeId": 8, "entityId": 42 }` | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей | | `sort` | object | — | Сортировка: `{ "typeId": "asc" }` | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/addresses/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "entityTypeId": 1, "city": "Пермь" }, "limit": 20 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/addresses/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "entityTypeId": 1, "city": "Пермь" }, "limit": 20 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/addresses/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { entityTypeId: 1, city: 'Пермь' }, limit: 20, }), }) const { success, data } = await res.json() console.log('Найдено:', data.length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/addresses/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { entityTypeId: 1, city: 'Пермь' }, limit: 20, }), }) const { success, data } = await res.json() ``` ### Другие сценарии Все адреса одного реквизита: ```json { "filter": { "entityTypeId": 8, "entityId": 42 } } ``` Адреса определённого типа у лида: ```json { "filter": { "entityTypeId": 1, "entityId": 1000755, "typeId": 1 } } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив адресов (все поля — см. [Поля адреса](/docs/entities/addresses/fields)) | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа ```json { "success": true, "data": [ { "typeId": 1, "entityTypeId": 1, "entityId": 1000755, "address1": "Монастырская улица, 5", "address2": "Вокзал Пермь I", "city": "Пермь", "postalCode": "614000", "region": "Пермский городской округ", "province": "Пермский край", "country": "Россия", "countryCode": null, "locAddrId": 483, "anchorTypeId": 1, "anchorId": 1000755 }, { "typeId": 1, "entityTypeId": 1, "entityId": 1000759, "address1": "улица Куйбышева, 97", "address2": "каб. 5", "city": "Пермь", "postalCode": "614045", "region": "Пермский городской округ", "province": "Пермский край", "country": "Россия", "countryCode": null, "locAddrId": 491, "anchorTypeId": 1, "anchorId": 1000759 } ], "meta": { "total": 107, "hasMore": true } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 400 | `INVALID_FILTER` | Ошибка в синтаксисе фильтра | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Имена полей в фильтре — camelCase.** Передавайте `typeId`, `entityTypeId`, `entityId`, `city`, `postalCode`, `countryCode` — те же имена, что отдаёт схема `GET /v1/addresses/fields`. ## Смотрите также - [Список адресов](/docs/entities/addresses/list) - [Поля адреса](/docs/entities/addresses/fields) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Addresses: Update ## Обновить адрес `PATCH /v1/addresses/:typeId/:entityTypeId/:entityId` Обновляет поля существующего адреса. Передавайте только те поля, которые нужно изменить. Полный список полей — [`GET /v1/addresses/fields`](./fields.md). ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `typeId` (path) | number | да | Тип адреса. Примеры: `1` — фактический, `6` — юридический, `8` — для корреспонденции, `11` — доставки | | `entityTypeId` (path) | number | да | Тип владельца: `8` — реквизит, `3` — контакт, `4` — компания, `1` — лид | | `entityId` (path) | number | да | ID владельца адреса. Для реквизита — ID из `GET /v1/requisites` | ## Поля запроса (body) | Поле | Тип | Описание | |------|-----|---------| | `address1` | string | Улица и дом | | `address2` | string | Дополнительная строка адреса | | `city` | string | Город | | `region` | string | Район или регион | | `province` | string | Область или штат | | `postalCode` | string | Почтовый индекс | | `country` | string | Страна (текстовое название) | | `countryCode` | string | Двухбуквенный код страны (например `RU`). В документации REST Битрикс24 поле помечено как неиспользуемое и оставленное для обратной совместимости — значение сохраняется как передано, поэтому не стоит рассчитывать, что оно на что-то влияет | Поля `typeId`, `entityTypeId`, `entityId` в теле запроса игнорируются — ключ задаётся только в пути. ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/addresses/11/8/1" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "city": "Санкт-Петербург", "address1": "Невский пр., 28", "postalCode": "191186" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/addresses/11/8/1" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "city": "Санкт-Петербург", "address1": "Невский пр., 28" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/addresses/11/8/1', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ city: 'Санкт-Петербург', address1: 'Невский пр., 28', postalCode: '191186', }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/addresses/11/8/1', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ city: 'Санкт-Петербург', address1: 'Невский пр., 28', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Подтверждение обновления с эхом ключа | | `data.typeId` | number | Тип адреса из пути | | `data.entityTypeId` | number | Тип владельца из пути | | `data.entityId` | number | ID владельца из пути | | `data.updated` | boolean | Всегда `true` при успешном обновлении | ## Пример ответа ```json { "success": true, "data": { "typeId": 11, "entityTypeId": 8, "entityId": 1, "updated": true } } ``` ## Пример ответа при ошибке 403 — нет скоупа `crm`: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_COMPOSITE_KEY` | Один или несколько параметров пути `typeId`, `entityTypeId`, `entityId` не являются положительными целыми числами | | 400 | `INVALID_REQUEST` | Тело запроса не является объектом | | 404 | `NOT_FOUND` | Адрес с таким составным ключом не найден | | 422 | `BITRIX_ERROR` | Битрикс24 отклонил обновление существующего адреса | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `crm`. This endpoint requires 'crm' scope | | 401 | `TOKEN_MISSING` | Не передан `X-Api-Key` или ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Ключ в пути, не в теле.** Адрес определяется тройкой `/:typeId/:entityTypeId/:entityId` в URL. Если передать `typeId`, `entityTypeId` или `entityId` в теле, они будут проигнорированы — приоритет у значений из пути. **Адрес компании или контакта хранится в реквизите.** Для компании (`4`) и контакта (`3`) адрес привязан к их реквизиту. Обновление по составному ключу компании или контакта автоматически применяется к нужному реквизиту, поэтому обновлять адрес можно по тому же ключу, по которому он был создан и читается. Для реквизита (`8`) и лида (`1`) ключ совпадает с местом хранения. **Адрес не найден — `404`.** Если адреса с таким составным ключом нет, эндпоинт возвращает `404 NOT_FOUND` и не выполняет обновление. ## Смотрите также - [Создать адрес](/docs/entities/addresses/create) - [Получить адрес](/docs/entities/addresses/get) - [Удалить адрес](/docs/entities/addresses/delete) - [Поля адреса](/docs/entities/addresses/fields) - [Реквизиты](/docs/entities/requisites) - [Batch](/docs/batch) --- # Bank Details: Create ## Создать банковский реквизит `POST /v1/bank-details` Создаёт новый банковский реквизит и привязывает его к реквизиту CRM. Восстановить удалённую запись нельзя — создавайте новую при необходимости. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `entityId` | number | да | ID реквизита-владельца. Поиск: `GET /v1/requisites` | | `name` | string | да | Название банковского реквизита | | `entityTypeId` | number | нет | Тип родительской сущности. Укажите `8`, чтобы привязать запись к реквизиту | | `rqBik` | string | нет | БИК банка | | `rqAccNum` | string | нет | Расчётный счёт | | `rqCorAccNum` | string | нет | Корреспондентский счёт | | `rqSwift` | string | нет | Код SWIFT | | `rqIban` | string | нет | Номер IBAN | | `rqBankName` | string | нет | Наименование банка | | `rqBankAddr` | string | нет | Адрес банка | | `rqAccName` | string | нет | Наименование владельца счёта | | `rqAccCurrency` | string | нет | Валюта счёта | | `active` | boolean | нет | Активен ли реквизит. По умолчанию `true` | | `sort` | number | нет | Порядок сортировки. По умолчанию `500` | | `code` / `xmlId` / `originatorId` | string | нет | Внешние идентификаторы для синхронизации | | `comments` | string | нет | Комментарий | Поля `id`, `createdAt`, `updatedAt`, `createdBy`, `modifyBy` заполняются системой и игнорируются при записи. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/bank-details" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "entityTypeId": 8, "entityId": 1, "name": "Расчётный счёт", "rqBik": "044525225", "rqAccNum": "40702810500000000001", "rqSwift": "SABRRUMM" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/bank-details" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "entityTypeId": 8, "entityId": 1, "name": "Расчётный счёт", "rqBik": "044525225", "rqAccNum": "40702810500000000001", "rqSwift": "SABRRUMM" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bank-details', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ entityTypeId: 8, entityId: 1, name: 'Расчётный счёт', rqBik: '044525225', rqAccNum: '40702810500000000001', rqSwift: 'SABRRUMM', }), }) const { success, data } = await res.json() console.log('Создан банковский реквизит ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bank-details', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ entityTypeId: 8, entityId: 1, name: 'Расчётный счёт', rqBik: '044525225', rqAccNum: '40702810500000000001', rqSwift: 'SABRRUMM', }), }) const { success, data } = await res.json() console.log('Создан банковский реквизит ID:', data.id) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Созданный банковский реквизит | | `data.id` | number | Идентификатор новой записи | | `data.entityId` | number | ID реквизита-владельца | | `data.countryId` | number | ID страны; `0`, если страна не задана | | `data.name` | string \| null | Название | | `data.active` | boolean | Активен ли реквизит | | `data.sort` | number | Порядок сортировки | | `data.rqBik` | string \| null | БИК банка | | `data.rqAccNum` | string \| null | Расчётный счёт | | `data.rqCorAccNum` | string \| null | Корреспондентский счёт | | `data.rqSwift` | string \| null | Код SWIFT | | `data.rqIban` | string \| null | Номер IBAN | | `data.rqBankName` | string \| null | Наименование банка | | `data.rqBankAddr` | string \| null | Адрес банка | | `data.rqAccName` | string \| null | Наименование владельца счёта | | `data.rqAccCurrency` | string \| null | Валюта счёта | | `data.comments` | string \| null | Комментарий | | `data.createdAt` | datetime | Дата создания (ISO 8601) | | `data.updatedAt` | datetime \| null | Дата последнего изменения | | `data.createdBy` | number | ID создателя | | `data.modifyBy` | number \| null | `null` сразу после создания | Незаполненные поля возвращаются как `null`. Полный список — [`GET /v1/bank-details/fields`](/docs/entities/bank-details/fields). ## Пример ответа HTTP-статус: `201 Created` ```json { "success": true, "data": { "id": 19, "entityId": 1, "countryId": 0, "createdAt": "2026-06-10T10:14:29.000Z", "updatedAt": null, "createdBy": 1, "modifyBy": null, "name": "Расчётный счёт", "code": null, "xmlId": null, "originatorId": null, "active": true, "sort": 500, "rqBankName": null, "rqBankAddr": null, "rqBik": "044525225", "rqAccName": null, "rqAccNum": "40702810500000000001", "rqAccCurrency": null, "rqCorAccNum": null, "rqIban": null, "rqSwift": "SABRRUMM", "comments": null } } ``` ## Пример ответа при ошибке 422 — не передан `entityId`: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "ENTITY_ID is not defined or invalid." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Не передан `entityTypeId` или `entityId`, либо Битрикс24 отклонил значение поля | | 403 | `SCOPE_DENIED` | Ключ не имеет скоупа `crm`. Сообщение: `This endpoint requires 'crm' scope` | | 401 | `TOKEN_MISSING` | Не передан `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`entityTypeId` не возвращается на чтении.** Это поле-владелец: его передают при создании со значением `8`, но в ответе `GET /v1/bank-details/:id` и в списке его нет. ## Смотрите также - [Список банковских реквизитов](/docs/entities/bank-details/list) - [Обновить банковский реквизит](/docs/entities/bank-details/update) - [Удалить банковский реквизит](/docs/entities/bank-details/delete) - [Поля банковского реквизита](/docs/entities/bank-details/fields) - [Реквизиты](/docs/entities/requisites) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Bank Details: Delete ## Удалить банковский реквизит `DELETE /v1/bank-details/:id` Удаляет банковский реквизит по ID. Восстановить удалённую запись через API нельзя — создавайте новую при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID банковского реквизита | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/bank-details/19" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/bank-details/19" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bank-details/19', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Банковский реквизит удалён') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bank-details/19', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом. Признак успеха — код ответа, не содержимое. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — банковский реквизит не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "The RequisiteBankDetail with ID '999999' is not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Банковский реквизит с таким ID не найден | | 403 | `SCOPE_DENIED` | Ключ не имеет скоупа `crm`. Сообщение: `This endpoint requires 'crm' scope` | | 401 | `TOKEN_MISSING` | Не передан `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список банковских реквизитов](/docs/entities/bank-details/list) - [Получить банковский реквизит](/docs/entities/bank-details/get) - [Обновить банковский реквизит](/docs/entities/bank-details/update) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Bank Details: Fields ## Поля банковского реквизита `GET /v1/bank-details/fields` Возвращает схему всех полей сущности банковского реквизита: типы, признак «только для чтения» и обязательность. ## Формат ответа Каждое поле в `data.fields` содержит: | Ключ | Тип | Описание | |------|-----|---------| | `type` | string | Тип значения: `number`, `string`, `boolean`, `datetime` | | `readonly` | boolean | `true` — поле не принимается при создании и обновлении | | `required` | boolean | `true` — поле обязательно при создании (присутствует только когда `true`) | | `label` | string | Человекочитаемое название поля на русском языке | | `description` | string | Пояснение к полю на русском языке | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/bank-details/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/bank-details/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bank-details/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Все поля:', Object.keys(data.fields)) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bank-details/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля из схемы Вайбкод ### Служебные | Поле | Битрикс24 | Тип | RO | Описание | |------|-----------|-----|:--:|---------| | `id` | `ID` | number | да | Идентификатор банковского реквизита | | `entityTypeId` | `ENTITY_TYPE_ID` | number | нет | Тип сущности-владельца. Всегда `8` (реквизит). Только для записи — в ответе `get` не возвращается | | `entityId` | `ENTITY_ID` | number | нет | ID реквизита-владельца | | `countryId` | `COUNTRY_ID` | number | нет | ID страны. `0` — страна не указана | | `name` | `NAME` | string | нет | Название банковского реквизита | | `code` | `CODE` | string | нет | Символьный код для внешних интеграций | | `xmlId` | `XML_ID` | string | нет | Внешний идентификатор для синхронизации | | `originatorId` | `ORIGINATOR_ID` | string | нет | ID системы-источника | | `active` | `ACTIVE` | boolean | нет | Активна ли запись | | `sort` | `SORT` | number | нет | Порядок сортировки | | `comments` | `COMMENTS` | string | нет | Комментарий к записи | | `createdAt` | `DATE_CREATE` | datetime | да | Дата создания (ISO 8601) | | `updatedAt` | `DATE_MODIFY` | datetime | да | Дата последнего изменения (ISO 8601) | | `createdBy` | `CREATED_BY_ID` | number | да | ID создателя | | `modifyBy` | `MODIFY_BY_ID` | number | да | ID последнего редактора | ### Банковские реквизиты | Поле | Битрикс24 | Тип | RO | Описание | |------|-----------|-----|:--:|---------| | `rqBankName` | `RQ_BANK_NAME` | string | нет | Наименование банка | | `rqBankAddr` | `RQ_BANK_ADDR` | string | нет | Адрес банка | | `rqBankRouteNum` | `RQ_BANK_ROUTE_NUM` | string | нет | Маршрутный номер банка | | `rqBankCode` | `RQ_BANK_CODE` | string | нет | Код банка | | `rqBik` | `RQ_BIK` | string | нет | БИК | | `rqMfo` | `RQ_MFO` | string | нет | МФО (Украина) | | `rqAccName` | `RQ_ACC_NAME` | string | нет | Наименование счёта | | `rqAccNum` | `RQ_ACC_NUM` | string | нет | Расчётный счёт | | `rqAccType` | `RQ_ACC_TYPE` | string | нет | Тип счёта | | `rqCorAccNum` | `RQ_COR_ACC_NUM` | string | нет | Корреспондентский счёт | | `rqAccCurrency` | `RQ_ACC_CURRENCY` | string | нет | Валюта счёта | | `rqIik` | `RQ_IIK` | string | нет | ИИК (Казахстан) | | `rqAgencyName` | `RQ_AGENCY_NAME` | string | нет | Наименование агентства | ### Международные реквизиты | Поле | Битрикс24 | Тип | RO | Описание | |------|-----------|-----|:--:|---------| | `rqIban` | `RQ_IBAN` | string | нет | IBAN | | `rqSwift` | `RQ_SWIFT` | string | нет | SWIFT-код | ### Реквизиты Франции | Поле | Битрикс24 | Тип | RO | Описание | |------|-----------|-----|:--:|---------| | `rqBic` | `RQ_Bic` | string | нет | BIC (французская форма; отличается от `rqBik`) | | `rqCodeb` | `RQ_CODEB` | string | нет | Код банка (Франция) | | `rqCodeg` | `RQ_CODEG` | string | нет | Код гуйше (Франция) | | `rqRib` | `RQ_RIB` | string | нет | RIB (Франция) | ## Поля Битрикс24 вне схемы (в UPPER_SNAKE_CASE) Эти поля Битрикс24 не входят в основную схему Вайбкод и доступны напрямую под исходным именем: | Поле | Тип | RO | Описание | |------|-----|:--:|---------| | `RQ_BIC` | string | нет | BIC в исходном формате Битрикс24 (отличается от `rqBic`) | ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true }, "entityTypeId": { "type": "number", "readonly": false, "notReturned": true }, "entityId": { "type": "number", "readonly": false, "required": true }, "countryId": { "type": "number", "readonly": false }, "name": { "type": "string", "readonly": false, "required": true }, "code": { "type": "string", "readonly": false }, "xmlId": { "type": "string", "readonly": false }, "originatorId": { "type": "string", "readonly": false }, "active": { "type": "boolean", "readonly": false }, "sort": { "type": "number", "readonly": false }, "comments": { "type": "string", "readonly": false }, "createdAt": { "type": "datetime", "readonly": true }, "updatedAt": { "type": "datetime", "readonly": true }, "createdBy": { "type": "number", "readonly": true }, "modifyBy": { "type": "number", "readonly": true }, "rqBankName": { "type": "string", "readonly": false }, "rqBankAddr": { "type": "string", "readonly": false }, "rqBankRouteNum": { "type": "string", "readonly": false }, "rqBankCode": { "type": "string", "readonly": false }, "rqAccNum": { "type": "string", "readonly": false }, "rqCorAccNum": { "type": "string", "readonly": false }, "rqIik": { "type": "string", "readonly": false }, "rqMfo": { "type": "string", "readonly": false }, "rqAccName": { "type": "string", "readonly": false }, "rqAccCurrency": { "type": "string", "readonly": false }, "rqBik": { "type": "string", "readonly": false }, "rqSwift": { "type": "string", "readonly": false }, "rqIban": { "type": "string", "readonly": false }, "rqAgencyName": { "type": "string", "readonly": false }, "rqAccType": { "type": "string", "readonly": false }, "rqBic": { "type": "string", "readonly": false }, "rqCodeb": { "type": "string", "readonly": false }, "rqCodeg": { "type": "string", "readonly": false }, "rqRib": { "type": "string", "readonly": false }, "RQ_BIC": { "type": "string", "readonly": false, "label": "RQ_BIC" } }, "batch": ["create", "update", "delete"] } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm`. Требуется: `This endpoint requires 'crm' scope` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить банковский реквизит](/docs/entities/bank-details/get) - [Список банковских реквизитов](/docs/entities/bank-details/list) - [Создать банковский реквизит](/docs/entities/bank-details/create) - [Реквизиты](/docs/entities/requisites) --- # Bank Details: Get ## Получить банковский реквизит `GET /v1/bank-details/:id` Возвращает банковский реквизит по ID со всеми полями записи. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID банковского реквизита | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/bank-details/19" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/bank-details/19" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bank-details/19', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Счёт:', data.name, '— БИК', data.rqBik) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bank-details/19', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект банковского реквизита | | `data.id` | number | Идентификатор банковского реквизита | | `data.entityId` | number | ID реквизита-владельца. Источник: `GET /v1/requisites` | | `data.countryId` | number | ID страны. `0` — страна не указана | | `data.name` | string | Название банковского реквизита | | `data.active` | boolean | Активна ли запись | | `data.sort` | number | Порядок сортировки | | `data.code` | string \| null | Символьный код для внешних интеграций | | `data.xmlId` | string \| null | Внешний идентификатор для синхронизации | | `data.originatorId` | string \| null | ID системы-источника | | `data.comments` | string \| null | Комментарий к записи | | `data.createdAt` | datetime | Дата создания (ISO 8601) | | `data.updatedAt` | datetime \| null | Дата последнего изменения (ISO 8601) | | `data.createdBy` | number | ID создателя | | `data.modifyBy` | number \| null | ID последнего редактора | | `data.rqBankName` | string \| null | Наименование банка | | `data.rqBankAddr` | string \| null | Адрес банка | | `data.rqBankRouteNum` | string \| null | Маршрутный номер банка | | `data.rqBankCode` | string \| null | Код банка | | `data.rqBik` | string \| null | БИК | | `data.rqAccNum` | string \| null | Расчётный счёт | | `data.rqCorAccNum` | string \| null | Корреспондентский счёт | | `data.rqSwift` | string \| null | SWIFT-код | | `data.rqIban` | string \| null | IBAN | | `data.rqIik` | string \| null | ИИК (Казахстан) | | `data.rqMfo` | string \| null | МФО (Украина) | | `data.rqAccName` | string \| null | Наименование счёта | | `data.rqAccCurrency` | string \| null | Валюта счёта | | `data.rqAccType` | string \| null | Тип счёта | | `data.rqAgencyName` | string \| null | Наименование агентства | | `data.rqBic` | string \| null | BIC (международный, отдельно от `rqBik`) | | `data.rqCodeb` | string \| null | Код банка (Франция, `RQ_CODEB`) | | `data.rqCodeg` | string \| null | Код гуйше (Франция, `RQ_CODEG`) | | `data.rqRib` | string \| null | RIB (Франция) | Полный список полей с типами и признаком `readonly` — [Поля банковского реквизита](/docs/entities/bank-details/fields). ## Пример ответа ```json { "success": true, "data": { "id": 19, "entityId": 1, "countryId": 0, "createdAt": "2026-06-10T10:14:29.000Z", "updatedAt": null, "createdBy": 1, "modifyBy": null, "name": "Расчётный счёт", "code": null, "xmlId": null, "originatorId": null, "active": true, "sort": 500, "rqBankName": null, "rqBankCode": null, "rqBankAddr": null, "rqBankRouteNum": null, "rqBik": "044525225", "rqMfo": null, "rqAccName": null, "rqAccNum": "40702810500000000001", "rqAccType": null, "rqIik": null, "rqAccCurrency": null, "rqCorAccNum": null, "rqIban": null, "rqSwift": "SABRRUMM", "rqBic": null, "rqCodeb": null, "rqCodeg": null, "rqRib": null, "rqAgencyName": null, "comments": null } } ``` ## Пример ответа при ошибке 404 — банковский реквизит не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "The RequisiteBankDetail with ID '999999' is not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Банковский реквизит с таким ID не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`entityTypeId` в ответе отсутствует.** Поле `entityTypeId` передаётся при создании банковского реквизита (всегда `8` — реквизит), но в ответах `get` и `list` не возвращается. Это поле-владелец, только для записи. **`countryId` равен `0` у записей без страны.** Если при создании страна не указана, поле возвращает числовое значение `0`, а не `null`. ## Смотрите также - [Поля банковского реквизита](/docs/entities/bank-details/fields) - [Список банковских реквизитов](/docs/entities/bank-details/list) - [Обновить банковский реквизит](/docs/entities/bank-details/update) - [Удалить банковский реквизит](/docs/entities/bank-details/delete) - [Реквизиты](/docs/entities/requisites) - [Лимиты и оптимизация](/docs/optimization) --- # Bank Details: List ## Список банковских реквизитов `GET /v1/bank-details` Возвращает список банковских реквизитов с поддержкой фильтрации, сортировки и авто-пагинации. Банковский реквизит всегда принадлежит конкретному реквизиту — для получения реквизитов конкретного реквизита передавайте фильтр по `entityId`. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` Вайбкод автоматически запрашивает несколько страниц у Битрикс24 | | `offset` | number | `0` | Пропустить N записей. При `offset ≥ 2500` рекомендуется `limit ≤ 500` | | `select` | string | — | Выборка полей: `?select=id,name,rqBik,rqAccNum` | | `sort` | string | — | Сортировка кратким синтаксисом: `?sort=-id`, минус означает убывание. Несколько полей — через запятую: `?sort=-id,name` | | `order` | object | — | Сортировка: `?order[id]=desc`. Если переданы и `sort`, и `order`, применяется `sort` | | `filter` | object | — | Фильтрация по полям `GET /v1/bank-details/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[entityId]=3` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/bank-details?filter[entityId]=3" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/bank-details?filter[entityId]=3" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bank-details?filter[entityId]=3', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} банковских реквизитов`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bank-details?filter[entityId]=3', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив банковских реквизитов (все поля — см. [Поля банковского реквизита](/docs/entities/bank-details/fields)) | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | ## Пример ответа ```json { "success": true, "data": [ { "id": 3, "entityId": 3, "countryId": 1, "name": "Банковские реквизиты 1", "active": true, "sort": 500, "code": null, "xmlId": null, "rqBankName": "Реквизиты 1", "rqBankAddr": null, "rqBik": null, "rqAccNum": null, "rqCorAccNum": null, "rqSwift": null, "rqIban": null, "createdAt": "2020-05-22T11:56:53.000Z", "updatedAt": "2023-12-05T11:50:19.000Z", "createdBy": 1, "modifyBy": 779 }, { "id": 5, "entityId": 11, "countryId": 1, "name": "Банковские реквизиты 1", "active": true, "sort": 500, "code": null, "xmlId": null, "rqBankName": "банк", "rqBankAddr": "тестовый адрес", "rqBik": "13142323452", "rqAccNum": "234245746878032451534", "rqCorAccNum": "235134524566748725431", "rqSwift": null, "rqIban": null, "createdAt": "2020-06-30T09:53:58.000Z", "updatedAt": null, "createdBy": 1, "modifyBy": null } ], "meta": { "total": 6, "hasMore": true } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 400 | `INVALID_FILTER` | Ошибка в синтаксисе фильтра | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`entityTypeId` не возвращается в ответе.** Это поле передаётся только при создании. В ответах `GET /v1/bank-details` и `GET /v1/bank-details/:id` поле отсутствует. **`countryId = 0` при отсутствии страны.** Если страна не указана, поле `countryId` возвращается как `0`, а не `null`. **Авто-пагинация.** При `limit > 50` Вайбкод автоматически запрашивает несколько страниц у Битрикс24 и возвращает все записи в одном ответе. ## Смотрите также - [Поиск банковских реквизитов](/docs/entities/bank-details/search) - [Поля банковского реквизита](/docs/entities/bank-details/fields) - [Реквизиты](/docs/entities/requisites) - [Синтаксис фильтрации](/docs/filtering) - [Entity API](/docs/entity-api) - [Batch](/docs/batch) --- # Bank Details: Search ## Поиск банковских реквизитов `POST /v1/bank-details/search` Поиск банковских реквизитов с фильтрами и авто-пагинацией. Аналогичен `GET /v1/bank-details`, но параметры передаются в теле запроса — подходит для сложных фильтров с большим количеством условий и для программной сборки запросов. ## Поля запроса (body) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям `GET /v1/bank-details/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "entityId": 3, "active": true }` | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки» | | `order` | object | — | Сортировка: `{ "id": "desc" }` | | `select` | string[] | — | Выборка полей: `["id", "name", "rqBik", "rqAccNum"]` | | `autoWindow` | boolean | `true` | Разбивать выборку по недельным окнам при фильтре по диапазону дат шире 14 дней. `false` отключает разбиение | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/bank-details/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "entityId": 3, "active": true }, "limit": 20, "order": { "id": "asc" } }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/bank-details/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "entityId": 3, "active": true }, "limit": 20, "order": { "id": "asc" } }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bank-details/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { entityId: 3, active: true }, limit: 20, order: { id: 'asc' }, }), }) const { success, data } = await res.json() console.log('Найдено:', data.length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bank-details/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { entityId: 3, active: true }, limit: 20, order: { id: 'asc' }, }), }) const { success, data } = await res.json() ``` ### Другие сценарии Все банковские реквизиты одного реквизита: ```json { "filter": { "entityId": 11 } } ``` Фильтр по БИК: ```json { "filter": { "rqBik": "13142323452" } } ``` С выборкой конкретных полей: ```json { "filter": { "active": true }, "select": ["id", "entityId", "name", "rqBik", "rqAccNum"], "order": { "id": "asc" } } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив банковских реквизитов (все поля — см. [Поля банковского реквизита](/docs/entities/bank-details/fields)) | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временны́м окнам | | `meta.windowCount` | number | Число окон. Приходит при `autoWindowed: true` | | `meta.batchWaves` | number | Число волн параллельных запросов. Приходит при `autoWindowed: true` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа ```json { "success": true, "data": [ { "id": 3, "entityId": 3, "countryId": 1, "name": "Банковские реквизиты 1", "active": true, "sort": 500, "code": null, "xmlId": null, "rqBankName": "Реквизиты 1", "rqBankAddr": null, "rqBik": null, "rqAccNum": null, "rqCorAccNum": null, "rqSwift": null, "rqIban": null, "createdAt": "2020-05-22T11:56:53.000Z", "updatedAt": "2023-12-05T11:50:19.000Z", "createdBy": 1, "modifyBy": 779 }, { "id": 5, "entityId": 11, "countryId": 1, "name": "Банковские реквизиты 1", "active": true, "sort": 500, "code": null, "xmlId": null, "rqBankName": "банк", "rqBankAddr": "тестовый адрес", "rqBik": "13142323452", "rqAccNum": "234245746878032451534", "rqCorAccNum": "235134524566748725431", "rqSwift": null, "rqIban": null, "createdAt": "2020-06-30T09:53:58.000Z", "updatedAt": null, "createdBy": 1, "modifyBy": null } ], "meta": { "total": 6, "hasMore": true } } ``` С фильтром по диапазону дат шире 14 дней в `meta` дополнительно приходят `autoWindowed`, `windowCount` и `batchWaves`: ```json { "success": true, "data": [ /* ... */ ], "meta": { "total": 2, "hasMore": false, "autoWindowed": true, "windowCount": 131, "batchWaves": 3, "durationMs": 1497 } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 400 | `INVALID_FILTER` | Ошибка в синтаксисе фильтра | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Разбиение по временны́м окнам.** Фильтр по диапазону дат шире 14 дней автоматически разбивается на недельные окна, которые выполняются параллельными волнами — так выборка обходит потолок в 5000 записей на один вызов. В `meta` тогда приходят `autoWindowed: true`, число окон `windowCount` и число волн `batchWaves`. Отключает разбиение параметр `autoWindow: false`. При активном разбиении `offset` больше нуля отклоняется с `UNSTABLE_OFFSET_PAGINATION`. **`entityTypeId` не возвращается в ответе.** Это поле передаётся только при создании. В ответах поиска поле отсутствует — фильтровать по `entityId` (ID реквизита-владельца). **Пагинация.** При `limit > 50` запрос автоматически разбивается на несколько вызовов к Битрикс24. Для больших выборок используйте `offset` и постраничные запросы. ## Смотрите также - [Список банковских реквизитов](/docs/entities/bank-details/list) - [Поля банковского реквизита](/docs/entities/bank-details/fields) - [Реквизиты](/docs/entities/requisites) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) --- # Bank Details: Update ## Обновить банковский реквизит `PATCH /v1/bank-details/:id` Обновляет поля существующего банковского реквизита. Передавайте только те поля, которые нужно изменить. Полный список — [`GET /v1/bank-details/fields`](/docs/entities/bank-details/fields). ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID банковского реквизита | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `name` | string | нет | Название банковского реквизита | | `rqBik` | string | нет | БИК банка | | `rqAccNum` | string | нет | Расчётный счёт | | `rqCorAccNum` | string | нет | Корреспондентский счёт | | `rqSwift` | string | нет | Код SWIFT | | `rqIban` | string | нет | Номер IBAN | | `rqBankName` | string | нет | Наименование банка | | `rqBankAddr` | string | нет | Адрес банка | | `rqAccName` | string | нет | Наименование владельца счёта | | `rqAccCurrency` | string | нет | Валюта счёта | | `active` | boolean | нет | Активен ли реквизит | | `sort` | number | нет | Порядок сортировки | | `comments` | string | нет | Комментарий | Поля `id`, `entityId`, `countryId`, `createdAt`, `updatedAt`, `createdBy`, `modifyBy` заполняются системой и игнорируются при записи. ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/bank-details/19" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "rqAccName": "ООО Ромашка", "rqCorAccNum": "30101810400000000225" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/bank-details/19" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "rqAccName": "ООО Ромашка", "rqCorAccNum": "30101810400000000225" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bank-details/19', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ rqAccName: 'ООО Ромашка', rqCorAccNum: '30101810400000000225', }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bank-details/19', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ rqAccName: 'ООО Ромашка', rqCorAccNum: '30101810400000000225', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Обновлённый банковский реквизит с актуальными значениями полей | | `data.id` | number | Идентификатор записи | | `data.entityId` | number | ID реквизита-владельца | | `data.updatedAt` | datetime | Новая дата изменения (ISO 8601) | | `data.modifyBy` | number | ID пользователя, выполнившего обновление | Объект содержит все поля в camelCase, включая неизменённые. Незаполненные поля — `null`. Полный список — [Поля банковского реквизита](/docs/entities/bank-details/fields). ## Пример ответа ```json { "success": true, "data": { "id": 19, "entityId": 1, "countryId": 0, "createdAt": "2026-06-10T10:14:29.000Z", "updatedAt": "2026-06-10T10:14:31.000Z", "createdBy": 1, "modifyBy": 1, "name": "Расчётный счёт", "code": null, "xmlId": null, "originatorId": null, "active": true, "sort": 500, "rqBankName": null, "rqBankAddr": null, "rqBik": "044525225", "rqAccName": "ООО Ромашка", "rqAccNum": "40702810500000000001", "rqAccCurrency": null, "rqCorAccNum": null, "rqIban": null, "rqSwift": "SABRRUMM", "comments": null } } ``` ## Пример ответа при ошибке 404 — банковский реквизит не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "The RequisiteBankDetail with ID '999999' is not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Банковский реквизит с таким ID не найден | | 403 | `SCOPE_DENIED` | Ключ не имеет скоупа `crm`. Сообщение: `This endpoint requires 'crm' scope` | | 401 | `TOKEN_MISSING` | Не передан `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Пустое значение очищает поле.** Чтобы очистить поле, передайте пустую строку `""`. В ответе очищенные строки приходят как `null`. ## Смотрите также - [Получить банковский реквизит](/docs/entities/bank-details/get) - [Создать банковский реквизит](/docs/entities/bank-details/create) - [Удалить банковский реквизит](/docs/entities/bank-details/delete) - [Поля банковского реквизита](/docs/entities/bank-details/fields) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Basket Items: Aggregate ## Агрегация позиций корзины `POST /v1/basket-items/aggregate` Подсчёт количества позиций и числовые агрегации (`sum`, `avg`, `min`, `max`) по полям `price` и `quantity`. Поддерживает фильтрацию и группировку по `orderId`, `productId`, `currency`. ## Стандартные поля | Поле | Назначение | |------|------------| | `price` | Числовое — подходит для `sum` / `avg` / `min` / `max` (агрегации по цене за единицу) | | `quantity` | Числовое — подходит для `sum` / `avg` / `min` / `max` (агрегации по количеству) | | `currency` | Категориальное — используется в `groupBy` (по валюте) | | `orderId`, `productId` | Идентификаторы — используются в `groupBy` (по заказу или товару) | Полный список агрегируемых полей перечислен в таблице выше. ## Поля запроса (тело) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций: `[{ "field": "quantity", "function": "sum" }]`. Функции: `count`, `sum`, `avg`, `min`, `max`. Для `count` поле — `"*"`. Без параметра — только `count` | | `filter` | object | нет | Фильтрация — те же поля, что в [`GET /v1/basket-items`](./list.md). [Синтаксис фильтрации](/docs/filtering) | | `groupBy` | string \| string[] | нет | Поле или массив полей для группировки (максимум 5) | | `groupOrderBy` | array | нет | Сортировка групп: `[{ "field": "quantity:sum", "direction": "desc" }]` | | `groupLimit` | number | нет | Ограничение количества возвращаемых групп (1-1000) | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/basket-items/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "quantity", "function": "sum" }, { "field": "price", "function": "avg" } ], "groupBy": "productId", "groupLimit": 5 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/basket-items/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "quantity", "function": "sum" }, { "field": "price", "function": "avg" } ], "groupBy": "productId", "groupLimit": 5 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/basket-items/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [ { field: 'quantity', function: 'sum' }, { field: 'price', function: 'avg' }, ], groupBy: 'productId', groupLimit: 5, }), }) const { success, data } = await res.json() console.log('Топ-5 товаров по продажам:', data.groups) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/basket-items/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [{ field: 'quantity', function: 'sum' }], groupBy: 'productId', }), }) const { success, data } = await res.json() ``` ## Другие сценарии Подсчёт записей — `count` с полем `"*"`, самый быстрый запрос без выгрузки записей. Без массива `aggregate` результат тот же: ```json { "aggregate": [{ "field": "*", "function": "count" }] } ``` Общая стоимость всех позиций в заказе: ```json { "aggregate": [{ "field": "price", "function": "sum" }], "filter": { "orderId": 33 } } ``` Топ-3 товаров по сумме продаж: ```json { "aggregate": [{ "field": "quantity", "function": "sum" }], "groupBy": "productId", "groupOrderBy": [{ "field": "quantity:sum", "direction": "desc" }], "groupLimit": 3 } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Общее количество позиций, соответствующих фильтру | | `data.aggregates` | object | Результаты агрегаций: `{ "quantity": { "sum": ... }, "price": { "avg": ... } }` | | `data.groups` | array | Группы (только при `groupBy`) | | `data.meta.totalRecords` | number | Общее количество записей | | `data.meta.recordsProcessed` | number | Количество обработанных записей (до 5000) | | `data.meta.truncated` | boolean | `true`, если записей больше 5000 | | `data.meta.groupTotal` | number | Количество групп до `groupLimit` | | `data.meta.groupsTruncated` | boolean | Был ли список групп обрезан `groupLimit` | ## Пример ответа ```json { "success": true, "data": { "count": 261, "aggregates": { "quantity": { "sum": 412 } }, "groups": [ { "productId": 119, "count": 23, "aggregates": { "quantity": { "sum": 47 } } }, { "productId": 245, "count": 18, "aggregates": { "quantity": { "sum": 36 } } }, { "productId": 87, "count": 14, "aggregates": { "quantity": { "sum": 21 } } } ], "meta": { "totalRecords": 261, "recordsProcessed": 261, "truncated": false, "groupTotal": 89, "groupsTruncated": true } } } ``` Без `groupBy` поле `data.groups` в ответе отсутствует. ## Пример ответа при ошибке 400 — поле в `groupBy` не поддерживает агрегацию: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "groupBy field 'foo' is not aggregatable on this entity. Available: price, quantity, currency, orderId, productId." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Неизвестная функция агрегации | | 400 | `INVALID_PARAMS` | Несуществующее числовое поле в `aggregate[].field` — сообщение `Field 'foo' not found. Available numeric fields: …` | | 400 | `INVALID_PARAMS` | Поле в `groupBy` не поддерживает агрегацию — сообщение содержит список допустимых полей | | 400 | `INVALID_PARAMS` | Передано больше 5 полей в `groupBy` | | 400 | `INVALID_PARAMS` | Зарезервированные ключевые слова в `groupBy`: `count`, `aggregates`, `meta`, `groups` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`count` против числовых функций.** `count` считается одним запросом в Битрикс24 — записи не выгружаются, ответ возвращается быстро на любом объёме. `sum` / `avg` / `min` / `max` подгружают записи постранично (максимум 5000) и считают на стороне Вайбкод. При более чем 5000 записях `meta.truncated` будет `true`. **Учёт незавершённых корзин.** В выборку попадают и позиции с `orderId: null` (товары в незавершённых корзинах). Чтобы исключить их, добавьте `filter[orderId][!]=null`. ## Смотрите также - [Список позиций](./list.md) - [Поиск позиций](./search.md) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Basket Items: Create ## Добавить позицию в корзину `POST /v1/basket-items` Добавляет товарную позицию в существующий заказ. Позиция ссылается на товар каталога через `productId` либо создаётся виртуальной при `productId: 0`. Тело запроса плоское — без обёртки `fields`. ## Поля запроса (тело) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `orderId` | number | да | Идентификатор заказа. Источник: [`GET /v1/orders`](../orders/list.md) | | `productId` | number | да | Идентификатор товара в каталоге. Источник: [`GET /v1/catalog-products`](/docs/entities/catalog-products). Значение `0` создаёт виртуальную позицию без привязки к каталогу | | `currency` | string | да | Валюта позиции. Список: [`GET /v1/currencies`](/docs/entities/currencies) | | `quantity` | number | да | Количество | | `name` | string | нет | Название позиции. При `productId > 0` подставляется из карточки товара — переданное значение на создании не сохраняется. При `productId: 0` сохраняется как передано | | `price` | number | нет | Цена за единицу. Для виртуальной позиции задаётся вручную. Передача `price` включает `customPrice` | | `basePrice` | number | нет | Базовая цена до скидки. По умолчанию равна `price` | | `discountPrice` | number | нет | Размер скидки за единицу. По умолчанию `0` | | `customPrice` | boolean | нет | Защита цены от автопересчёта при изменении товара в каталоге. При передаче `price` выставляется в `true`. По умолчанию `false` | | `vatRate` | number | нет | Ставка НДС в долях единицы. `0.20` = 20%, `0.10` = 10%, `0` — без НДС | | `vatIncluded` | boolean | нет | Включён ли НДС в цену. По умолчанию `true` | | `weight` | number | нет | Вес единицы в граммах | | `measureCode` | number | нет | Код единицы измерения. `796` — шт, `163` — г, `006` — м | | `productXmlId` | string | нет | Внешний идентификатор товара. Для виртуальной позиции задаётся вручную | | `catalogXmlId` | string | нет | Внешний идентификатор каталога. Для виртуальной позиции задаётся вручную | | `xmlId` | string | нет | Внешний идентификатор позиции | ## Примеры Примеры ниже создают виртуальную позицию `productId: 0` — для неё `name` сохраняется как передано. ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/basket-items" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "orderId": 1, "productId": 0, "currency": "RUB", "quantity": 1, "name": "Подарочная упаковка" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/basket-items" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "orderId": 1, "productId": 0, "currency": "RUB", "quantity": 1, "name": "Подарочная упаковка" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/basket-items', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ orderId: 1, productId: 0, currency: 'RUB', quantity: 1, name: 'Подарочная упаковка', }), }) const { success, data } = await res.json() console.log('Basket item ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/basket-items', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ orderId: 1, productId: 0, currency: 'RUB', quantity: 1, name: 'Подарочная упаковка', }), }) const { success, data } = await res.json() ``` Каталожная позиция создаётся передачей `productId` товара — `name`, `price` и единица измерения заполнятся из его карточки: ```json { "orderId": 1, "productId": 119, "currency": "RUB", "quantity": 2 } ``` ## Поля ответа Возвращается полный объект созданной позиции. | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор созданной позиции | | `name` | string | Название. Для каталожного товара — из карточки, для виртуальной позиции — как передано | | `price` | number | Цена за единицу | | `customPrice` | boolean | `true`, если цена задана вручную через `price` | | `productXmlId` | string \| null | Внешний идентификатор товара. `null` у виртуальной позиции без переданного значения | | `catalogXmlId` | string \| null | Внешний идентификатор каталога. `null` у виртуальной позиции без переданного значения | | `dateInsert` | datetime | Дата создания | Полный набор полей — [`GET /v1/basket-items/fields`](./fields.md). ## Пример ответа ```json { "success": true, "data": { "id": 1021, "orderId": 1, "productId": 0, "name": "Подарочная упаковка", "price": 0, "basePrice": 0, "discountPrice": 0, "customPrice": false, "currency": "RUB", "quantity": 1, "sort": 100, "weight": null, "dimensions": null, "measureCode": null, "measureName": null, "canBuy": true, "vatRate": null, "vatIncluded": true, "xmlId": "bx_6a3e475a2d55c", "productXmlId": null, "catalogXmlId": null, "dateInsert": "2026-06-26T08:33:14.000Z", "dateUpdate": "2026-06-26T08:33:14.000Z" } } ``` ## Пример ответа при ошибке 422 — не переданы обязательные поля: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Required fields: orderId, productId, currency, quantity" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Не переданы обязательные поля — сообщение содержит их список | | 422 | `BITRIX_ERROR` | Несуществующий `orderId` или `productId` — позиция не сохранена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Имя каталожного товара берётся из карточки.** При `productId > 0` поля `name`, `productXmlId`, `catalogXmlId`, `measureCode`, `measureName` заполняются из карточки товара. Переданное в запросе `name` на создании не сохраняется. Чтобы задать каталожной позиции произвольное имя, обновите её после создания через [`PATCH /v1/basket-items/:id`](./update.md). **Виртуальная позиция.** При `productId: 0` позиция не привязана к каталогу. Поля `name`, `price`, `productXmlId`, `catalogXmlId` задаются вручную в запросе и сохраняются как переданы. **Ручная цена включает `customPrice`.** Если передать `price`, в ответе `customPrice` становится `true` — цена позиции не пересчитывается при изменении цены товара в каталоге. Без `price` остаётся `false`. **Несколько позиций для одного товара.** Можно добавить одну и ту же `productId` в заказ несколькими позициями — Битрикс24 не объединяет их. Чтобы увеличить количество существующей позиции, используйте [`PATCH /v1/basket-items/:id`](./update.md) с `quantity`. ## Смотрите также - [Список позиций](./list.md) - [Получить позицию](./get.md) - [Обновить позицию](./update.md) - [Поля позиции](./fields.md) - [Заказ](../orders/get.md) - [Товары каталога](/docs/entities/catalog-products) - [Batch](/docs/batch) --- # Basket Items: Delete ## Удалить позицию корзины `DELETE /v1/basket-items/:id` Удаляет позицию корзины по идентификатору. Восстановить удалённую позицию через API нельзя — создавайте новую при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор позиции | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/basket-items/9" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/basket-items/9" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/basket-items/9', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Позиция удалена') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/basket-items/9', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Позиция удалена') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — успех проверяется по статусу. ## Пример ответа ```http HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 422 — позиция не найдена: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "basket item is not exists" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Позиция с таким ID не найдена или уже удалена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Заказ остаётся без изменений.** Удаление позиции не затрагивает родительский заказ — только пропадает одна строка корзины. Сумма заказа (`orders.price`) при этом не пересчитывается автоматически. ## Смотрите также - [Список позиций](./list.md) - [Получить позицию](./get.md) - [Обновить позицию](./update.md) - [Обновить заказ](../orders/update.md) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Basket Items: Fields ## Поля позиции корзины `GET /v1/basket-items/fields` Возвращает схему полей позиции корзины: типы, флаги только-для-чтения, список агрегируемых полей. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/basket-items/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/basket-items/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/basket-items/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { data } = await res.json() console.log('Поля позиции:', Object.keys(data.fields)) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/basket-items/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор позиции (только чтение) | | `orderId` | number \| null | Идентификатор заказа. Источник: [`GET /v1/orders`](../orders/list.md). У свободных позиций без заказа — `null` | | `productId` | number | Идентификатор товара в каталоге. Источник: [`GET /v1/catalog-products`](/docs/entities/catalog-products). `0` — виртуальная позиция без привязки к каталогу | | `name` | string | Название позиции | | `price` | number | Цена за единицу с учётом скидки | | `basePrice` | number | Базовая цена до скидки | | `discountPrice` | number | Размер скидки за единицу | | `customPrice` | boolean | Цена задана вручную и не пересчитывается при изменении товара в каталоге | | `currency` | string | Валюта позиции. Список: [`GET /v1/currencies`](/docs/entities/currencies) | | `quantity` | number | Количество | | `sort` | number | Порядок позиции в корзине. По умолчанию `100` | | `weight` | number \| null | Вес единицы в граммах. У позиций без веса — `null` | | `dimensions` | string \| null | Габариты в формате сериализации PHP. У позиций без габаритов — `null` | | `measureCode` | number \| null | Код единицы измерения. `796` — шт, `163` — г, `006` — м. Может быть `null` | | `measureName` | string \| null | Название единицы измерения. Может быть `null` | | `canBuy` | boolean | Доступна ли позиция к покупке | | `vatRate` | number \| null | Ставка НДС в долях единицы. `0.20` = 20%. У позиций без НДС — `null` | | `vatIncluded` | boolean | Включён ли НДС в цену | | `xmlId` | string | Внешний идентификатор позиции | | `productXmlId` | string \| null | Внешний идентификатор товара. Может быть `null` | | `catalogXmlId` | string \| null | Внешний идентификатор каталога. Может быть `null` | | `dateInsert` | datetime | Дата создания (только чтение) | | `dateUpdate` | datetime | Дата последнего изменения (только чтение) | | `barcodeMulti` | boolean | Позиция учитывается по нескольким штрихкодам | | `type` | string \| null | Тип позиции (только чтение). На живых порталах всегда `null` | | `properties` | array | Свойства позиции, только чтение. Каждый элемент: `{basketId, code, id, name, sort, value, xmlId}`. Возвращается только `GET /v1/basket-items/:id`, в списке — нет | | `reservations` | array | Резервы позиции на складах, только чтение. Возвращается только `GET /v1/basket-items/:id`, в списке — нет | ## Пример ответа Каждое поле, помимо `type` и `readonly`, содержит `label` (короткое название) и `description` (пояснение) на русском языке. В примере ниже они опущены для краткости. ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true }, "orderId": { "type": "number", "readonly": false }, "productId": { "type": "number", "readonly": false }, "name": { "type": "string", "readonly": false }, "price": { "type": "number", "readonly": false }, "basePrice": { "type": "number", "readonly": false }, "discountPrice": { "type": "number", "readonly": false }, "customPrice": { "type": "boolean", "readonly": false }, "currency": { "type": "string", "readonly": false }, "quantity": { "type": "number", "readonly": false }, "sort": { "type": "number", "readonly": false }, "weight": { "type": "number", "readonly": false, "nullable": true }, "dimensions": { "type": "string", "readonly": false, "nullable": true }, "measureCode": { "type": "number", "readonly": false, "nullable": true }, "measureName": { "type": "string", "readonly": false, "nullable": true }, "canBuy": { "type": "boolean", "readonly": false }, "vatRate": { "type": "number", "readonly": false, "nullable": true }, "vatIncluded": { "type": "boolean", "readonly": false }, "xmlId": { "type": "string", "readonly": false }, "productXmlId": { "type": "string", "readonly": false, "nullable": true }, "catalogXmlId": { "type": "string", "readonly": false, "nullable": true }, "dateInsert": { "type": "datetime", "readonly": true }, "dateUpdate": { "type": "datetime", "readonly": true }, "barcodeMulti": { "type": "boolean", "readonly": false }, "type": { "type": "string", "readonly": true }, "properties": { "type": "array", "readonly": true }, "reservations": { "type": "array", "readonly": true } }, "aggregatable": ["price", "quantity", "currency", "orderId", "productId"], "batch": ["create", "update", "delete"] } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'sale' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список позиций](./list.md) - [Добавить позицию](./create.md) - [Агрегация позиций](./aggregate.md) - [Entity API](/docs/entity-api) --- # Basket Items: Get ## Получить позицию корзины `GET /v1/basket-items/:id` Возвращает одну позицию корзины по идентификатору со всеми полями. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор позиции | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/basket-items/9" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/basket-items/9" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/basket-items/9', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Позиция:', data.name, '×', data.quantity, '=', data.price * data.quantity, data.currency) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/basket-items/9', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор позиции | | `orderId` | number \| null | Идентификатор заказа. `null` у свободных позиций без заказа | | `productId` | number | Идентификатор товара в каталоге | | `name` | string | Название товара | | `price` | number | Цена за единицу | | `basePrice` | number | Базовая цена до скидки | | `discountPrice` | number | Размер скидки за единицу | | `currency` | string | Валюта | | `quantity` | number | Количество | | `sort` | number | Порядок позиции в корзине | | `weight` | number \| null | Вес в граммах. `null` у виртуальных позиций с `productId: 0` | | `vatRate` | number \| null | Ставка НДС в долях единицы. `null` у виртуальных позиций с `productId: 0` | | `vatIncluded` | boolean | Включён ли НДС в цену | | `customPrice` | boolean | Защита цены от автопересчёта при изменении товара в каталоге | | `canBuy` | boolean | Доступен ли товар к покупке | | `barcodeMulti` | boolean | Позиция учитывается по нескольким штрихкодам | | `measureCode` | number \| null | Код единицы измерения. `null` у виртуальных позиций с `productId: 0` | | `measureName` | string \| null | Название единицы измерения. `null` у виртуальных позиций с `productId: 0` | | `dimensions` | string \| null | Габариты в формате сериализации PHP. `null` у виртуальных позиций с `productId: 0` | | `xmlId` | string | Внешний идентификатор позиции | | `productXmlId` | string \| null | Внешний идентификатор товара в каталоге. `null` у виртуальных позиций с `productId: 0` | | `catalogXmlId` | string \| null | Внешний идентификатор каталога. `null` у виртуальных позиций с `productId: 0` | | `type` | string \| null | Тип позиции. На живых порталах всегда `null` | | `properties` | array | Свойства позиции. Каждый элемент: `{basketId, code, id, name, sort, value, xmlId}` | | `reservations` | array | Резервы позиции на складах | | `dateInsert` | datetime | Дата создания | | `dateUpdate` | datetime | Дата последнего изменения | Полный список полей — [`GET /v1/basket-items/fields`](./fields.md). ## Пример ответа ```json { "success": true, "data": { "id": 9, "orderId": 33, "productId": 119, "name": "Домашние Тапочки Любимый Спорт", "price": 470, "basePrice": 470, "discountPrice": 0, "currency": "RUB", "quantity": 1, "weight": 0, "vatRate": 0, "vatIncluded": true, "customPrice": false, "canBuy": true, "barcodeMulti": false, "measureCode": 796, "measureName": "шт", "dimensions": "a:3:{s:5:\"WIDTH\";N;s:6:\"HEIGHT\";N;s:6:\"LENGTH\";N;}", "xmlId": "bx_5fc9f8c57fe6c", "productXmlId": "1000000475", "catalogXmlId": "FUTURE-1C-CATALOG", "type": null, "sort": 200, "properties": [ { "id": 17, "basketId": 9, "code": "CATALOG.XML_ID", "name": "Catalog XML_ID", "value": "FUTURE-1C-CATALOG", "sort": 100, "xmlId": "bx_5fc9f8c57ff3e" }, { "id": 19, "basketId": 9, "code": "PRODUCT.XML_ID", "name": "Product XML_ID", "value": "1000000475", "sort": 100, "xmlId": "bx_5fc9f8c57ffb2" } ], "reservations": [], "dateInsert": "2020-12-04T07:52:21.000Z", "dateUpdate": "2022-11-02T05:10:13.000Z" } } ``` ## Пример ответа при ошибке 422 — позиция не найдена: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "basket item is not exists" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Позиция с таким ID не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Обновить позицию](./update.md) - [Удалить позицию](./delete.md) - [Список позиций](./list.md) - [Поля позиции](./fields.md) - [Заказ](../orders/get.md) - [Лимиты и оптимизация](/docs/optimization) --- # Basket Items: List ## Список позиций корзины `GET /v1/basket-items` Возвращает список позиций корзины с поддержкой фильтрации и автоматической пагинации. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` Вайбкод автоматически запрашивает несколько страниц у Битрикс24 | | `offset` | number | `0` | Пропустить N записей. При `offset ≥ 2500` рекомендуется `limit ≤ 500` | | `select` | string | — | Выборка полей: `?select=id,orderId,name,quantity,price` | | `order` | object | — | Сортировка: `?order[id]=desc` | | `filter` | object | — | Фильтрация по ключевым полям позиции.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[orderId]=33` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/basket-items?limit=10&filter[orderId]=33" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/basket-items?limit=10&filter[orderId]=33" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/basket-items?limit=10&filter[orderId]=33', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Позиций в заказе: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/basket-items?limit=10&filter[orderId]=33', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив позиций корзины | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | ## Пример ответа ```json { "success": true, "data": [ { "id": 9, "orderId": 33, "productId": 119, "name": "Домашние Тапочки Любимый Спорт", "price": 470, "basePrice": 470, "discountPrice": 0, "currency": "RUB", "quantity": 1, "weight": 0, "vatRate": 0, "vatIncluded": true, "measureCode": 796, "measureName": "шт", "xmlId": "bx_5fc9f8c57fe6c", "productXmlId": "1000000475", "catalogXmlId": "FUTURE-1C-CATALOG", "canBuy": true, "dateInsert": "2020-12-04T07:52:21.000Z", "dateUpdate": "2022-11-02T05:10:13.000Z" } ], "meta": { "total": 1, "hasMore": false } } ``` Показаны основные поля. Полный ответ позиции — см. [`GET /v1/basket-items/:id`](./get.md). ## Пример ответа при ошибке 400 — фильтр по несуществующему полю: ```json { "success": false, "error": { "code": "UNKNOWN_FILTER_FIELD", "message": "Unknown filter field 'foo' for entity 'basket-items'. Available: …" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет в схеме | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Автоматическая пагинация:** при `limit > 50` Вайбкод автоматически запрашивает несколько страниц у Битрикс24 и возвращает все записи в одном ответе. **Свободные позиции без заказа.** Часть позиций в `data[]` может иметь `orderId: null` — это позиции в незавершённых корзинах покупателей, ещё не оформленных в заказ. Чтобы исключить их, добавьте `filter[orderId][!]=null` или фильтр по конкретному `orderId`. ## Смотрите также - [Поиск позиций](./search.md) - [Получить позицию](./get.md) - [Добавить позицию](./create.md) - [Заказ](../orders/get.md) - [Товары каталога](/docs/entities/catalog-products) - [Синтаксис фильтрации](/docs/filtering) - [Entity API](/docs/entity-api) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Basket Items: Search ## Поиск позиций корзины `POST /v1/basket-items/search` Поиск позиций корзины с фильтрацией и автоматической пагинацией. Аналогичен [`GET /v1/basket-items`](./list.md), но параметры передаются в теле POST-запроса — подходит для сложных запросов с большим количеством условий. ## Поля запроса (тело) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям позиции.
[Синтаксис фильтрации](/docs/filtering) | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки» | | `select` | string[] | — | Выборка полей: `["id", "orderId", "name", "quantity", "price"]` | | `order` | object | — | Сортировка: `{ "id": "desc" }` | | `autoWindow` | boolean | `true` | Разбивать выборку по недельным окнам при фильтре по диапазону дат шире 14 дней. `false` отключает разбиение | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/basket-items/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "orderId": 33 }, "limit": 10, "select": ["id", "orderId", "name", "quantity", "price", "currency"] }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/basket-items/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "orderId": 33 }, "limit": 10, "select": ["id", "orderId", "name", "quantity", "price", "currency"] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/basket-items/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { orderId: 33 }, limit: 10, select: ['id', 'orderId', 'name', 'quantity', 'price', 'currency'], }), }) const { success, data, meta } = await res.json() console.log('Найдено:', meta.total) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/basket-items/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { orderId: 33 }, limit: 10, select: ['id', 'orderId', 'name', 'quantity', 'price', 'currency'], }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив позиций корзины | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временны́м окнам | | `meta.windowCount` | number | Число окон. Приходит при `autoWindowed: true` | | `meta.batchWaves` | number | Число волн параллельных запросов. Приходит при `autoWindowed: true` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа ```json { "success": true, "data": [ { "id": 9, "orderId": 33, "name": "Домашние Тапочки Любимый Спорт", "quantity": 1, "price": 470, "currency": "RUB" } ], "meta": { "total": 1, "hasMore": false } } ``` С фильтром по диапазону дат шире 14 дней в `meta` дополнительно приходят `autoWindowed`, `windowCount` и `batchWaves`: ```json { "success": true, "data": [ /* ... */ ], "meta": { "total": 55, "hasMore": true, "autoWindowed": true, "windowCount": 131, "batchWaves": 3, "durationMs": 3454 } } ``` ## Пример ответа при ошибке 400 — фильтр по несуществующему полю: ```json { "success": false, "error": { "code": "UNKNOWN_FILTER_FIELD", "message": "Unknown filter field 'foo' for entity 'basket-items'. Available: …" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет в схеме | | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Разбиение по временны́м окнам.** Фильтр по диапазону дат шире 14 дней автоматически разбивается на недельные окна, которые выполняются параллельными волнами — так выборка обходит потолок в 5000 записей на один вызов. В `meta` тогда приходят `autoWindowed: true`, число окон `windowCount` и число волн `batchWaves`. Отключает разбиение параметр `autoWindow: false`. При активном разбиении `offset` больше нуля отклоняется с `UNSTABLE_OFFSET_PAGINATION`. **`select` ограничивает поля в ответе.** Если передан `select`, в каждом элементе `data[]` будут только перечисленные поля. Без `select` возвращаются все поля позиции. **Поиск товара по всем заказам.** Фильтр `{"productId": 119}` без `orderId` найдёт все позиции с этим товаром по всему порталу — это даёт срез продаж конкретного товара. ## Смотрите также - [Список позиций](./list.md) - [Получить позицию](./get.md) - [Заказ](../orders/get.md) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Basket Items: Update ## Обновить позицию корзины `PATCH /v1/basket-items/:id` Обновляет поля существующей позиции корзины. Передавайте только изменяемые поля плоско в корне JSON — без обёртки `fields`. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор позиции | ## Поля для обновления (тело) | Параметр | Тип | Описание | |----------|-----|---------| | `quantity` | number | Количество | | `price` | number | Цена за единицу | | `basePrice` | number | Базовая цена до скидки | | `discountPrice` | number | Размер скидки за единицу | | `currency` | string | Валюта | | `name` | string | Переопределение названия товара | | `vatRate` | number | Ставка НДС в долях единицы | | `vatIncluded` | boolean | Включён ли НДС в цену | | `customPrice` | boolean | Защита цены от автопересчёта | | `weight` | number | Вес в граммах | | `measureCode` | number | Код единицы измерения | | `xmlId` | string | Внешний идентификатор | Редактируются все поля позиции, кроме служебных (`id`, `orderId`, `productId`, `productXmlId`, `catalogXmlId`, `dateInsert`, `dateUpdate`). Полный набор доступных полей виден в ответе [`GET /v1/basket-items/:id`](./get.md). > **Частичное обновление.** Передавать `quantity` в каждом запросе не нужно. При отсутствии `quantity` в теле обёртка дочитывает текущее количество позиции и подставляет его — можно изменить только цену или другое поле. Если при таком частичном обновлении позиция не найдена, вернётся `404 ENTITY_NOT_FOUND`. ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/basket-items/9" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "quantity": 3, "discountPrice": 50 }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/basket-items/9" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "quantity": 3, "discountPrice": 50 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/basket-items/9', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ quantity: 3, discountPrice: 50, }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/basket-items/9', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ quantity: 3, discountPrice: 50, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | object | Обновлённый объект позиции со всеми полями | ## Пример ответа ```json { "success": true, "data": { "id": 9, "orderId": 33, "productId": 119, "name": "Домашние Тапочки Любимый Спорт", "price": 470, "basePrice": 470, "discountPrice": 50, "currency": "RUB", "quantity": 3, "vatRate": 0, "vatIncluded": true, "customPrice": false, "canBuy": true, "weight": 0, "measureCode": 796, "measureName": "шт", "dateUpdate": "2026-05-13T11:58:14.000Z" } } ``` ## Пример ответа при ошибке 422 — позиция не найдена: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "basket item is not exists" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Позиция не найдена (частичный PATCH без `quantity` — определяется на предзагрузке) | | 422 | `BITRIX_ERROR` | Позиция с таким ID не найдена (PATCH с явным `quantity`) | | 400 | `BITRIX_ERROR` | Некорректное значение поля | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Поля `id`, `orderId`, `productId`, `productXmlId`, `catalogXmlId`, `dateInsert` доступны только для чтения.** Они проставляются при создании, попытка изменить их игнорируется. Чтобы перенести позицию в другой заказ, удалите её через [`DELETE /v1/basket-items/:id`](./delete.md) и создайте новую через [`POST /v1/basket-items`](./create.md). **Защита цены через `customPrice`.** При `customPrice: true` цена позиции не будет пересчитана автоматически при изменении цены товара в каталоге. ## Смотрите также - [Получить позицию](./get.md) - [Список позиций](./list.md) - [Удалить позицию](./delete.md) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Bizproc Activities: Create ## Зарегистрировать действие `POST /v1/bizproc-activities` Регистрирует новое действие для дизайнера бизнес-процессов Битрикс24. Поля передаются плоско в корне JSON — без обёртки `fields`. Вызывается только ключом авторизации вместе с заголовком `Authorization: Bearer`. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `code` | string | да | Уникальный код действия. Разрешены символы `a-z`, `A-Z`, `0-9`, `.`, `-`, `_`. Служит идентификатором в путях обновления и удаления | | `name` | string \| object | да | Название действия. Строка или локализованный объект вида `{"ru": "...", "en": "..."}` | | `handler` | string | да | URL обработчика действия. Домен совпадает с доменом приложения | | `description` | string \| object | нет | Описание действия. Строка или локализованный объект | | `authUserId` | number | нет | ID пользователя, чей токен передаётся приложению при вызове действия. Список: `GET /v1/users` | | `useSubscription` | string | нет | Ждать ли ответа от приложения перед продолжением процесса: `Y` или `N` | | `properties` | object | нет | Входные параметры действия — поля, которые заполняются в дизайнере | | `returnProperties` | object | нет | Выходные параметры действия — значения, которые действие возвращает в процесс | | `documentType` | array | нет | Тип документа, к которому применимо действие — модуль, объект, тип. Значения: [Типы документов](/docs/entities/bizproc-activities#типы-документов) | | `filter` | object | нет | Правила `INCLUDE` / `EXCLUDE` по типу документа | | `usePlacement` | string | нет | Открывать настройки действия в выдвижной панели: `Y` или `N` | | `placementHandler` | string | нет | URL выдвижной панели настроек. Обязателен при `usePlacement: "Y"` | ## Примеры Токен сессии выдаёт OAuth-авторизация и живёт 24 часа без продления — [Передача ключа](/docs/keys-auth#передача-ключа). ### curl — ключ авторизации ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/bizproc-activities" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "code": "notify_manager", "name": { "ru": "Уведомить руководителя", "en": "Notify manager" }, "handler": "https://your-app.example.com/bizproc/notify" }' ``` ### JavaScript — ключ авторизации ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bizproc-activities', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ code: 'notify_manager', name: { ru: 'Уведомить руководителя', en: 'Notify manager' }, handler: 'https://your-app.example.com/bizproc/notify', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | boolean | `true` — Битрикс24 подтвердил регистрацию действия. Это признак успеха, а не числовой идентификатор. Идентификатор действия — заданный вами `code` | ## Пример ответа ```json { "success": true, "data": { "id": true } } ``` ## Пример ответа при ошибке 403 — вызов API-ключом: ```json { "success": false, "error": { "code": "OAUTH_REQUIRED", "message": "bizproc-activities require an OAuth app key (vibe_app_*) with an Authorization: Bearer session — a personal vibe_api_* key lacks the per-user OAuth context Bitrix24 needs for these methods. Create an OAuth app (POST /v1/apps) and retry with its key. On this 403 switch keys — do NOT delete or recreate the app (that discards anything already registered under it, e.g. a bizproc robot you just registered)." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 403 | `OAUTH_REQUIRED` | Запрос отправлен API-ключом. Регистрировать действия можно только ключом авторизации | | 401 | `TOKEN_MISSING` | Передан ключ авторизации без заголовка `Authorization: Bearer` | | 401 | `WRONG_AUTH_SCHEME` | Ключ авторизации отправлен в заголовке `Authorization: Bearer`. Сам ключ передаётся в `X-Api-Key`, а `Authorization: Bearer` несёт токен сессии | | 401 | `INVALID_SESSION` | Токен сессии истёк или недействителен — пройдите авторизацию заново | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `bizproc` | | 400 | `MISSING_REQUIRED_FIELDS` | Не передано обязательное поле — `code`, `name` или `handler` | | 400 | `SERVER_APP_MISMATCH` | `handler` ведёт на субдомен Black Hole, за которым нет сервера этого приложения — субдомена не существует либо сервер принадлежит другому приложению. Регистрируйте обработчик ключом того приложения, к которому привязан сервер | | 503 | `BIZPROC_CALLBACK_RESOLVE_FAILED` | Платформе не удалось сопоставить обработчик с сервером. Действие не зарегистрировано — повторите запрос | | 422 | `BITRIX_ERROR` | Битрикс24 отклонил регистрацию — причина в `error.message` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Обработчик на субдомене Black Hole получает надёжную доставку.** Платформа берёт доставку вызовов на себя, а в Битрикс24 сохраняет адрес своего приёмника вместо переданного вами. Такой обработчик регистрируется только одиночным запросом, а сама доставка включается по аккаунтам — [Доставка вызовов действий и роботов](/docs/infra/bizproc-callbacks). ## Смотрите также - [Обновить действие](/docs/entities/bizproc-activities/update) - [Удалить действие](/docs/entities/bizproc-activities/delete) - [Доставка вызовов действий и роботов](/docs/infra/bizproc-callbacks) - [Ключи и авторизация](/docs/keys-auth) --- # Bizproc Activities: Delete ## Удалить действие `DELETE /v1/bizproc-activities/:code` Удаляет действие бизнес-процесса по коду. Восстановить удалённое действие через API нельзя — при необходимости зарегистрируйте новое. Вызывается только ключом авторизации вместе с заголовком `Authorization: Bearer`. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `code` (path) | string | да | Символьный код действия | ## Примеры Токен сессии выдаёт OAuth-авторизация и живёт 24 часа без продления — [Передача ключа](/docs/keys-auth#передача-ключа). ### curl — ключ авторизации ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/bizproc-activities/notify_manager" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — ключ авторизации ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bizproc-activities/notify_manager', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Действие удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — успех проверяется по статусу. ## Пример ответа ```http HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 422 — действие с указанным кодом не найдено: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Activity or Robot not found!" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 403 | `OAUTH_REQUIRED` | Запрос отправлен API-ключом. Удалять действия можно только ключом авторизации | | 401 | `TOKEN_MISSING` | Передан ключ авторизации без заголовка `Authorization: Bearer` | | 401 | `WRONG_AUTH_SCHEME` | Ключ авторизации отправлен в заголовке `Authorization: Bearer`. Сам ключ передаётся в `X-Api-Key`, а `Authorization: Bearer` несёт токен сессии | | 401 | `INVALID_SESSION` | Токен сессии истёк или недействителен — пройдите авторизацию заново | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `bizproc` | | 422 | `BITRIX_ERROR` | Битрикс24 не нашёл действие с указанным кодом или отклонил удаление — причина в `error.message` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Зарегистрировать действие](/docs/entities/bizproc-activities/create) - [Обновить действие](/docs/entities/bizproc-activities/update) - [Ключи и авторизация](/docs/keys-auth) --- # Bizproc Activities: Fields ## Поля действия `GET /v1/bizproc-activities/fields` Возвращает схему полей действия бизнес-процесса: тип каждого поля, доступность на запись, обязательность на регистрацию, подпись и описание. Отвечает описанием схемы, к зарегистрированным на портале действиям не обращается. ## Примеры Читать схему можно только ключом авторизации — оба примера отправляют ключ авторизации и заголовок `Authorization: Bearer`. Токен сессии выдаёт OAuth-авторизация и живёт 24 часа без продления — [Передача ключа](/docs/keys-auth#передача-ключа). ### curl — ключ авторизации ```bash curl -X GET "https://vibecode.bitrix24.tech/v1/bizproc-activities/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — ключ авторизации ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bizproc-activities/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() console.log(Object.keys(data.fields)) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.fields` | object | Схема полей: ключ — имя поля, значение — его описание | | `data.fields.<поле>.type` | string | Тип значения: `string`, `number`, `object`, `array` | | `data.fields.<поле>.readonly` | boolean | `true` — поле заполняется системой и в запросах на запись не передаётся | | `data.fields.<поле>.required` | boolean | Приходит только у обязательных на регистрацию полей | | `data.fields.<поле>.label` | string | Короткая подпись поля | | `data.fields.<поле>.description` | string | Развёрнутое описание поля | | `data.batch` | array | Операции сущности, доступные в [`POST /v1/batch`](/docs/batch) | Состав схемы: | Поле | Тип | RO | Обяз. | Описание | |------|-----|:--:|:-----:|---------| | `code` | string | | да | Уникальный код действия. Служит идентификатором в путях обновления и удаления | | `handler` | string | | да | URL обработчика действия | | `name` | string | | да | Название действия | | `description` | string | | нет | Описание действия | | `authUserId` | number | | нет | Пользователь, чей токен передаётся приложению при вызове. Список: `GET /v1/users` | | `useSubscription` | string | | нет | Ждать ли ответа приложения перед продолжением процесса: `Y` или `N` | | `properties` | object | | нет | Входные параметры действия | | `returnProperties` | object | | нет | Выходные параметры действия | | `documentType` | array | | нет | Тип документа, к которому применимо действие — массив из трёх элементов: модуль, объект, тип. Допустимые сочетания: [Зарегистрировать действие](./create.md) | | `filter` | object | | нет | Правила `INCLUDE` и `EXCLUDE` по типу документа | | `usePlacement` | string | | нет | Открывать настройки действия в выдвижной панели: `Y` или `N` | | `placementHandler` | string | | нет | URL выдвижной панели настроек | ## Пример ответа ```json { "success": true, "data": { "fields": { "code": { "type": "string", "readonly": false, "required": true, "label": "Код", "description": "Уникальный код действия. Служит идентификатором в путях обновления и удаления." }, "handler": { "type": "string", "readonly": false, "required": true, "label": "URL обработчика", "description": "URL обработчика действия." }, "name": { "type": "string", "readonly": false, "required": true, "label": "Название", "description": "Название действия." }, "description": { "type": "string", "readonly": false, "label": "Описание", "description": "Описание действия." }, "authUserId": { "type": "number", "readonly": false, "label": "ID пользователя-авторизатора", "description": "Пользователь, чей токен передаётся приложению при вызове. Список: GET /v1/users." }, "useSubscription": { "type": "string", "readonly": false, "label": "Ожидание ответа", "description": "Ждать ли ответа приложения перед продолжением процесса: Y или N." }, "properties": { "type": "object", "readonly": false, "label": "Входные параметры", "description": "Входные параметры действия." }, "returnProperties": { "type": "object", "readonly": false, "label": "Выходные параметры", "description": "Выходные параметры действия." }, "documentType": { "type": "array", "readonly": false, "label": "Тип документа", "description": "Тип документа, к которому применимо действие." }, "filter": { "type": "object", "readonly": false, "label": "Фильтр по типу документа", "description": "Правила INCLUDE и EXCLUDE по типу документа." }, "usePlacement": { "type": "string", "readonly": false, "label": "Настройки в панели", "description": "Открывать настройки действия в выдвижной панели: Y или N." }, "placementHandler": { "type": "string", "readonly": false, "label": "URL панели настроек", "description": "URL выдвижной панели настроек." } }, "batch": ["create", "update", "delete"] } } ``` ## Пример ответа при ошибке 403 — запрос отправлен API-ключом: ```json { "success": false, "error": { "code": "OAUTH_REQUIRED", "message": "bizproc-activities require an OAuth app key (vibe_app_*) with an Authorization: Bearer session — a personal vibe_api_* key lacks the per-user OAuth context Bitrix24 needs for these methods. Create an OAuth app (POST /v1/apps) and retry with its key. On this 403 switch keys — do NOT delete or recreate the app (that discards anything already registered under it, e.g. a bizproc robot you just registered)." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 403 | `OAUTH_REQUIRED` | Запрос отправлен API-ключом. Схема доступна только ключу авторизации | | 401 | `TOKEN_MISSING` | Ключ авторизации без заголовка `Authorization: Bearer` | | 401 | `WRONG_AUTH_SCHEME` | Ключ авторизации отправлен в заголовке `Authorization: Bearer`. Сам ключ передаётся в `X-Api-Key`, а `Authorization: Bearer` несёт токен сессии | | 401 | `INVALID_SESSION` | Токен сессии истёк или недействителен — пройдите авторизацию заново | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `bizproc` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Схема одинакова у действий и роботов.** Обе сущности описываются одним набором из двенадцати полей — различается смысл, а не состав. ## Смотрите также - [Список действий](/docs/entities/bizproc-activities/list) - [Зарегистрировать действие](/docs/entities/bizproc-activities/create) - [Обновить действие](/docs/entities/bizproc-activities/update) - [Удалить действие](/docs/entities/bizproc-activities/delete) - [Ключи и авторизация](/docs/keys-auth) --- # Bizproc Activities: List ## Список действий `GET /v1/bizproc-activities` Возвращает список кодов действий бизнес-процессов, зарегистрированных на портале. Каждый элемент ответа — символьный код действия, который используется в путях обновления и удаления. Метод работает только с ключом авторизации. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Максимальное количество кодов в ответе | ## Примеры Токен сессии выдаёт OAuth-авторизация и живёт 24 часа без продления — [Передача ключа](/docs/keys-auth#передача-ключа). ### curl — ключ авторизации ```bash curl "https://vibecode.bitrix24.tech/v1/bizproc-activities" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — ключ авторизации ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bizproc-activities', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() console.log(`Зарегистрировано действий: ${meta.total}`) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив строк — коды зарегистрированных действий | | `meta.total` | number | Количество кодов в ответе | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | ## Пример ответа ```json { "success": true, "data": [ "notify_manager", "sync_status" ], "meta": { "total": 2, "hasMore": false } } ``` ## Пример ответа при ошибке 403 — вызов API-ключом на методе только для ключа авторизации: ```json { "success": false, "error": { "code": "OAUTH_REQUIRED", "message": "bizproc-activities require an OAuth app key (vibe_app_*) with an Authorization: Bearer session — a personal vibe_api_* key lacks the per-user OAuth context Bitrix24 needs for these methods. Create an OAuth app (POST /v1/apps) and retry with its key. On this 403 switch keys — do NOT delete or recreate the app (that discards anything already registered under it, e.g. a bizproc robot you just registered)." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `OAUTH_REQUIRED` | Вызов API-ключом. Метод доступен только ключу авторизации | | 401 | `TOKEN_MISSING` | Ключ авторизации передан без заголовка `Authorization: Bearer <сессия>` | | 401 | `WRONG_AUTH_SCHEME` | Ключ авторизации отправлен в заголовке `Authorization: Bearer`. Сам ключ передаётся в `X-Api-Key`, а `Authorization: Bearer` несёт токен сессии | | 401 | `INVALID_SESSION` | Токен сессии истёк или недействителен — пройдите авторизацию заново | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `bizproc` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Пустой список — успешный ответ.** Пока на портале не зарегистрировано ни одного действия, `data` приходит пустым массивом с кодом `200`. Отсутствие действий — не ошибка. ## Смотрите также - [Зарегистрировать действие](/docs/entities/bizproc-activities/create) - [Ключи и авторизация](/docs/keys-auth) - [Ошибки](/docs/errors) --- # Bizproc Activities: Update ## Обновить действие `PATCH /v1/bizproc-activities/:code` Обновляет ранее зарегистрированное действие бизнес-процесса. Передавайте только изменяемые поля плоско в корне JSON — без обёртки `fields`. Вызывается только ключом авторизации вместе с заголовком `Authorization: Bearer`. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `code` (path) | string | да | Символьный код действия | ## Поля запроса (body) | Поле | Тип | Описание | |------|-----|---------| | `name` | string \| object | Название действия. Строка или локализованный объект вида `{"ru": "...", "en": "..."}` | | `handler` | string | URL обработчика действия. Домен совпадает с доменом приложения | | `description` | string \| object | Описание действия. Строка или локализованный объект | | `authUserId` | number | ID пользователя, чей токен передаётся приложению при вызове действия. Список: `GET /v1/users` | | `useSubscription` | string | Ждать ли ответа от приложения перед продолжением процесса: `Y` или `N` | | `properties` | object | Входные параметры действия | | `returnProperties` | object | Выходные параметры действия | | `documentType` | array | Тип документа: `[модуль, объект, тип]` | | `filter` | object | Правила `INCLUDE` / `EXCLUDE` по типу документа | | `usePlacement` | string | Открывать настройки действия в выдвижной панели: `Y` или `N` | | `placementHandler` | string | URL выдвижной панели настроек. Обязателен при `usePlacement: "Y"` | ## Примеры Токен сессии выдаёт OAuth-авторизация и живёт 24 часа без продления — [Передача ключа](/docs/keys-auth#передача-ключа). ### curl — ключ авторизации ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/bizproc-activities/notify_manager" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": { "ru": "Уведомить руководителя отдела", "en": "Notify department manager" } }' ``` ### JavaScript — ключ авторизации ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bizproc-activities/notify_manager', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: { ru: 'Уведомить руководителя отдела', en: 'Notify department manager' }, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | string | Код обновлённого действия — совпадает с `code` из пути | ## Пример ответа ```json { "success": true, "data": { "id": "notify_manager" } } ``` ## Пример ответа при ошибке 422 — действие с указанным кодом не найдено: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Activity or Robot not found!" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 401 | `TOKEN_MISSING` | Передан ключ авторизации без заголовка `Authorization: Bearer` | | 401 | `WRONG_AUTH_SCHEME` | Ключ авторизации отправлен в заголовке `Authorization: Bearer`. Сам ключ передаётся в `X-Api-Key`, а `Authorization: Bearer` несёт токен сессии | | 401 | `INVALID_SESSION` | Токен сессии истёк или недействителен — пройдите авторизацию заново | | 403 | `OAUTH_REQUIRED` | Запрос отправлен API-ключом. Обновлять действия можно только ключом авторизации | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `bizproc` | | 400 | `SERVER_APP_MISMATCH` | Новый `handler` ведёт на субдомен Black Hole, за которым нет сервера этого приложения — субдомена не существует либо сервер принадлежит другому приложению | | 503 | `BIZPROC_CALLBACK_RESOLVE_FAILED` | Платформе не удалось сопоставить обработчик с сервером. Действие не обновлено — повторите запрос | | 422 | `BITRIX_ERROR` | Битрикс24 не нашёл действие с указанным кодом или отклонил обновление — причина в `error.message` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Смена обработчика на субдомен Black Hole переключает действие на надёжную доставку.** Обратная смена — на адрес своего домена — возвращает прямые вызовы без повторов, а запрос без поля `handler` привязку не меняет. Смена на субдомен идёт только одиночным запросом — [Доставка вызовов действий и роботов](/docs/infra/bizproc-callbacks). ## Смотрите также - [Зарегистрировать действие](/docs/entities/bizproc-activities/create) - [Удалить действие](/docs/entities/bizproc-activities/delete) - [Доставка вызовов действий и роботов](/docs/infra/bizproc-callbacks) - [Ключи и авторизация](/docs/keys-auth) --- # Bizproc Robots: Create ## Зарегистрировать робота `POST /v1/bizproc-robots` Регистрирует нового робота автоматизации в Битрикс24. Поля передаются плоско в корне JSON — без обёртки `fields`. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `code` | string | да | Уникальный код робота. Разрешены символы `a-z`, `A-Z`, `0-9`, `.`, `-`, `_`. Становится идентификатором робота в путях обновления и удаления | | `name` | string \| object | да | Название робота. Строка или локализованный объект вида `{"ru": "...", "en": "..."}` | | `handler` | string | да | URL обработчика. Домен должен совпадать с доменом приложения | | `documentType` | array | нет | Тип документа `[модуль, объект, тип]`. Значения:
`["crm", "CCrmDocumentLead", "LEAD"]` — лиды
`["crm", "CCrmDocumentDeal", "DEAL"]` — сделки
`["crm", "Bitrix\\Crm\\Integration\\BizProc\\Document\\Quote", "QUOTE"]` — предложения
`["crm", "Bitrix\\Crm\\Integration\\BizProc\\Document\\SmartInvoice", "SMART_INVOICE"]` — счета
`["crm", "Bitrix\\Crm\\Integration\\BizProc\\Document\\Dynamic", "DYNAMIC_"]` — смарт-процессы, `` из поля `entityTypeId` в [GET /v1/smart-processes](/docs/entities/smart-processes/list) | | `description` | string \| object | нет | Описание робота. Строка или локализованный объект | | `authUserId` | number | нет | Пользователь, чей токен передаётся приложению при вызове робота. Список: `GET /v1/users` | | `useSubscription` | string | нет | Ждать ли ответа приложения перед продолжением правила: `Y` или `N` | | `properties` | object | нет | Входные параметры робота — поля, которые заполняются в правиле автоматизации | | `returnProperties` | object | нет | Выходные параметры робота — значения, которые робот возвращает | | `filter` | object | нет | Правила `INCLUDE` / `EXCLUDE` по типу документа | | `usePlacement` | string | нет | Открывать настройки робота в выдвижной панели: `Y` или `N` | | `placementHandler` | string | нет | URL выдвижной панели настроек. Обязателен при `usePlacement: "Y"` | ## Примеры Регистрировать робота можно только ключом авторизации — оба примера отправляют ключ авторизации и заголовок `Authorization: Bearer`. Токен сессии выдаёт OAuth-авторизация и живёт 24 часа без продления — [Передача ключа](/docs/keys-auth#передача-ключа). ### curl — ключ авторизации ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/bizproc-robots" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "code": "deal_notify", "name": { "ru": "Уведомление по сделке", "en": "Deal notification" }, "handler": "https://app.example.com/robots/deal-notify", "documentType": ["crm", "CCrmDocumentDeal", "DEAL"], "useSubscription": "N" }' ``` ### JavaScript — ключ авторизации ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bizproc-robots', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ code: 'deal_notify', name: { ru: 'Уведомление по сделке', en: 'Deal notification' }, handler: 'https://app.example.com/robots/deal-notify', documentType: ['crm', 'CCrmDocumentDeal', 'DEAL'], useSubscription: 'N', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | boolean | `true` — Битрикс24 подтвердил регистрацию робота. Это признак успеха, а не числовой идентификатор. Идентификатор робота — заданный вами `code` | ## Пример ответа ```json { "success": true, "data": { "id": true } } ``` ## Пример ответа при ошибке 403 — запрос отправлен API-ключом: ```json { "success": false, "error": { "code": "OAUTH_REQUIRED", "message": "bizproc-robots require an OAuth app key (vibe_app_*) with an Authorization: Bearer session — a personal vibe_api_* key lacks the per-user OAuth context Bitrix24 needs for these methods. Create an OAuth app (POST /v1/apps) and retry with its key. On this 403 switch keys — do NOT delete or recreate the app (that discards anything already registered under it, e.g. a bizproc robot you just registered)." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 403 | `OAUTH_REQUIRED` | Запрос отправлен API-ключом. Регистрировать роботов можно только ключом авторизации | | 401 | `TOKEN_MISSING` | Ключ авторизации без заголовка `Authorization: Bearer` | | 401 | `WRONG_AUTH_SCHEME` | Ключ авторизации отправлен в заголовке `Authorization: Bearer`. Сам ключ передаётся в `X-Api-Key`, а `Authorization: Bearer` несёт токен сессии | | 401 | `INVALID_SESSION` | Токен сессии истёк или недействителен — пройдите авторизацию заново | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `bizproc` | | 400 | `MISSING_REQUIRED_FIELDS` | Не передано обязательное поле — `code`, `name` или `handler` | | 400 | `SERVER_APP_MISMATCH` | `handler` ведёт на субдомен Black Hole, за которым нет сервера этого приложения — субдомена не существует либо сервер принадлежит другому приложению. Регистрируйте обработчик ключом того приложения, к которому привязан сервер | | 503 | `BIZPROC_CALLBACK_RESOLVE_FAILED` | Платформе не удалось сопоставить обработчик с сервером. Робот не зарегистрирован — повторите запрос | | 422 | `BITRIX_ERROR` | Ошибка валидации Битрикс24 — текст в `error.message` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Обработчик на субдомене Black Hole получает надёжную доставку.** Платформа берёт доставку вызовов на себя, а в Битрикс24 сохраняет адрес своего приёмника вместо переданного вами. Такой обработчик регистрируется только одиночным запросом, а сама доставка включается по аккаунтам — [Доставка вызовов действий и роботов](/docs/infra/bizproc-callbacks). ## Смотрите также - [Обновить робота](/docs/entities/bizproc-robots/update) - [Удалить робота](/docs/entities/bizproc-robots/delete) - [Доставка вызовов действий и роботов](/docs/infra/bizproc-callbacks) - [Ключи и авторизация](/docs/keys-auth) --- # Bizproc Robots: Delete ## Удалить робота `DELETE /v1/bizproc-robots/:code` Удаляет зарегистрированного робота по коду. Восстановить удалённого робота через API нельзя — зарегистрируйте нового при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `code` (path) | string | да | Код робота, заданный при регистрации | ## Примеры Удалять робота можно только ключом авторизации — оба примера отправляют ключ авторизации и заголовок `Authorization: Bearer`. Токен сессии выдаёт OAuth-авторизация и живёт 24 часа без продления — [Передача ключа](/docs/keys-auth#передача-ключа). ### curl — ключ авторизации ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/bizproc-robots/deal_notify" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — ключ авторизации ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bizproc-robots/deal_notify', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Робот удалён') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — успех проверяется по статусу. ## Пример ответа ```http HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 422 — робот с указанным кодом не найден: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Activity or Robot not found!" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 403 | `OAUTH_REQUIRED` | Запрос отправлен API-ключом. Удалять роботов можно только ключом авторизации | | 401 | `TOKEN_MISSING` | Ключ авторизации без заголовка `Authorization: Bearer` | | 401 | `WRONG_AUTH_SCHEME` | Ключ авторизации отправлен в заголовке `Authorization: Bearer`. Сам ключ передаётся в `X-Api-Key`, а `Authorization: Bearer` несёт токен сессии | | 401 | `INVALID_SESSION` | Токен сессии истёк или недействителен — пройдите авторизацию заново | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `bizproc` | | 422 | `BITRIX_ERROR` | Битрикс24 не нашёл робота с указанным кодом или отклонил удаление — причина в `error.message` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Зарегистрировать робота](/docs/entities/bizproc-robots/create) - [Обновить робота](/docs/entities/bizproc-robots/update) - [Ключи и авторизация](/docs/keys-auth) --- # Bizproc Robots: Fields ## Поля робота `GET /v1/bizproc-robots/fields` Возвращает схему полей робота автоматизации: тип каждого поля, доступность на запись, обязательность на регистрацию, подпись и описание. Отвечает описанием схемы, к зарегистрированным на портале роботам не обращается. ## Примеры Читать схему можно только ключом авторизации — оба примера отправляют ключ авторизации и заголовок `Authorization: Bearer`. Токен сессии выдаёт OAuth-авторизация и живёт 24 часа без продления — [Передача ключа](/docs/keys-auth#передача-ключа). ### curl — ключ авторизации ```bash curl -X GET "https://vibecode.bitrix24.tech/v1/bizproc-robots/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — ключ авторизации ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bizproc-robots/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() console.log(Object.keys(data.fields)) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.fields` | object | Схема полей: ключ — имя поля, значение — его описание | | `data.fields.<поле>.type` | string | Тип значения: `string`, `number`, `object`, `array` | | `data.fields.<поле>.readonly` | boolean | `true` — поле заполняется системой и в запросах на запись не передаётся | | `data.fields.<поле>.required` | boolean | Приходит только у обязательных на регистрацию полей | | `data.fields.<поле>.label` | string | Короткая подпись поля | | `data.fields.<поле>.description` | string | Развёрнутое описание поля | | `data.batch` | array | Операции сущности, доступные в [`POST /v1/batch`](/docs/batch) | Состав схемы: | Поле | Тип | RO | Обяз. | Описание | |------|-----|:--:|:-----:|---------| | `code` | string | | да | Уникальный код робота. Служит идентификатором в путях обновления и удаления | | `handler` | string | | да | URL обработчика робота | | `name` | string | | да | Название робота | | `description` | string | | нет | Описание робота | | `authUserId` | number | | нет | Пользователь, чей токен передаётся приложению при вызове. Список: `GET /v1/users` | | `useSubscription` | string | | нет | Ждать ли ответа приложения перед продолжением процесса: `Y` или `N` | | `properties` | object | | нет | Входные параметры робота | | `returnProperties` | object | | нет | Выходные параметры робота | | `documentType` | array | | нет | Тип документа, к которому применим робот — массив из трёх элементов: модуль, объект, тип. Допустимые сочетания: [Зарегистрировать робота](./create.md) | | `filter` | object | | нет | Правила `INCLUDE` и `EXCLUDE` по типу документа | | `usePlacement` | string | | нет | Открывать настройки робота в выдвижной панели: `Y` или `N` | | `placementHandler` | string | | нет | URL выдвижной панели настроек | ## Пример ответа ```json { "success": true, "data": { "fields": { "code": { "type": "string", "readonly": false, "required": true, "label": "Код", "description": "Уникальный код робота. Служит идентификатором в путях обновления и удаления." }, "handler": { "type": "string", "readonly": false, "required": true, "label": "URL обработчика", "description": "URL обработчика робота." }, "name": { "type": "string", "readonly": false, "required": true, "label": "Название", "description": "Название робота." }, "description": { "type": "string", "readonly": false, "label": "Описание", "description": "Описание робота." }, "authUserId": { "type": "number", "readonly": false, "label": "ID пользователя-авторизатора", "description": "Пользователь, чей токен передаётся приложению при вызове. Список: GET /v1/users." }, "useSubscription": { "type": "string", "readonly": false, "label": "Ожидание ответа", "description": "Ждать ли ответа приложения перед продолжением процесса: Y или N." }, "properties": { "type": "object", "readonly": false, "label": "Входные параметры", "description": "Входные параметры робота." }, "returnProperties": { "type": "object", "readonly": false, "label": "Выходные параметры", "description": "Выходные параметры робота." }, "documentType": { "type": "array", "readonly": false, "label": "Тип документа", "description": "Тип документа, к которому применим робот." }, "filter": { "type": "object", "readonly": false, "label": "Фильтр по типу документа", "description": "Правила INCLUDE и EXCLUDE по типу документа." }, "usePlacement": { "type": "string", "readonly": false, "label": "Настройки в панели", "description": "Открывать настройки робота в выдвижной панели: Y или N." }, "placementHandler": { "type": "string", "readonly": false, "label": "URL панели настроек", "description": "URL выдвижной панели настроек." } }, "batch": ["create", "update", "delete"] } } ``` ## Пример ответа при ошибке 403 — запрос отправлен API-ключом: ```json { "success": false, "error": { "code": "OAUTH_REQUIRED", "message": "bizproc-robots require an OAuth app key (vibe_app_*) with an Authorization: Bearer session — a personal vibe_api_* key lacks the per-user OAuth context Bitrix24 needs for these methods. Create an OAuth app (POST /v1/apps) and retry with its key. On this 403 switch keys — do NOT delete or recreate the app (that discards anything already registered under it, e.g. a bizproc robot you just registered)." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 403 | `OAUTH_REQUIRED` | Запрос отправлен API-ключом. Схема доступна только ключу авторизации | | 401 | `TOKEN_MISSING` | Ключ авторизации без заголовка `Authorization: Bearer` | | 401 | `WRONG_AUTH_SCHEME` | Ключ авторизации отправлен в заголовке `Authorization: Bearer`. Сам ключ передаётся в `X-Api-Key`, а `Authorization: Bearer` несёт токен сессии | | 401 | `INVALID_SESSION` | Токен сессии истёк или недействителен — пройдите авторизацию заново | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `bizproc` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Схема одинакова у роботов и действий.** Обе сущности описываются одним набором из двенадцати полей — различается смысл, а не состав. ## Смотрите также - [Список роботов](/docs/entities/bizproc-robots/list) - [Зарегистрировать робота](/docs/entities/bizproc-robots/create) - [Обновить робота](/docs/entities/bizproc-robots/update) - [Удалить робота](/docs/entities/bizproc-robots/delete) - [Ключи и авторизация](/docs/keys-auth) --- # Bizproc Robots: List ## Список роботов `GET /v1/bizproc-robots` Возвращает список кодов роботов автоматизации, зарегистрированных на портале. Каждый элемент ответа — символьный код робота, который используется в путях обновления и удаления. Метод работает только с ключом авторизации. Токен сессии выдаёт OAuth-авторизация и живёт 24 часа без продления — [Передача ключа](/docs/keys-auth#передача-ключа). ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Максимальное количество кодов в ответе | ## Примеры ### curl — ключ авторизации ```bash curl "https://vibecode.bitrix24.tech/v1/bizproc-robots" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — ключ авторизации ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bizproc-robots', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() console.log(`Зарегистрировано роботов: ${meta.total}`) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив строк — коды зарегистрированных роботов | | `meta.total` | number | Количество кодов в ответе | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | ## Пример ответа ```json { "success": true, "data": [ "deal_notify", "sms_sender" ], "meta": { "total": 2, "hasMore": false } } ``` ## Пример ответа при ошибке 403 — вызов API-ключом на методе только для ключа авторизации: ```json { "success": false, "error": { "code": "OAUTH_REQUIRED", "message": "bizproc-robots require an OAuth app key (vibe_app_*) with an Authorization: Bearer session — a personal vibe_api_* key lacks the per-user OAuth context Bitrix24 needs for these methods. Create an OAuth app (POST /v1/apps) and retry with its key. On this 403 switch keys — do NOT delete or recreate the app (that discards anything already registered under it, e.g. a bizproc robot you just registered)." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `OAUTH_REQUIRED` | Вызов API-ключом. Метод доступен только ключу авторизации | | 401 | `TOKEN_MISSING` | Ключ авторизации передан без заголовка `Authorization: Bearer <сессия>` | | 401 | `WRONG_AUTH_SCHEME` | Ключ авторизации отправлен в заголовке `Authorization: Bearer`. Сам ключ передаётся в `X-Api-Key`, а `Authorization: Bearer` несёт токен сессии | | 401 | `INVALID_SESSION` | Токен сессии истёк или недействителен — пройдите авторизацию заново | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `bizproc` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Пустой список — успешный ответ.** Пока на портале не зарегистрировано ни одного робота, `data` приходит пустым массивом с кодом `200`. Отсутствие роботов — не ошибка. ## Смотрите также - [Зарегистрировать робота](/docs/entities/bizproc-robots/create) - [Ключи и авторизация](/docs/keys-auth) - [Ошибки](/docs/errors) --- # Bizproc Robots: Update ## Обновить робота `PATCH /v1/bizproc-robots/:code` Обновляет поля зарегистрированного робота. Поля передаются плоско в корне JSON — без обёртки `fields`. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `code` (path) | string | да | Код робота, заданный при регистрации | ## Поля запроса (body) | Поле | Тип | Описание | |------|-----|---------| | `name` | string \| object | Название робота. Строка или локализованный объект вида `{"ru": "...", "en": "..."}` | | `handler` | string | URL обработчика. Домен должен совпадать с доменом приложения | | `documentType` | array | Тип документа `[модуль, объект, тип]`. Значения:
`["crm", "CCrmDocumentLead", "LEAD"]` — лиды
`["crm", "CCrmDocumentDeal", "DEAL"]` — сделки
`["crm", "Bitrix\\Crm\\Integration\\BizProc\\Document\\Quote", "QUOTE"]` — предложения
`["crm", "Bitrix\\Crm\\Integration\\BizProc\\Document\\SmartInvoice", "SMART_INVOICE"]` — счета
`["crm", "Bitrix\\Crm\\Integration\\BizProc\\Document\\Dynamic", "DYNAMIC_"]` — смарт-процессы, `` из поля `entityTypeId` в [GET /v1/smart-processes](/docs/entities/smart-processes/list) | | `description` | string \| object | Описание робота. Строка или локализованный объект | | `authUserId` | number | Пользователь, чей токен передаётся приложению при вызове робота. Список: `GET /v1/users` | | `useSubscription` | string | Ждать ли ответа приложения перед продолжением правила: `Y` или `N` | | `properties` | object | Входные параметры робота | | `returnProperties` | object | Выходные параметры робота | | `filter` | object | Правила `INCLUDE` / `EXCLUDE` по типу документа | | `usePlacement` | string | Открывать настройки робота в выдвижной панели: `Y` или `N` | | `placementHandler` | string | URL выдвижной панели настроек. Обязателен при `usePlacement: "Y"` | ## Примеры Обновлять робота можно только ключом авторизации — оба примера отправляют ключ авторизации и заголовок `Authorization: Bearer`. Токен сессии выдаёт OAuth-авторизация и живёт 24 часа без продления — [Передача ключа](/docs/keys-auth#передача-ключа). ### curl — ключ авторизации ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/bizproc-robots/deal_notify" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": { "ru": "Уведомление по сделке — v2", "en": "Deal notification v2" }, "handler": "https://app.example.com/robots/deal-notify-v2" }' ``` ### JavaScript — ключ авторизации ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bizproc-robots/deal_notify', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: { ru: 'Уведомление по сделке — v2', en: 'Deal notification v2' }, handler: 'https://app.example.com/robots/deal-notify-v2', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | string | Код обновлённого робота — совпадает с `code` из пути | ## Пример ответа ```json { "success": true, "data": { "id": "deal_notify" } } ``` ## Пример ответа при ошибке 422 — робот с указанным кодом не найден: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Activity or Robot not found!" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 403 | `OAUTH_REQUIRED` | Запрос отправлен API-ключом. Обновлять роботов можно только ключом авторизации | | 401 | `TOKEN_MISSING` | Ключ авторизации без заголовка `Authorization: Bearer` | | 401 | `WRONG_AUTH_SCHEME` | Ключ авторизации отправлен в заголовке `Authorization: Bearer`. Сам ключ передаётся в `X-Api-Key`, а `Authorization: Bearer` несёт токен сессии | | 401 | `INVALID_SESSION` | Токен сессии истёк или недействителен — пройдите авторизацию заново | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `bizproc` | | 400 | `SERVER_APP_MISMATCH` | Новый `handler` ведёт на субдомен Black Hole, за которым нет сервера этого приложения — субдомена не существует либо сервер принадлежит другому приложению | | 503 | `BIZPROC_CALLBACK_RESOLVE_FAILED` | Платформе не удалось сопоставить обработчик с сервером. Робот не обновлён — повторите запрос | | 422 | `BITRIX_ERROR` | Битрикс24 не нашёл робота с указанным кодом или отклонил обновление — причина в `error.message` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Смена обработчика на субдомен Black Hole переключает робота на надёжную доставку.** Обратная смена — на адрес своего домена — возвращает прямые вызовы без повторов, а запрос без поля `handler` привязку не меняет. Смена на субдомен идёт только одиночным запросом — [Доставка вызовов действий и роботов](/docs/infra/bizproc-callbacks). ## Смотрите также - [Зарегистрировать робота](/docs/entities/bizproc-robots/create) - [Удалить робота](/docs/entities/bizproc-robots/delete) - [Доставка вызовов действий и роботов](/docs/infra/bizproc-callbacks) - [Ключи и авторизация](/docs/keys-auth) --- # Bizproc Templates: Create ## Загрузить шаблон `POST /v1/bizproc-templates` Загружает шаблон бизнес-процесса из файла BPT и привязывает его к типу документа. Поля передаются плоско в корне JSON, без обёртки fields. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `templateData` | array | да | Файл шаблона из двух элементов — имя файла и его содержимое в base64. Пример: `["process.bpt", "eNrlWNtO41YUfe..."]` | | `documentType` | array | да | Тип документа `[модуль, объект, тип]`. Значения:
`["crm", "CCrmDocumentLead", "LEAD"]` — лиды
`["crm", "CCrmDocumentContact", "CONTACT"]` — контакты
`["crm", "CCrmDocumentCompany", "COMPANY"]` — компании
`["crm", "CCrmDocumentDeal", "DEAL"]` — сделки
`["crm", "Bitrix\\Crm\\Integration\\BizProc\\Document\\Quote", "QUOTE"]` — предложения
`["crm", "Bitrix\\Crm\\Integration\\BizProc\\Document\\SmartInvoice", "SMART_INVOICE"]` — счета
`["crm", "Bitrix\\Crm\\Integration\\BizProc\\Document\\Dynamic", "DYNAMIC_"]` — смарт-процессы, `` из поля `entityTypeId` в [GET /v1/smart-processes](/docs/entities/smart-processes/list)
`["lists", "BizprocDocument", "iblock_"]` — процессы в ленте новостей
`["lists", "Bitrix\\Lists\\BizprocDocumentLists", "iblock_"]` — списки в группах
`["disk", "Bitrix\\Disk\\BizProcDocument", "STORAGE_"]` — документы Диска | | `name` | string | да | Название шаблона. Пустое значение Битрикс24 отклоняет | | `description` | string | нет | Описание шаблона | | `autoExecute` | number | нет | Условие автозапуска: `0` — без автозапуска, `1` — при создании документа, `2` — при изменении, `3` — при создании и изменении. По умолчанию `0` | ## Примеры Загружать шаблоны можно только ключом авторизации — оба примера отправляют ключ авторизации и заголовок `Authorization: Bearer`. Токен сессии выдаёт OAuth-авторизация и живёт 24 часа без продления — [Передача ключа](/docs/keys-auth#передача-ключа). ### curl — ключ авторизации ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/bizproc-templates" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "documentType": ["crm", "CCrmDocumentDeal", "DEAL"], "name": "Согласование сделки", "description": "Загружен из приложения", "autoExecute": 0, "templateData": ["approval.bpt", "eNrlWNtO41YUfe..."] }' ``` ### JavaScript — ключ авторизации ```javascript import { readFile } from 'node:fs/promises' const file = await readFile('approval.bpt') const res = await fetch('https://vibecode.bitrix24.tech/v1/bizproc-templates', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ documentType: ['crm', 'CCrmDocumentDeal', 'DEAL'], name: 'Согласование сделки', description: 'Загружен из приложения', autoExecute: 0, templateData: ['approval.bpt', file.toString('base64')], }), }) const { success, data } = await res.json() console.log(`Идентификатор шаблона: ${data.id}`) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Идентификатор созданного шаблона. Указывается в путях обновления и удаления | ## Пример ответа ```json { "success": true, "data": { "id": 1215 } } ``` ## Пример ответа при ошибке 400 — не передан файл шаблона: ```json { "success": false, "error": { "code": "MISSING_REQUIRED_FIELDS", "message": "Body field \"templateData\" is required to create bizprocTemplate." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `MISSING_REQUIRED_FIELDS` | Не передано поле `templateData` | | 422 | `BITRIX_ERROR` | Не передан `name` — сообщение `Empty template name!`, `b24Code` содержит `ERROR_TEMPLATE_VALIDATION_FAILURE` | | 422 | `BITRIX_ERROR` | Не передан `documentType` или указан неизвестный тип — сообщение `Incorrect field DOCUMENT_TYPE!`, `b24Code` содержит `ERROR_TEMPLATE_VALIDATION_FAILURE` | | 422 | `BITRIX_ERROR` | Содержимое файла не распознано как шаблон. Текст `message` приходит от Битрикс24 на языке аккаунта, на русском — `Некорректный шаблон бизнес-процесса` | | 403 | `OAUTH_REQUIRED` | Запрос отправлен API-ключом. Загружать шаблоны можно только ключом авторизации | | 401 | `TOKEN_MISSING` | Ключ авторизации без заголовка `Authorization: Bearer` | | 401 | `WRONG_AUTH_SCHEME` | Ключ авторизации отправлен в заголовке `Authorization: Bearer`. Сам ключ передаётся в `X-Api-Key`, а `Authorization: Bearer` несёт токен сессии | | 401 | `INVALID_SESSION` | Токен сессии истёк или недействителен — пройдите авторизацию заново | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `bizproc` | При ошибке на стороне Битрикс24 объект `error` дополняется полем `b24Code` — машинным кодом причины. Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Файл `.bpt` готовится в Битрикс24.** Настройте процесс в конструкторе бизнес-процессов и выгрузите его в файл — этот файл и передаётся в `templateData`. Собрать содержимое `.bpt` через API нельзя, поэтому подготовка файла остаётся ручным шагом. **Ответ не показывает, что записалось.** Приходит только `id`, поэтому применённые значения проверяйте чтением записи через [`GET /v1/bizproc-templates`](./list.md) с фильтром по `id`. ## Смотрите также - [Список шаблонов](/docs/entities/bizproc-templates/list) - [Поиск шаблонов](/docs/entities/bizproc-templates/search) - [Поля шаблона](/docs/entities/bizproc-templates/fields) - [Обновить шаблон](/docs/entities/bizproc-templates/update) - [Удалить шаблон](/docs/entities/bizproc-templates/delete) - [Ключи и авторизация](/docs/keys-auth) --- # Bizproc Templates: Delete ## Удалить шаблон `DELETE /v1/bizproc-templates/:id` Удаляет шаблон бизнес-процесса, загруженный этим же приложением. Восстановить удалённый шаблон через API нельзя — загрузите файл заново при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор шаблона. Источник: [`GET /v1/bizproc-templates`](./list.md) | ## Примеры Удалять шаблоны можно только ключом авторизации — оба примера отправляют ключ авторизации и заголовок `Authorization: Bearer`. Токен сессии выдаёт OAuth-авторизация и живёт 24 часа без продления — [Передача ключа](/docs/keys-auth#передача-ключа). ### curl — ключ авторизации ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/bizproc-templates/1215" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — ключ авторизации ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bizproc-templates/1215', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Шаблон удалён') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — успех проверяется по статусу. ## Пример ответа ```http HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 422 — шаблон загружен другим приложением или создан в конструкторе Битрикс24: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "You can delete ONLY templates created by current application" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 422 | `BITRIX_ERROR` | Шаблон загружен другим приложением — сообщение `You can delete ONLY templates created by current application` | | 422 | `BITRIX_ERROR` | Шаблона с указанным `id` нет либо он уже удалён — сообщение `Workflow template not found.`, поле `b24Code` содержит `ERROR_TEMPLATE_NOT_FOUND` | | 403 | `OAUTH_REQUIRED` | Запрос отправлен API-ключом. Удалять шаблоны можно только ключом авторизации | | 401 | `TOKEN_MISSING` | Ключ авторизации без заголовка `Authorization: Bearer` | | 401 | `WRONG_AUTH_SCHEME` | Ключ авторизации отправлен в заголовке `Authorization: Bearer`. Сам ключ передаётся в `X-Api-Key`, а `Authorization: Bearer` несёт токен сессии | | 401 | `INVALID_SESSION` | Токен сессии истёк или недействителен — пройдите авторизацию заново | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `bizproc` | При ошибке на стороне Битрикс24 объект `error` дополняется полем `b24Code` — машинным кодом причины. Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Удаляются только свои шаблоны.** Удалить можно шаблон, загруженный тем же приложением, чьим ключом авторизации отправлен запрос. Шаблоны из конструктора Битрикс24 и шаблоны других приложений возвращают `422` и остаются на портале. ## Смотрите также - [Список шаблонов](/docs/entities/bizproc-templates/list) - [Поиск шаблонов](/docs/entities/bizproc-templates/search) - [Поля шаблона](/docs/entities/bizproc-templates/fields) - [Загрузить шаблон](/docs/entities/bizproc-templates/create) - [Обновить шаблон](/docs/entities/bizproc-templates/update) - [Ключи и авторизация](/docs/keys-auth) --- # Bizproc Templates: Fields ## Поля шаблона `GET /v1/bizproc-templates/fields` Возвращает схему полей шаблона бизнес-процесса: тип каждого поля, доступность на запись и обязательность на создание. Отвечает описанием схемы, к содержимому шаблонов портала не обращается. ## Примеры Читать схему можно только ключом авторизации — оба примера отправляют ключ авторизации и заголовок `Authorization: Bearer`. Токен сессии выдаёт OAuth-авторизация и живёт 24 часа без продления — [Передача ключа](/docs/keys-auth#передача-ключа). ### curl — ключ авторизации ```bash curl -X GET "https://vibecode.bitrix24.tech/v1/bizproc-templates/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — ключ авторизации ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bizproc-templates/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() console.log(Object.keys(data.fields)) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.fields` | object | Схема полей: ключ — имя поля, значение — его описание | | `data.fields.<поле>.type` | string | Тип значения: `number`, `string`, `array`, `datetime`, `boolean` | | `data.fields.<поле>.readonly` | boolean | `true` — поле заполняется системой и в запросах на запись не передаётся | | `data.fields.<поле>.required` | boolean | Приходит только у обязательных на создание полей | | `data.batch` | array | Операции сущности, доступные в [`POST /v1/batch`](/docs/batch) | Состав схемы: | Поле | Тип | RO | Описание | |------|-----|:--:|---------| | `id` | number | RO | Идентификатор шаблона | | `moduleId` | string | | Модуль, к которому привязан шаблон: `lists`, `crm`, `disk`, `bizproc` | | `entity` | string | | Объект документа внутри модуля, например `BizprocDocument` | | `documentType` | array | | Тип документа из трёх элементов — модуль, объект, тип | | `templateData` | array | | Файл шаблона — имя файла и содержимое в base64. Обязателен на создание, в ответах чтения не возвращается | | `autoExecute` | number | | Условие автозапуска: `0` — без автозапуска, `1` — при создании документа, `2` — при изменении, `3` — при создании и изменении | | `name` | string | | Название шаблона | | `description` | string | | Описание шаблона | | `modified` | datetime | RO | Дата последнего изменения | | `isModified` | boolean | RO | Правился ли шаблон после загрузки файла | | `userId` | number | | Автор последнего изменения. Список: `GET /v1/users` | ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true }, "moduleId": { "type": "string", "readonly": false }, "entity": { "type": "string", "readonly": false }, "documentType": { "type": "array", "readonly": false }, "templateData": { "type": "array", "readonly": false, "required": true }, "autoExecute": { "type": "number", "readonly": false }, "name": { "type": "string", "readonly": false }, "description": { "type": "string", "readonly": false }, "modified": { "type": "datetime", "readonly": true }, "isModified": { "type": "boolean", "readonly": true }, "userId": { "type": "number", "readonly": false } }, "batch": ["create", "update", "delete"] } } ``` ## Пример ответа при ошибке 403 — запрос отправлен API-ключом: ```json { "success": false, "error": { "code": "OAUTH_REQUIRED", "message": "bizproc-templates require an OAuth app key (vibe_app_*) with an Authorization: Bearer session — a personal vibe_api_* key lacks the per-user OAuth context Bitrix24 needs for these methods. Create an OAuth app (POST /v1/apps) and retry with its key. On this 403 switch keys — do NOT delete or recreate the app (that discards anything already registered under it, e.g. a bizproc robot you just registered)." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 403 | `OAUTH_REQUIRED` | Запрос отправлен API-ключом. Схема доступна только ключу авторизации | | 401 | `TOKEN_MISSING` | Ключ авторизации без заголовка `Authorization: Bearer` | | 401 | `WRONG_AUTH_SCHEME` | Ключ авторизации отправлен в заголовке `Authorization: Bearer`. Сам ключ передаётся в `X-Api-Key`, а `Authorization: Bearer` несёт токен сессии | | 401 | `INVALID_SESSION` | Токен сессии истёк или недействителен — пройдите авторизацию заново | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `bizproc` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Метка `readonly: false` не означает, что поле можно изменить.** Обновление применяет только `name`, `description`, `autoExecute` и `templateData` — см. [Обновить шаблон](./update.md). Остальные поля без метки `readonly` — `moduleId`, `entity`, `documentType`, `userId` — задаются при загрузке файла, и запрос на их изменение вернёт `200` без эффекта. **Отсутствие метки `readonly` не означает, что поле можно прочитать.** У `templateData` стоит `readonly: false`, но обратно это поле не приходит ни в списке, ни через `select` — оно доступно только на запись. **Метка `required: true` стоит только у `templateData`, хотя при загрузке обязательны три поля.** Схема отражает проверку на стороне Вайбкод: без `templateData` запрос отклоняется сразу с кодом `MISSING_REQUIRED_FIELDS`. Отсутствие `name` или `documentType` проходит эту проверку и отклоняется на шаг позже, с кодом `BITRIX_ERROR`. Полный список обязательных полей загрузки — на странице [Загрузить шаблон](./create.md). ## Смотрите также - [Список шаблонов](/docs/entities/bizproc-templates/list) - [Поиск шаблонов](/docs/entities/bizproc-templates/search) - [Загрузить шаблон](/docs/entities/bizproc-templates/create) - [Обновить шаблон](/docs/entities/bizproc-templates/update) - [Удалить шаблон](/docs/entities/bizproc-templates/delete) - [Ключи и авторизация](/docs/keys-auth) --- # Bizproc Templates: List ## Список шаблонов `GET /v1/bizproc-templates` Возвращает шаблоны бизнес-процессов, заведённые на портале, с фильтрацией, сортировкой и пагинацией. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `select` (query) | string | — | Поля через запятую: `id`, `moduleId`, `entity`, `documentType`, `autoExecute`, `name`, `description`, `modified`, `isModified`, `userId`. Без `select` возвращается полный набор объявленных полей, включая `id` | | `filter` (query) | object | — | Фильтрация по полям [`GET /v1/bizproc-templates/fields`](./fields.md).
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[entity]=BizprocDocument`.
Значения `moduleId` и `entity` — первые два элемента `documentType`, они перечислены в [Загрузить шаблон](./create.md) | | `order` (query) | object | — | Сортировка. Пример: `?order[id]=desc` | | `limit` (query) | number | `50` | Количество записей в ответе. Ноль не означает «без ограничения» — он игнорируется, приходят 50 записей и предупреждение `LIMIT_ZERO_IGNORED` | | `offset` (query) | number | `0` | Смещение выборки | Для `limit` больше 50 запрос пагинируется на стороне сервера. Максимум — 5000 записей за вызов. ## Примеры Читать шаблоны можно только ключом авторизации — оба примера отправляют ключ авторизации и заголовок `Authorization: Bearer`. Токен сессии выдаёт OAuth-авторизация и живёт 24 часа без продления — [Передача ключа](/docs/keys-auth#передача-ключа). ### curl — ключ авторизации ```bash curl -X GET "https://vibecode.bitrix24.tech/v1/bizproc-templates?select=id,name,moduleId,entity,autoExecute&limit=2" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — ключ авторизации ```javascript const params = new URLSearchParams({ select: 'id,name,moduleId,entity,autoExecute', limit: '2', }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/bizproc-templates?${params}`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() console.log(`Шаблонов на портале: ${meta.total}`) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив шаблонов. Состав полей элемента определяется параметром `select`, полная схема — [Поля шаблона](./fields.md) | | `meta.total` | number | Количество шаблонов, попавших под фильтр | | `meta.hasMore` | boolean | Есть ли записи за пределами `limit` | | `meta.warnings` | array | Предупреждения о разборе запроса. Каждое — объект с полями `code`, `field` и `message`, например неизвестное имя поля в `select` с кодом `UNKNOWN_SELECT_FIELD` | ## Пример ответа ```json { "success": true, "data": [ { "id": 23, "name": "Согласование договора", "moduleId": "lists", "entity": "BizprocDocument", "autoExecute": 1 }, { "id": 25, "name": "Заявка на закупку", "moduleId": "lists", "entity": "BizprocDocument", "autoExecute": 1 } ], "meta": { "total": 81, "hasMore": true } } ``` ## Пример ответа при ошибке 403 — запрос отправлен API-ключом: ```json { "success": false, "error": { "code": "OAUTH_REQUIRED", "message": "bizproc-templates require an OAuth app key (vibe_app_*) with an Authorization: Bearer session — a personal vibe_api_* key lacks the per-user OAuth context Bitrix24 needs for these methods. Create an OAuth app (POST /v1/apps) and retry with its key. On this 403 switch keys — do NOT delete or recreate the app (that discards anything already registered under it, e.g. a bizproc robot you just registered)." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_FILTER_OPERATOR` | Неизвестный оператор в фильтре. Сообщение перечисляет поддерживаемые операторы | | 400 | `INVALID_FILTER_OPERATOR` | Логический ключ `$or` или `$and` в фильтре. Условие ИЛИ задаётся оператором `$in` для одного поля или параллельными запросами через [`POST /v1/batch`](/docs/batch), условие И — соседними ключами одного фильтра | | 403 | `OAUTH_REQUIRED` | Запрос отправлен API-ключом. Читать шаблоны можно только ключом авторизации | | 401 | `TOKEN_MISSING` | Ключ авторизации без заголовка `Authorization: Bearer` | | 401 | `WRONG_AUTH_SCHEME` | Ключ авторизации отправлен в заголовке `Authorization: Bearer`. Сам ключ передаётся в `X-Api-Key`, а `Authorization: Bearer` несёт токен сессии | | 401 | `INVALID_SESSION` | Токен сессии истёк или недействителен — пройдите авторизацию заново | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `bizproc` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Файл шаблона в ответе не приходит.** Содержимое `.bpt`, переданное при создании в поле `templateData`, обратно через API не читается — ни в списке, ни через `select`. Сохраняйте исходный файл на своей стороне. **Поле `documentType` собирается из `moduleId` и `entity`.** Запрашивайте все три поля вместе — иначе первые два элемента массива приходят как `null`: `select=id,documentType` вернёт `[null, null, "iblock_19"]`, а `select=id,documentType,moduleId,entity` — `["lists", "BizprocDocument", "iblock_19"]`. **Неизвестное имя поля в `select`, `filter` или `order` не вызывает ошибку.** Ответ приходит с кодом `200`, неизвестное имя отбрасывается: в `filter` выборка не сужается, в `order` порядок не меняется, в `select` поле отсутствует в записях, а в `meta.warnings` приходит предупреждение с кодом `UNKNOWN_SELECT_FIELD`. Имена полей сверяйте со строкой `select` в таблице параметров или со схемой [`GET /v1/bizproc-templates/fields`](./fields.md). ## Смотрите также - [Поиск шаблонов](/docs/entities/bizproc-templates/search) - [Поля шаблона](/docs/entities/bizproc-templates/fields) - [Загрузить шаблон](/docs/entities/bizproc-templates/create) - [Обновить шаблон](/docs/entities/bizproc-templates/update) - [Удалить шаблон](/docs/entities/bizproc-templates/delete) - [Синтаксис фильтрации](/docs/filtering) - [Ключи и авторизация](/docs/keys-auth) --- # Bizproc Templates: Search ## Поиск шаблонов `POST /v1/bizproc-templates/search` Отбирает шаблоны бизнес-процессов по условиям и возвращает их списком. Отличие от списка шаблонов — условия отбора передаются в теле запроса, поэтому сложный фильтр не нужно укладывать в адресную строку. ## Поля запроса (body) | Поле | Тип | По умолч. | Описание | |------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям [`GET /v1/bizproc-templates/fields`](./fields.md).
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "entity": "CCrmDocumentLead" }`.
Значения `moduleId` и `entity` — первые два элемента `documentType`, они перечислены в [Загрузить шаблон](./create.md) | | `select` | string[] | — | Поля в ответе: `id`, `moduleId`, `entity`, `documentType`, `autoExecute`, `name`, `description`, `modified`, `isModified`, `userId`. Без `select` возвращается полный набор объявленных полей | | `order` | object | — | Сортировка. Пример: `{ "id": "desc" }` | | `limit` | number | `50` | Количество записей в ответе, до 5000. Ноль не означает «без ограничения» — он игнорируется, приходят 50 записей и предупреждение `LIMIT_ZERO_IGNORED` | | `offset` | number | `0` | Смещение выборки | | `autoWindow` | boolean | `true` | Разбивать выборку недельными окнами при фильтре по диапазону `modified` шире 14 дней. `false` отключает разбиение | ## Примеры Искать шаблоны можно только ключом авторизации — оба примера отправляют ключ авторизации и заголовок `Authorization: Bearer`. Токен сессии выдаёт OAuth-авторизация и живёт 24 часа без продления — [Передача ключа](/docs/keys-auth#передача-ключа). ### curl — ключ авторизации ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/bizproc-templates/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "moduleId": "crm" }, "select": ["id", "name", "entity", "autoExecute"], "order": { "id": "desc" }, "limit": 3 }' ``` ### JavaScript — ключ авторизации ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bizproc-templates/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { moduleId: 'crm' }, select: ['id', 'name', 'entity', 'autoExecute'], order: { id: 'desc' }, limit: 3, }), }) const { success, data, meta } = await res.json() console.log(`Найдено шаблонов: ${meta.total}`) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив шаблонов. Состав полей элемента определяется параметром `select`, полная схема — [Поля шаблона](./fields.md). Файл шаблона `templateData` в ответах не приходит | | `meta.total` | number | Количество шаблонов, попавших под фильтр | | `meta.hasMore` | boolean | Есть ли записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.warnings` | array | Предупреждения о разборе запроса. Каждое — объект с полями `code`, `field` и `message`, например неизвестное имя поля в `select` с кодом `UNKNOWN_SELECT_FIELD` | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временным окнам | | `meta.windowCount` | number | Число окон, на которые разбит диапазон дат. Приходит при `autoWindowed` равном `true` | | `meta.batchWaves` | number | Число волн параллельных запросов при разбиении по окнам | ## Пример ответа ```json { "success": true, "data": [ { "id": 1237, "name": "Согласование договора", "entity": "CCrmDocumentDeal", "autoExecute": 1 }, { "id": 1153, "name": "Заявка на закупку", "entity": "CCrmDocumentDeal", "autoExecute": 0 }, { "id": 1143, "name": "Обработка обращения", "entity": "CCrmDocumentLead", "autoExecute": 0 } ], "meta": { "total": 18, "hasMore": true, "durationMs": 113 } } ``` ## Пример ответа при ошибке 403 — запрос отправлен API-ключом: ```json { "success": false, "error": { "code": "OAUTH_REQUIRED", "message": "bizproc-templates require an OAuth app key (vibe_app_*) with an Authorization: Bearer session — a personal vibe_api_* key lacks the per-user OAuth context Bitrix24 needs for these methods. Create an OAuth app (POST /v1/apps) and retry with its key. On this 403 switch keys — do NOT delete or recreate the app (that discards anything already registered under it, e.g. a bizproc robot you just registered)." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_FILTER_OPERATOR` | Неизвестный оператор в фильтре. Сообщение перечисляет поддерживаемые операторы | | 400 | `INVALID_FILTER_OPERATOR` | Логический ключ `$or` или `$and` в фильтре. Условие ИЛИ задаётся оператором `$in` для одного поля или параллельными запросами через [`POST /v1/batch`](/docs/batch), условие И — соседними ключами одного фильтра | | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | | 403 | `OAUTH_REQUIRED` | Запрос отправлен API-ключом. Искать шаблоны можно только ключом авторизации | | 401 | `TOKEN_MISSING` | Ключ авторизации без заголовка `Authorization: Bearer` | | 401 | `WRONG_AUTH_SCHEME` | Ключ авторизации отправлен в заголовке `Authorization: Bearer`. Сам ключ передаётся в `X-Api-Key`, а `Authorization: Bearer` несёт токен сессии | | 401 | `INVALID_SESSION` | Токен сессии истёк или недействителен — пройдите авторизацию заново | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `bizproc` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Идентификатор в `select` перечисляется явно.** К выбранным полям `id` не добавляется — если он нужен для последующего обновления или удаления, включите его в `select` сами. **При разбиении по окнам `meta.total` считает только прочитанные окна.** Фильтр по диапазону `modified` шире 14 дней читает выборку недельными окнами и останавливается, когда набрал `limit` записей: в `meta.total` тогда приходит количество из уже прочитанных окон, оно меньше полного. Точное количество даёт запрос с `autoWindow: false` либо чтение всей выборки одним запросом с `limit` до 5000. **Неизвестное имя поля не прерывает запрос.** В `filter` выборка не сужается, в `order` порядок не меняется, в `select` поле отсутствует в записях, а в `meta.warnings` приходит предупреждение с кодом `UNKNOWN_SELECT_FIELD`. Имена полей сверяйте со схемой [`GET /v1/bizproc-templates/fields`](./fields.md). ## Смотрите также - [Список шаблонов](/docs/entities/bizproc-templates/list) - [Поля шаблона](/docs/entities/bizproc-templates/fields) - [Загрузить шаблон](/docs/entities/bizproc-templates/create) - [Синтаксис фильтрации](/docs/filtering) - [Ключи и авторизация](/docs/keys-auth) --- # Bizproc Templates: Update ## Обновить шаблон `PATCH /v1/bizproc-templates/:id` Изменяет шаблон бизнес-процесса, загруженный этим же приложением. Поля передаются плоско в корне JSON, без обёртки fields. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор шаблона. Источник: [`GET /v1/bizproc-templates`](./list.md) | ## Поля запроса (body) Изменяются четыре поля. Остальные поля записи задаются при загрузке файла и запросом на обновление не меняются. | Поле | Тип | Описание | |------|-----|---------| | `name` | string | Название шаблона | | `description` | string | Описание шаблона | | `autoExecute` | number | Условие автозапуска: `0` — без автозапуска, `1` — при создании документа, `2` — при изменении, `3` — при создании и изменении | | `templateData` | array | Новый файл шаблона из двух элементов — имя файла и его содержимое в base64 | ## Примеры Обновлять шаблоны можно только ключом авторизации — оба примера отправляют ключ авторизации и заголовок `Authorization: Bearer`. Токен сессии выдаёт OAuth-авторизация и живёт 24 часа без продления — [Передача ключа](/docs/keys-auth#передача-ключа). ### curl — ключ авторизации ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/bizproc-templates/1215" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Согласование сделки — версия 2", "autoExecute": 1 }' ``` ### JavaScript — ключ авторизации ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bizproc-templates/1215', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Согласование сделки — версия 2', autoExecute: 1, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Идентификатор обновлённого шаблона | ## Пример ответа ```json { "success": true, "data": { "id": 1215 } } ``` ## Пример ответа при ошибке 422 — шаблон загружен другим приложением или создан в конструкторе Битрикс24: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "You can update ONLY templates created by current application" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 422 | `BITRIX_ERROR` | Шаблон загружен другим приложением — сообщение `You can update ONLY templates created by current application` | | 422 | `BITRIX_ERROR` | Шаблона с указанным `id` нет — сообщение `Workflow template not found.`, поле `b24Code` содержит `ERROR_TEMPLATE_NOT_FOUND` | | 400 | `EMPTY_UPDATE_BODY` | Тело запроса пустое — передайте хотя бы одно поле | | 400 | `READONLY_FIELD` | В теле передано поле только для чтения, например `id` | | 403 | `OAUTH_REQUIRED` | Запрос отправлен API-ключом. Обновлять шаблоны можно только ключом авторизации | | 401 | `TOKEN_MISSING` | Ключ авторизации без заголовка `Authorization: Bearer` | | 401 | `WRONG_AUTH_SCHEME` | Ключ авторизации отправлен в заголовке `Authorization: Bearer`. Сам ключ передаётся в `X-Api-Key`, а `Authorization: Bearer` несёт токен сессии | | 401 | `INVALID_SESSION` | Токен сессии истёк или недействителен — пройдите авторизацию заново | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `bizproc` | При ошибке на стороне Битрикс24 объект `error` дополняется полем `b24Code` — машинным кодом причины. Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Обновляются только свои шаблоны.** Изменить можно шаблон, загруженный тем же приложением, чьим ключом авторизации отправлен запрос. Шаблоны из конструктора Битрикс24 и шаблоны других приложений возвращают `422` и остаются нетронутыми. **`documentType` не меняется после загрузки.** В схеме [`GET /v1/bizproc-templates/fields`](./fields.md) поле помечено `readonly: false`, но запрос на обновление применяет только четыре поля из таблицы выше — тип документа задаётся при загрузке файла. Запрос с `documentType` вернёт `200`, значение останется прежним. **Имя поля вне списка выше не вызывает ошибку.** Ответ приходит с кодом `200`, значение не применяется. Проверяйте результат чтением записи через [`GET /v1/bizproc-templates`](./list.md) с фильтром по `id`. **Замена файла помечает шаблон как изменённый.** После обновления `templateData` поле `isModified` в ответе списка становится `true`. ## Смотрите также - [Список шаблонов](/docs/entities/bizproc-templates/list) - [Поиск шаблонов](/docs/entities/bizproc-templates/search) - [Поля шаблона](/docs/entities/bizproc-templates/fields) - [Загрузить шаблон](/docs/entities/bizproc-templates/create) - [Удалить шаблон](/docs/entities/bizproc-templates/delete) - [Ключи и авторизация](/docs/keys-auth) --- # Bookings: Create ## Создать бронирование `POST /v1/bookings` Создаёт новое бронирование на портале. Поля передаются плоско в корне JSON. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `resourceIds` | number[] | да | Идентификаторы ресурсов, которые резервирует бронирование. Массив не может быть пустым. Получить список ресурсов через API Вайбкод нельзя — укажите известные идентификаторы | | `datePeriod` | object | да | Период бронирования. Структура: `from` и `to`, у каждого — `timestamp` (Unix-секунды) и `timezone` (часовой пояс в формате IANA, например `Europe/Moscow`) | | `name` | string | нет | Название бронирования. Может быть `null` | | `description` | string | нет | Описание бронирования. Может быть `null` | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/bookings" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "resourceIds": [1], "datePeriod": { "from": { "timestamp": 1780132384, "timezone": "Europe/Moscow" }, "to": { "timestamp": 1780135984, "timezone": "Europe/Moscow" } }, "name": "Переговорная на демонстрацию", "description": "Бронь переговорной комнаты" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/bookings" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "resourceIds": [1], "datePeriod": { "from": { "timestamp": 1780132384, "timezone": "Europe/Moscow" }, "to": { "timestamp": 1780135984, "timezone": "Europe/Moscow" } }, "name": "Переговорная на демонстрацию", "description": "Бронь переговорной комнаты" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bookings', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ resourceIds: [1], datePeriod: { from: { timestamp: 1780132384, timezone: 'Europe/Moscow' }, to: { timestamp: 1780135984, timezone: 'Europe/Moscow' }, }, name: 'Переговорная на демонстрацию', description: 'Бронь переговорной комнаты', }), }) const { success, data } = await res.json() console.log('ID бронирования:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bookings', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ resourceIds: [1], datePeriod: { from: { timestamp: 1780132384, timezone: 'Europe/Moscow' }, to: { timestamp: 1780135984, timezone: 'Europe/Moscow' }, }, name: 'Переговорная на демонстрацию', description: 'Бронь переговорной комнаты', }), }) const { success, data } = await res.json() ``` ## Поля ответа Возвращается полный объект созданного бронирования. | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Идентификатор созданного бронирования | | `data.name` | string \| null | Название бронирования | | `data.description` | string \| null | Описание бронирования | | `data.resourceIds` | number[] | Идентификаторы зарезервированных ресурсов | | `data.datePeriod` | object | Период бронирования: `from` и `to`, у каждого `timestamp` и `timezone` | ## Пример ответа ```json { "success": true, "data": { "id": 27, "name": "Переговорная на демонстрацию", "description": "Бронь переговорной комнаты", "resourceIds": [1], "datePeriod": { "from": { "timestamp": 1780132384, "timezone": "Europe/Moscow" }, "to": { "timestamp": 1780135984, "timezone": "Europe/Moscow" } } } } ``` ## Пример ответа при ошибке 422 — не переданы обязательные поля: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Required fields: resourceIds, datePeriod" } } ``` ## Ошибки | HTTP | Код | Описание | |------|--------------|---------| | 422 | `BITRIX_ERROR` | Не переданы обязательные поля `resourceIds` и/или `datePeriod`. Сообщение: `Required fields: resourceIds, datePeriod` | | 422 | `BITRIX_ERROR` | Передан пустой массив `resourceIds`. Сообщение: `Empty resource collection` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `booking` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Бронирования](/docs/entities/bookings) - [Обновить бронирование](/docs/entities/bookings/update) - [Получить бронирование](/docs/entities/bookings/get) - [Удалить бронирование](/docs/entities/bookings/delete) - [Batch](/docs/batch) --- # Bookings: Delete ## Удалить бронирование `DELETE /v1/bookings/:id` Удаляет бронирование по идентификатору. Восстановить удалённое бронирование через API нельзя — создавайте новое при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор бронирования | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/bookings/27" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/bookings/27" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bookings/27', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Бронирование удалено') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bookings/27', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Бронирование удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом. Признак успеха — код ответа, не содержимое. ## Пример ответа ```http HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 422 — бронирование уже удалено или не существует: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "booking not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Бронирование с указанным `id` не найдено или уже удалено. Сообщение: `booking not found` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `booking` | | 401 | `MISSING_API_KEY` | Запрос отправлен без заголовка `X-Api-Key` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список бронирований](/docs/entities/bookings/list) - [Создать бронирование](/docs/entities/bookings/create) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Bookings: Fields ## Поля бронирования `GET /v1/bookings/fields` Возвращает описание всех полей бронирования с типами и атрибутами. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/bookings/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/bookings/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bookings/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bookings/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | RO | Описание | |------|-----|:--:|---------| | `id` | number | да | Идентификатор бронирования | | `name` | string | | Название бронирования. Может быть `null` | | `description` | string | | Описание бронирования. Может быть `null` | | `resourceIds` | array | | Идентификаторы резервируемых ресурсов. Обязательно при создании, массив не может быть пустым | | `datePeriod` | object | | Период бронирования. Обязательно при создании: `from` и `to`, у каждого `timestamp` в Unix-секундах и `timezone` в формате IANA | ## Пример ответа `GET /v1/bookings/fields` возвращает описания полей под ключом `data.fields`, где каждое поле — `{ type, readonly, label, description }`, а у обязательных при создании — ещё и `required: true`. Имена полей в camelCase, как в ответах API. Плюс `data.batch` со списком доступных batch-операций. ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "ID бронирования", "description": "Уникальный идентификатор бронирования." }, "name": { "type": "string", "readonly": false, "label": "Название", "description": "Название бронирования, заданное пользователем." }, "description": { "type": "string", "readonly": false, "label": "Описание", "description": "Текстовое описание бронирования с дополнительными деталями." }, "resourceIds": { "type": "array", "readonly": false, "required": true, "label": "ID ресурсов", "description": "Список идентификаторов ресурсов, зарезервированных этим бронированием." }, "datePeriod": { "type": "object", "readonly": false, "required": true, "label": "Период бронирования", "description": "Временной интервал бронирования с датой и временем начала и окончания." } }, "batch": ["create", "update", "delete"] } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'booking' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `booking` | | 401 | `MISSING_API_KEY` | Запрос отправлен без заголовка `X-Api-Key` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Бронирования](/docs/entities/bookings) - [Создать бронирование](/docs/entities/bookings/create) - [Обновить бронирование](/docs/entities/bookings/update) --- # Bookings: Get ## Получить бронирование `GET /v1/bookings/:id` Возвращает одно бронирование по идентификатору. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор бронирования | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/bookings/27" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/bookings/27" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bookings/27', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Бронирование:', data.name, data.resourceIds) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bookings/27', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа Объект содержит 5 полей — все приведены в таблице ниже. | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Идентификатор бронирования | | `data.name` | string \| null | Название бронирования. Может быть `null` | | `data.description` | string \| null | Описание бронирования. Может быть `null` | | `data.resourceIds` | number[] | Идентификаторы резервируемых ресурсов | | `data.datePeriod` | object | Период бронирования: `from` и `to`, у каждого `timestamp` (Unix-секунды) и `timezone` (IANA) | ## Пример ответа ```json { "success": true, "data": { "id": 27, "name": "Переговорная на демонстрацию", "description": "Бронь переговорной комнаты", "resourceIds": [1], "datePeriod": { "from": { "timestamp": 1780132384, "timezone": "Europe/Moscow" }, "to": { "timestamp": 1780135984, "timezone": "Europe/Moscow" } } } } ``` ## Пример ответа при ошибке 422 — бронирование не найдено: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Booking not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Бронирование с указанным `id` не найдено | | 422 | `BITRIX_ERROR` | `id` содержит нечисловое значение | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `booking` | | 401 | `MISSING_API_KEY` | Запрос отправлен без заголовка `X-Api-Key` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список бронирований](/docs/entities/bookings/list) - [Обновить бронирование](/docs/entities/bookings/update) - [Удалить бронирование](/docs/entities/bookings/delete) - [Лимиты и оптимизация](/docs/optimization) --- # Bookings: List ## Список бронирований `GET /v1/bookings` Возвращает бронирования за указанный диапазон дат. Начало и конец интервала обязательны — без них запрос вернётся с ошибкой. Записи вне переданного интервала в ответ не попадают. ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `dateFrom` (query) | string \| number | да | — | Начало интервала. ISO 8601 (`"2026-05-01T00:00:00Z"`) или Unix-секунды (`1714521600`) | | `dateTo` (query) | string \| number | да | — | Конец интервала. ISO 8601 или Unix-секунды | | `limit` (query) | number | нет | `50` | Количество записей (от 1 до 5000). Отрицательное значение или ноль → `400 INVALID_PARAMS` | | `offset` (query) | number | нет | `0` | Смещение. Используйте с осторожностью — см. «Известные особенности» | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/bookings?dateFrom=2024-01-01T00:00:00Z&dateTo=2026-12-31T23:59:59Z&limit=10" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/bookings?dateFrom=2024-01-01T00:00:00Z&dateTo=2026-12-31T23:59:59Z&limit=10" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const params = new URLSearchParams({ dateFrom: '2024-01-01T00:00:00Z', dateTo: '2026-12-31T23:59:59Z', limit: '10', }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/bookings?${params}`, { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Получено ${data.length} бронирований, hasMore: ${meta.hasMore}`) ``` ### JavaScript — OAuth-приложение ```javascript const params = new URLSearchParams({ dateFrom: '2024-01-01T00:00:00Z', dateTo: '2026-12-31T23:59:59Z', limit: '10', }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/bookings?${params}`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив бронирований (поля каждой записи — см. [Бронирования](/docs/entities/bookings)) | | `meta.total` | number | Всегда `0` — общее количество не вычисляется. Для определения наличия дополнительных записей используйте `meta.hasMore` | | `meta.hasMore` | boolean | `true`, если количество записей, подходящих под фильтр, превышает `limit` | ## Пример ответа ```json { "success": true, "data": [ { "datePeriod": { "from": { "timestamp": 1723446900, "timezone": "Europe/Moscow" }, "to": { "timestamp": 1723447800, "timezone": "Europe/Moscow" } }, "description": null, "id": 3, "name": null, "resourceIds": [1, 3] }, { "datePeriod": { "from": { "timestamp": 1741687200, "timezone": "Europe/Kaliningrad" }, "to": { "timestamp": 1741690800, "timezone": "Europe/Kaliningrad" } }, "description": null, "id": 1, "name": "Запись", "resourceIds": [1] }, { "datePeriod": { "from": { "timestamp": 1752570000, "timezone": "Europe/Kaliningrad" }, "to": { "timestamp": 1752571800, "timezone": "Europe/Kaliningrad" } }, "description": null, "id": 5, "name": null, "resourceIds": [1] } ], "meta": { "total": 0, "hasMore": true } } ``` ## Пример ответа при ошибке 400 — не переданы обязательные параметры: ```json { "success": false, "error": { "code": "MISSING_REQUIRED_PARAMS", "message": "GET /v1/bookings requires dateFrom and dateTo query parameters (ISO 8601 datetime or Unix seconds). Example: ?dateFrom=2026-05-01T00:00:00Z&dateTo=2026-05-31T23:59:59Z." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_PARAMS` | Не переданы `dateFrom` или `dateTo` | | 400 | `INVALID_DATE` | Значение `dateFrom` или `dateTo` не является ISO 8601 или Unix-секундами | | 400 | `INVALID_PARAMS` | `limit` меньше 1 или не является числом | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `booking` | | 401 | `MISSING_API_KEY` | Заголовок `X-Api-Key` не передан | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`offset` работает ненадёжно на малых значениях.** Значения `offset` меньше размера страницы не гарантируют пропуск записей. Для выборки бронирований за стандартный рабочий период (день, неделя, месяц) все записи помещаются в одну страницу при достаточном `limit` — предпочтительнее одного запроса с большим `limit` вместо серии запросов с малым `offset`. ## Смотрите также - [Поиск бронирований](/docs/entities/bookings/search) - [Получить бронирование](/docs/entities/bookings/get) - [Создать бронирование](/docs/entities/bookings/create) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Bookings: Search ## Поиск бронирований `POST /v1/bookings/search` Возвращает бронирования за указанный диапазон дат. Начало и конец интервала обязательны. Подходит, когда параметры запроса удобнее передавать в теле, а не в строке запроса. ## Поля запроса (body) Принимает две равнозначные формы. Используйте любую из них. **Форма 1 — параметры на верхнем уровне:** | Поле | Тип | Обяз. | По умолч. | Описание | |------|-----|:-----:|-----------|---------| | `dateFrom` | string \| number | да | — | Начало интервала. ISO 8601 (`"2026-05-01T00:00:00Z"`) или Unix-секунды (`1714521600`) | | `dateTo` | string \| number | да | — | Конец интервала. ISO 8601 или Unix-секунды | | `limit` | number | нет | `50` | Количество записей (от 1 до 5000) | | `offset` | number | нет | `0` | Смещение | **Форма 2 — параметры во вложенном фильтре:** | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `filter.within.dateFrom` | string \| number | да | Начало интервала | | `filter.within.dateTo` | string \| number | да | Конец интервала | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/bookings/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "dateFrom": "2024-01-01T00:00:00Z", "dateTo": "2026-12-31T23:59:59Z", "limit": 10 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/bookings/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "dateFrom": "2024-01-01T00:00:00Z", "dateTo": "2026-12-31T23:59:59Z", "limit": 10 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bookings/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ dateFrom: '2024-01-01T00:00:00Z', dateTo: '2026-12-31T23:59:59Z', limit: 10, }), }) const { success, data, meta } = await res.json() console.log(`Получено ${data.length} бронирований, hasMore: ${meta.hasMore}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bookings/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ dateFrom: '2024-01-01T00:00:00Z', dateTo: '2026-12-31T23:59:59Z', limit: 10, }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив бронирований (поля каждой записи — см. [Бронирования](/docs/entities/bookings)) | | `meta.total` | number | Всегда `0` — общее количество не вычисляется. Для определения наличия дополнительных записей используйте `meta.hasMore` | | `meta.hasMore` | boolean | `true`, если количество записей, подходящих под условие, превышает `limit` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа ```json { "success": true, "data": [ { "datePeriod": { "from": { "timestamp": 1723446900, "timezone": "Europe/Moscow" }, "to": { "timestamp": 1723447800, "timezone": "Europe/Moscow" } }, "description": null, "id": 3, "name": null, "resourceIds": [1, 3] }, { "datePeriod": { "from": { "timestamp": 1741687200, "timezone": "Europe/Kaliningrad" }, "to": { "timestamp": 1741690800, "timezone": "Europe/Kaliningrad" } }, "description": null, "id": 1, "name": "Запись", "resourceIds": [1] }, { "datePeriod": { "from": { "timestamp": 1752570000, "timezone": "Europe/Kaliningrad" }, "to": { "timestamp": 1752571800, "timezone": "Europe/Kaliningrad" } }, "description": null, "id": 5, "name": null, "resourceIds": [1] } ], "meta": { "total": 0, "hasMore": true } } ``` ## Пример ответа при ошибке 400 — не переданы обязательные параметры: ```json { "success": false, "error": { "code": "MISSING_REQUIRED_PARAMS", "message": "POST /v1/bookings/search requires { dateFrom, dateTo } at the top level OR { filter: { within: { dateFrom, dateTo } } }. Values are ISO 8601 or Unix seconds." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_PARAMS` | Не переданы `dateFrom` или `dateTo` ни в одной из допустимых форм | | 400 | `INVALID_DATE` | Значение `dateFrom` или `dateTo` не является ISO 8601 или Unix-секундами | | 400 | `INVALID_PARAMS` | `limit` меньше 1 или не является числом | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `booking` | | 401 | `MISSING_API_KEY` | Заголовок `X-Api-Key` не передан | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список бронирований](/docs/entities/bookings/list) - [Получить бронирование](/docs/entities/bookings/get) - [Создать бронирование](/docs/entities/bookings/create) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Bookings: Update ## Обновить бронирование `PATCH /v1/bookings/:id` Обновляет поля существующего бронирования. Передавайте только изменяемые поля плоско в корне JSON. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор бронирования | ## Поля запроса (body) | Поле | Тип | Описание | |------|-----|---------| | `resourceIds` | number[] | Идентификаторы ресурсов, которые резервирует бронирование. Массив не может быть пустым. Получить список ресурсов через API Вайбкод нельзя — укажите известные идентификаторы | | `datePeriod` | object | Период бронирования. Структура: `from` и `to`, у каждого — `timestamp` (Unix-секунды) и `timezone` (часовой пояс в формате IANA, например `Europe/Moscow`) | | `name` | string | Название бронирования. Может быть `null` | | `description` | string | Описание бронирования. Может быть `null` | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/bookings/27" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Переговорная (обновлено)", "description": "Изменённое описание" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/bookings/27" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Переговорная (обновлено)", "description": "Изменённое описание" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bookings/27', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Переговорная (обновлено)', description: 'Изменённое описание', }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/bookings/27', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Переговорная (обновлено)', description: 'Изменённое описание', }), }) const { success, data } = await res.json() ``` ## Поля ответа Возвращается полный объект обновлённого бронирования. | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Идентификатор бронирования | | `data.name` | string \| null | Название бронирования | | `data.description` | string \| null | Описание бронирования | | `data.resourceIds` | number[] | Идентификаторы зарезервированных ресурсов | | `data.datePeriod` | object | Период бронирования: `from` и `to`, у каждого `timestamp` и `timezone` | ## Пример ответа ```json { "success": true, "data": { "id": 27, "name": "Переговорная (обновлено)", "description": "Изменённое описание", "resourceIds": [1], "datePeriod": { "from": { "timestamp": 1780132384, "timezone": "Europe/Moscow" }, "to": { "timestamp": 1780135984, "timezone": "Europe/Moscow" } } } } ``` ## Пример ответа при ошибке 422 — бронирование не найдено: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Booking not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|--------------|---------| | 422 | `BITRIX_ERROR` | Бронирование с указанным `id` не существует. Сообщение: `Booking not found` | | 422 | `BITRIX_ERROR` | Передан пустой массив `resourceIds`. Сообщение: `Empty resource collection` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `booking` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Бронирования](/docs/entities/bookings) - [Создать бронирование](/docs/entities/bookings/create) - [Получить бронирование](/docs/entities/bookings/get) - [Удалить бронирование](/docs/entities/bookings/delete) - [Batch](/docs/batch) --- # Calendar Events: Create ## Создать событие `POST /v1/calendar-events` Создаёт новое событие в указанном календаре. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `type` | string | да | Тип календаря: `user`, `group`, `company_calendar` | | `ownerId` | number | да | ID владельца календаря: сотрудник (`GET /v1/users`) или рабочая группа | | `name` | string | да | Название события | | `from` | datetime | да | Начало события в ISO 8601. Принимается строка с явным смещением (`2026-06-10T10:00:00+03:00`), в UTC (`2026-06-10T07:00:00Z`) или без зоны (`2026-06-10T10:00:00`) | | `to` | datetime | да | Окончание события в ISO 8601. Принимается строка с явным смещением (`2026-06-10T11:00:00+03:00`), в UTC (`2026-06-10T08:00:00Z`) или без зоны (`2026-06-10T11:00:00`) | | `timezoneFrom` | string | нет | Часовой пояс начала события (IANA-имя: `Europe/Moscow`, `Asia/Almaty`, `UTC`). Без него используется часовой пояс сотрудника-владельца API-ключа | | `timezoneTo` | string | нет | Часовой пояс окончания события (IANA-имя) | | `description` | string | нет | Описание | | `sectionId` | number | нет | ID секции календаря. Если поле не передано — при каждом вызове создаётся новая секция. Чтобы события писались в одну секцию, передавайте `sectionId` существующей секции. ID существующей секции возвращает [`GET /v1/calendar-events`](./list.md) в поле `sectionId` любого ранее созданного события | | `skipTime` | boolean | нет | Событие на весь день. При `true` время в `from`/`to` игнорируется, длительность фиксируется в 24 часа | | `importance` | string | нет | `high`, `normal`, `low` | | `accessibility` | string | нет | Занятость: `busy`, `quest` (под вопросом), `free`, `absent` | | `location` | string | нет | Место проведения | | `color` | string | нет | Цвет события (HEX, `#RRGGBB`) | | `attendees` | number[] | нет | Массив ID приглашённых сотрудников. Список: `GET /v1/users`. **Только для записи** — в ответе участники возвращаются в полях `attendeeList`, `attendeesCodes`. См. [Поля события](./fields.md) | | `remind` | array | нет | Настройки напоминаний. Каждый элемент: `{type: 'min' \| 'hour' \| 'day', count: <число>}` | | `rrule` | object | нет | Расписание повторения регулярного события. Структура полей и пример — секция [Регулярное событие](#регулярное-событие) ниже | | `isPrivate` | boolean | нет | Приватное событие — детали скрыты от других пользователей | | `isMeeting` | boolean | нет | Событие-встреча с приглашениями | Полный список полей: [`GET /v1/calendar-events/fields`](./fields.md). ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/calendar-events" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "type": "user", "ownerId": 1, "name": "Созвон с командой", "from": "2026-06-10T10:00:00", "to": "2026-06-10T11:00:00", "timezoneFrom": "Europe/Moscow", "timezoneTo": "Europe/Moscow", "description": "Еженедельная синхронизация", "accessibility": "busy", "sectionId": 3 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/calendar-events" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "type": "user", "ownerId": 1, "name": "Созвон с командой", "from": "2026-06-10T10:00:00", "to": "2026-06-10T11:00:00", "timezoneFrom": "Europe/Moscow", "timezoneTo": "Europe/Moscow", "description": "Еженедельная синхронизация", "accessibility": "busy", "sectionId": 3 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calendar-events', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ type: 'user', ownerId: 1, name: 'Созвон с командой', from: '2026-06-10T10:00:00', to: '2026-06-10T11:00:00', timezoneFrom: 'Europe/Moscow', timezoneTo: 'Europe/Moscow', description: 'Еженедельная синхронизация', accessibility: 'busy', sectionId: 3, }), }) const { success, data } = await res.json() console.log('ID события:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calendar-events', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ type: 'user', ownerId: 1, name: 'Созвон с командой', from: '2026-06-10T10:00:00', to: '2026-06-10T11:00:00', timezoneFrom: 'Europe/Moscow', timezoneTo: 'Europe/Moscow', description: 'Еженедельная синхронизация', accessibility: 'busy', sectionId: 3, }), }) const { success, data } = await res.json() ``` ## Регулярное событие Чтобы создать повторяющееся событие, передайте поле `rrule` как объект. Запрос: ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/calendar-events" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "type": "user", "ownerId": 1, "name": "Созвон команды", "from": "2026-07-13T10:00:00", "to": "2026-07-13T11:00:00", "timezoneFrom": "Europe/Moscow", "timezoneTo": "Europe/Moscow", "rrule": { "FREQ": "WEEKLY", "INTERVAL": 1, "BYDAY": ["MO", "WE"], "UNTIL": "2026-09-30" } }' ``` Создаётся одно событие с одним `id` — список (`GET /v1/calendar-events`) вернёт по элементу на каждое вхождение серии, все они будут иметь общий `parentId`. Удаление события (`DELETE /v1/calendar-events/:id`) убирает всю серию. Поля `rrule`: | Поле | Тип | Описание | |------|-----|---------| | `FREQ` | string | Периодичность: `DAILY`, `WEEKLY`, `MONTHLY`, `YEARLY` | | `INTERVAL` | number | Интервал. `1` — каждый цикл, `2` — через один и т. д. | | `BYDAY` | string[] | Дни недели для `WEEKLY`: `SU`, `MO`, `TU`, `WE`, `TH`, `FR`, `SA` | | `UNTIL` | date | Дата окончания серии в формате `YYYY-MM-DD`. Альтернатива — `COUNT` | | `COUNT` | number | Количество повторений. Альтернатива — `UNTIL` | ## Поля ответа Объект созданного события со всеми полями — см. [Поля события](./fields.md). URL карточки события в Битрикс24 зависит от типа календаря: | `type` | URL | |---|---| | `user` | `https://.bitrix24.ru/company/personal/user//calendar/?EVENT_ID=&EVENT_DATE=` | | `group` | `https://.bitrix24.ru/workgroups/group//calendar/?EVENT_ID=&EVENT_DATE=` | | `company_calendar` | `https://.bitrix24.ru/calendar/?EVENT_ID=&EVENT_DATE=` | `` — дата начала события (поле `from`) в формате «день.месяц.год» через точку. `` — домен вашего портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": { "id": 7773, "parentId": 7773, "deleted": false, "type": "user", "ownerId": 1, "name": "Созвон с командой", "from": "2026-06-10T10:00:00+03:00", "to": "2026-06-10T11:00:00+03:00", "skipTime": false, "durationSeconds": 3600, "createdBy": 1, "dateCreate": "06/05/2026 09:12:00 am", "updatedAt": "06/05/2026 09:12:00 am", "description": "Еженедельная синхронизация", "accessibility": "busy", "importance": "normal", "isMeeting": false, "meetingStatus": "H", "meetingHost": 1, "sectionId": 3, "attendeeList": [ { "id": 1, "entryId": "7773", "status": "H" } ] } } ``` ## Пример ответа при ошибке 422 — не передано обязательное поле: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Не задан обязательный параметр \"name\" для метода \"calendar.event.add\"" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Не передано обязательное поле (`type`, `ownerId`, `name`, `from`, `to`) | | 400 | `READONLY_FIELD` | В теле запроса передано read-only поле (`id`, `createdBy`, `dateCreate`, `updatedAt`) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `calendar` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Накопление секций при создании без `sectionId`.** Если поле `sectionId` не передано, при каждом вызове создаётся новая секция календаря. На серии вызовов без `sectionId` в календаре сотрудника копятся пустые секции, видимые в веб-интерфейсе Битрикс24. Чтобы все события писались в одну секцию, передавайте `sectionId` существующей секции — её ID можно взять из ответа [`GET /v1/calendar-events`](./list.md). ## Смотрите также - [Поля события](./fields.md) - [Обновить событие](./update.md) - [Удалить событие](./delete.md) - [Список событий](./list.md) --- # Calendar Events: Delete ## Удалить событие `DELETE /v1/calendar-events/:id` Удаляет событие календаря по идентификатору. Восстановить удалённое событие через API нельзя — создавайте новое при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID события | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/calendar-events/7773" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/calendar-events/7773" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calendar-events/7773', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Событие удалено') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calendar-events/7773', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом. Признак успеха — код ответа, не содержимое. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 422 — событие уже удалено или не существовало: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "При удалении события произошла ошибка" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Событие с указанным `id` не существует или уже удалено | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `calendar` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Регулярные события.** Удаление события с правилом повторения (`rrule`) удаляет всю серию — все вхождения с одним `parentId`. Точечно убрать одно вхождение из серии через API нельзя. ## Смотрите также - [Список событий](./list.md) - [Batch](/docs/batch) --- # Calendar Events: Fields ## Поля события `GET /v1/calendar-events/fields` Возвращает схему полей события: тип, признак readonly, доступные batch-операции. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/calendar-events/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/calendar-events/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calendar-events/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data.fields).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calendar-events/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | RO | Описание | |------|-----|:--:|---------| | `id` | number | да | ID события | | `parentId` | number | да | ID родительского события (для повторяющихся событий совпадает с `id` исходного) | | `active` | boolean | да | Активность события. Возвращается в списке `GET /v1/calendar-events`, в карточке `GET /v1/calendar-events/:id` отсутствует | | `deleted` | boolean | да | Признак удаления | | `name` | string | | Название | | `description` | string | | Описание | | `type` | string | | Тип календаря: `user`, `group`, `company_calendar` | | `ownerId` | number | | ID владельца календаря. Сотрудник: `GET /v1/users` | | `from` | datetime | | Начало (ISO 8601) | | `to` | datetime | | Окончание (ISO 8601) | | `skipTime` | boolean | | Событие на весь день. При `true` длительность фиксируется в 24 часа | | `durationSeconds` | number | да | Продолжительность события в секундах | | `importance` | string | | Важность: `high`, `normal`, `low` | | `accessibility` | string | | Занятость: `busy`, `quest`, `free`, `absent` | | `location` | string | | Место проведения | | `color` | string | | Цвет события (HEX) | | `textColor` | string | | Цвет текста события (HEX). Возвращается в списке `GET /v1/calendar-events`, в карточке `GET /v1/calendar-events/:id` отсутствует | | `sectionId` | number | | ID секции календаря | | `isPrivate` | boolean | | Приватное событие | | `isMeeting` | boolean | | Событие-встреча с приглашениями | | `attendees` | number[] | | Массив ID приглашённых сотрудников для записи. **Только для записи** — в ответах событий это поле не возвращается, участники доступны в `attendeeList`, `attendeesCodes` | | `attendeesCodes` | string[] | да | Внутренние коды участников Битрикс24 (формат `U`) | | `attendeeList` | array | да | Расширенный список участников: `{ id, entryId, status }`, где `status` — `Y` (принято), `H` (хост), `Q` (под вопросом), `N` (отклонено) | | `remind` | array | | Настройки напоминаний | | `rrule` | object | | Расписание повторения регулярного события: периодичность (`FREQ`), интервал (`INTERVAL`), дни недели (`BYDAY`), граница серии (`UNTIL` или `COUNT`). На чтение `BYDAY` приходит объектом-словарём вида `{"MO":"MO"}`, а `UNTIL` — строка-дата в формате региональных настроек портала, которую Битрикс24 подставляет даже при заданном `COUNT` | | `createdBy` | number | да | ID создателя события. Поиск: `GET /v1/users` | | `dateCreate` | string | да | Дата создания. Строка в формате Битрикс24, зависящем от региональных настроек портала (например `08.06.2026 17:29:51` или `06/08/2026 05:29:51 pm`). Это не ISO 8601 — не разбирать фиксированным парсером | | `updatedAt` | string | да | Дата последнего изменения. Строка в том же формате региональных настроек портала, что и `dateCreate`. Это не ISO 8601 | | `meetingStatus` | string | да | Статус участия владельца календаря: `Y` (принято), `H` (хост), `Q` (под вопросом), `N` (отклонено) | | `meetingHost` | number | да | ID организатора встречи. Поиск: `GET /v1/users` | | `eventType` | string | да | Технический тип события (для системных событий) | | `syncStatus` | string | да | Статус синхронизации с внешними календарями | | `recurrenceId` | number | да | ID серии повторяющихся событий | | `collabId` | number | да | ID коллабораций (при участии внешних пользователей) | | `occurrenceIndex` | number | да | Порядковый номер вхождения в развёрнутой серии повторяющегося события, начинается с нуля. Строки серии делят один `id` — пара `id` + `occurrenceIndex` однозначно идентифицирует строку набора | | `version` | number | да | Монотонный счётчик изменений события — растёт при каждом изменении и не зависит от региональных настроек. Сравнивайте пары `id` + `version`, чтобы находить обновлённые события без разбора дат | Незаполненные скалярные поля возвращаются как `null`, пустые массивы — как `[]`. В минимальном событии `null` приходит, например, в `eventType`, `description`, `location`, `color`, `textColor`, `rrule`, `recurrenceId`, `syncStatus`, `collabId`, а `remind` приходит пустым массивом `[]`. **Полей `dateFrom` / `dateTo` не существует** — начало и окончание события лежат в `from` / `to`. Исходные имена Битрикс24 `DATE_FROM` / `DATE_TO` принимаются в `select` как алиасы и проецируют канонические `from` / `to`. Незнакомое имя в `select` на этой сущности отвечает `400 UNKNOWN_SELECT_FIELD` с перечнем допустимых имён. ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "ID события", "description": "Уникальный идентификатор события календаря." }, "name": { "type": "string", "readonly": false, "label": "Название", "description": "Название события календаря." }, "type": { "type": "string", "readonly": false, "label": "Тип календаря", "description": "Тип календаря события: пользовательский, групповой или общий календарь компании." }, "ownerId": { "type": "number", "readonly": false, "label": "ID владельца календаря", "description": "Идентификатор владельца календаря — сотрудника или рабочей группы." }, "from": { "type": "datetime", "readonly": false, "label": "Начало события", "description": "Дата и время начала события в формате ISO 8601 со смещением часового пояса." }, "to": { "type": "datetime", "readonly": false, "label": "Окончание события", "description": "Дата и время окончания события в формате ISO 8601 со смещением часового пояса." }, "skipTime": { "type": "boolean", "readonly": false, "label": "Событие на весь день", "description": "Признак того, что событие длится весь день без учёта конкретного времени." }, "durationSeconds": { "type": "number", "readonly": true, "label": "Длительность в секундах", "description": "Продолжительность события в секундах." }, "importance": { "type": "string", "readonly": false, "label": "Важность", "description": "Уровень важности события: высокий, обычный или низкий." }, "accessibility": { "type": "string", "readonly": false, "label": "Занятость", "description": "Статус занятости владельца на время события: занят, под вопросом, свободен или отсутствует." }, "sectionId": { "type": "number", "readonly": false, "label": "ID секции календаря", "description": "Идентификатор секции календаря, в которую записано событие." }, "attendees": { "type": "array", "readonly": false, "label": "Приглашённые участники", "description": "Массив ID сотрудников, приглашаемых на событие — поле только для записи; в ответе участники возвращаются в attendeeList и attendeesCodes." }, "rrule": { "type": "object", "readonly": false, "label": "Правило повторения", "description": "Расписание повторения регулярного события: периодичность, интервал, дни недели и условие окончания серии." }, "dateCreate": { "type": "string", "readonly": true, "label": "Дата создания", "description": "Дата и время создания события в строковом формате, зависящем от региональных настроек портала." }, "updatedAt": { "type": "string", "readonly": true, "label": "Дата изменения", "description": "Дата и время последнего изменения события в строковом формате, зависящем от региональных настроек портала." }, "occurrenceIndex": { "type": "number", "readonly": true, "label": "Номер вхождения", "description": "Порядковый номер (с нуля) вхождения в развёрнутой серии повторяющегося события. Повторяющиеся события возвращаются отдельной строкой на каждое вхождение с одним и тем же id — пара (id, occurrenceIndex) однозначно идентифицирует строку." }, "version": { "type": "number", "readonly": true, "label": "Версия изменений", "description": "Монотонный счётчик изменений на стороне Битрикс24 — растёт при каждом изменении события. Локале-независимый маркер изменения: сравнивайте пары (id, version), чтобы находить обновлённые события без разбора дат." } }, "batch": ["create", "update", "delete"] } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'calendar' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `calendar` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать событие](./create.md) - [Обновить событие](./update.md) - [Список событий](./list.md) --- # Calendar Events: Get ## Получить событие `GET /v1/calendar-events/:id` Возвращает одно событие календаря по идентификатору. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID события | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/calendar-events/7773" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/calendar-events/7773" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calendar-events/7773', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log(data.name, '—', data.from) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calendar-events/7773', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа Объект события со всеми полями — см. [Поля события](./fields.md). ## Пример ответа ```json { "success": true, "data": { "id": 7773, "parentId": 7773, "deleted": false, "type": "user", "ownerId": 1, "name": "Созвон с командой", "from": "2026-06-10T10:00:00+03:00", "to": "2026-06-10T11:00:00+03:00", "skipTime": false, "durationSeconds": 3600, "createdBy": 1, "dateCreate": "06/05/2026 09:12:00 am", "updatedAt": "06/05/2026 09:12:00 am", "description": "Еженедельная синхронизация", "accessibility": "busy", "importance": "normal", "isMeeting": false, "meetingStatus": "H", "meetingHost": 1, "sectionId": 3, "attendeeList": [ { "id": 1, "entryId": "7773", "status": "H" } ] } } ``` ## Пример ответа при ошибке 404 — событие не найдено: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "calendarEvent 99999999 not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Событие с указанным `id` не существует | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `calendar` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Поля события](./fields.md) - [Обновить событие](./update.md) - [Список событий](./list.md) --- # Calendar Events: List ## Список событий `GET /v1/calendar-events` Возвращает события календаря за фиксированный период вокруг текущей даты: с месяца назад по три месяца вперёд. ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `type` (query) | string | да | — | Тип календаря: `user`, `group`, `company_calendar` | | `ownerId` (query) | number | да | — | ID владельца календаря: сотрудник (`GET /v1/users`) или рабочая группа | | `limit` (query) | number | нет | `50` | Размер окна выдачи — до 5000 вхождений | | `offset` (query) | number | нет | `0` | Начало окна: пропустить первые N вхождений отсортированного набора | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/calendar-events?type=user&ownerId=1&limit=10" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/calendar-events?type=user&ownerId=1&limit=10" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const params = new URLSearchParams({ type: 'user', ownerId: '1', limit: '10' }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/calendar-events?${params}`, { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} событий`) ``` ### JavaScript — OAuth-приложение ```javascript const params = new URLSearchParams({ type: 'user', ownerId: '1', limit: '10' }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/calendar-events?${params}`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив событий (все поля — см. [Поля события](./fields.md)) | | `meta.total` | number | Общее количество вхождений в наборе. Повторяющиеся события развёрнуты — по строке на вхождение | | `meta.hasMore` | boolean | `true`, пока за пределами окна `offset + limit` остаются записи | URL карточки любого события из массива `data` зависит от типа календаря: | `type` | URL | |---|---| | `user` | `https://.bitrix24.ru/company/personal/user//calendar/?EVENT_ID=&EVENT_DATE=` | | `group` | `https://.bitrix24.ru/workgroups/group//calendar/?EVENT_ID=&EVENT_DATE=` | | `company_calendar` | `https://.bitrix24.ru/calendar/?EVENT_ID=&EVENT_DATE=` | `` — дата начала события (поле `from`) в формате «день.месяц.год» через точку. `` — домен вашего портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 7773, "parentId": 7773, "active": true, "deleted": false, "type": "user", "ownerId": 1, "name": "Созвон с командой", "from": "2026-06-10T10:00:00+03:00", "to": "2026-06-10T11:00:00+03:00", "skipTime": false, "durationSeconds": 3600, "createdBy": 1, "dateCreate": "06/05/2026 09:12:00 am", "updatedAt": "06/05/2026 09:12:00 am", "description": "Еженедельная синхронизация", "accessibility": "busy", "importance": "normal", "isMeeting": false, "meetingStatus": "H", "meetingHost": 1, "sectionId": 3, "attendeeList": [ { "id": 1, "entryId": "7773", "status": "H" } ] } ], "meta": { "total": 1, "hasMore": false } } ``` ## Пример ответа при ошибке 400 — не переданы обязательные `type` и `ownerId`: ```json { "success": false, "error": { "code": "MISSING_REQUIRED_PARAMS", "message": "GET /v1/calendar-events requires query parameters: type, ownerId. Example: GET /v1/calendar-events?type=...&ownerId=..." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_PARAMS` | Не переданы `type` и (или) `ownerId` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `calendar` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Весь диапазон — одним набором.** Запрошенный период приходит от Битрикс24 одним массивом без пагинации. Платформа сортирует его детерминированно — по началу события `from`, при равенстве по `id`, затем по `occurrenceIndex` — и отдаёт окно от `offset` до `offset + limit`. Порядок элементов воспроизводим от запроса к запросу, окна с разными `offset` не пересекаются и в объединении дают весь набор. **Регулярные события.** Событие с полем `rrule` в списке возвращается отдельным элементом на каждое вхождение серии, попадающее в окно выборки. У всех элементов общий `id` и `parentId`, различаются `from` / `to` и `occurrenceIndex` — пара `id` + `occurrenceIndex` однозначно идентифицирует строку набора. **Отслеживание изменений.** Поле `version` — монотонный счётчик изменений события, не зависящий от региональных настроек аккаунта. Запросите список с `select=id,version`, сравните пары со своим снимком и дочитайте изменённые события. Описания обоих полей — [Поля события](./fields.md). ## Смотрите также - [Создать событие](./create.md) - [Получить событие](./get.md) - [Поля события](./fields.md) --- # Calendar Events: Search ## Поиск событий календаря `POST /v1/calendar-events/search` Возвращает те же события, что и `GET /v1/calendar-events`, но параметры передаются в теле запроса. Поиск ведётся в пределах одного календаря — `type` и `ownerId` обязательны. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|-------|---------| | `filter` | object | да | Условия поиска. Обязательны `type` и `ownerId`. Дополнительно — `from`, `to`, `section`. Поле вне этого набора возвращает `400 UNSUPPORTED_FILTER` | | `filter.type` | string | да | Тип календаря: `user`, `group`, `company_calendar` | | `filter.ownerId` | number | да | ID владельца календаря. Для `type=user` — ID сотрудника из `GET /v1/users`, для `type=group` — ID рабочей группы | | `filter.from` | string | нет | Начало периода выборки событий (ISO 8601) | | `filter.to` | string | нет | Конец периода выборки событий (ISO 8601) | | `filter.section` | number | нет | ID секции календаря | | `limit` | number | нет | Количество записей до 5000. По умолчанию `50` | | `offset` | number | нет | Пропустить N записей | | `order` | object | нет | Сортировка: `{ "from": "desc" }` | | `select` | string[] | нет | Выборка полей: `["id", "name", "from"]` | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/calendar-events/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "type": "user", "ownerId": 1, "from": "2026-06-01T00:00:00", "to": "2026-07-01T00:00:00" }, "order": { "from": "desc" }, "limit": 20 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/calendar-events/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "type": "user", "ownerId": 1, "from": "2026-06-01T00:00:00", "to": "2026-07-01T00:00:00" }, "order": { "from": "desc" }, "limit": 20 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calendar-events/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { type: 'user', ownerId: 1, from: '2026-06-01T00:00:00', to: '2026-07-01T00:00:00', }, order: { from: 'desc' }, limit: 20, }), }) const { success, data } = await res.json() console.log('Найдено:', data.length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calendar-events/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { type: 'user', ownerId: 1, from: '2026-06-01T00:00:00', to: '2026-07-01T00:00:00', }, order: { from: 'desc' }, limit: 20, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив событий. Все поля — см. [Поля события](/docs/entities/calendar-events/fields) | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа Показаны основные поля. Полный список — [Поля события](/docs/entities/calendar-events/fields). ```json { "success": true, "data": [ { "id": 7521, "type": "user", "ownerId": 1, "name": "Еженедельная планёрка", "from": "2026-06-15T14:00:00+03:00", "to": "2026-06-15T15:00:00+03:00", "skipTime": false, "durationSeconds": 3600, "importance": "normal", "accessibility": "busy", "isMeeting": true, "sectionId": 3 } ], "meta": { "total": 1, "hasMore": false, "durationMs": 169 } } ``` ## Пример ответа при ошибке 400 — фильтр по неподдерживаемому полю: ```json { "success": false, "error": { "code": "UNSUPPORTED_FILTER", "message": "calendar-events search accepts only top-level parameters: type, ownerId, from, to, section. Filter keys received: NAME. For single-record lookup use GET /v1/calendar-events/:id." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_PARAMS` | Не переданы обязательные `type` и (или) `ownerId`. `message` перечисляет недостающие поля | | 400 | `UNSUPPORTED_FILTER` | Фильтр содержит поле вне набора `type`, `ownerId`, `from`, `to`, `section` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `calendar` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Поиск ограничен одним календарём и периодом.** Отбор идёт только по `type`, `ownerId`, `from`, `to`, `section` — по содержимому события (`name`, `importance`, `accessibility` и другим полям) поиск не ведётся. Чтобы отобрать события по таким полям, получите выборку за нужный период и отфильтруйте её на стороне приложения. ## Смотрите также - [Список событий](/docs/entities/calendar-events/list) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Calendar Events: Update ## Обновить событие `PATCH /v1/calendar-events/:id` Обновляет поля существующего события. Передавайте только изменяемые поля — Вайбкод автоматически дочитывает текущее событие и подставляет `type`, `ownerId`, `name`, которые Битрикс24 требует при каждом обновлении. ## Часто обновляемые поля | Поле | Тип | Описание | |------|-----|---------| | `name` | string | Название события | | `to` | datetime | Перенос окончания (ISO 8601). Передавайте вместе с `timezoneTo` | | `timezoneTo` | string | Часовой пояс окончания (IANA-имя, `Europe/Moscow`) | | `location` | string | Место проведения | | `description` | string | Описание | | `accessibility` | string | Занятость: `busy`, `quest`, `free`, `absent` | | `importance` | string | Важность: `high`, `normal`, `low` | | `attendees` | number[] | Массив ID приглашённых сотрудников | Полный список изменяемых полей: [`GET /v1/calendar-events/fields`](./fields.md). ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/calendar-events/7773" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Созвон с командой — расширенная встреча", "to": "2026-06-10T12:00:00", "timezoneTo": "Europe/Moscow", "location": "Переговорная №3" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/calendar-events/7773" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Созвон с командой — расширенная встреча", "to": "2026-06-10T12:00:00", "timezoneTo": "Europe/Moscow", "location": "Переговорная №3" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calendar-events/7773', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Созвон с командой — расширенная встреча', to: '2026-06-10T12:00:00', timezoneTo: 'Europe/Moscow', location: 'Переговорная №3', }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calendar-events/7773', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Созвон с командой — расширенная встреча', to: '2026-06-10T12:00:00', timezoneTo: 'Europe/Moscow', location: 'Переговорная №3', }), }) const { success, data } = await res.json() ``` ## Поля ответа Обновлённый объект события со всеми полями — см. [Поля события](./fields.md). ## Пример ответа ```json { "success": true, "data": { "id": 7773, "parentId": 7773, "type": "user", "ownerId": 1, "name": "Созвон с командой — расширенная встреча", "from": "2026-06-10T10:00:00+03:00", "to": "2026-06-10T12:00:00+03:00", "skipTime": false, "durationSeconds": 7200, "updatedAt": "06/05/2026 11:30:00 am", "accessibility": "busy", "importance": "normal", "sectionId": 3, "location": "Переговорная №3" } } ``` ## Пример ответа при ошибке 404 — событие не найдено: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "calendarEvent 99999999 not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Событие с указанным `id` не существует | | 400 | `READONLY_FIELD` | В теле запроса передано read-only поле — полный список в [Поля события](./fields.md) с пометкой «да» в колонке RO | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `calendar` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Перенос начала события через `PATCH` сейчас не работает.** Поле `from` принимается, но новое значение в Битрикс24 не записывается. Поле `to` обновляется корректно. Чтобы перенести начало события — удалите старое и создайте новое через [`POST /v1/calendar-events`](./create.md). ## Смотрите также - [Получить событие](./get.md) - [Поля события](./fields.md) - [Создать событие](./create.md) - [Удалить событие](./delete.md) --- # Calendar Sections: Batch ## Пакет операций над секциями календаря `POST /v1/calendar-sections/batch` Массовое создание, обновление или удаление секций календаря одним запросом — до 500 элементов за вызов. Это отдельный эндпоинт сущности, не путать с [универсальным batch](/docs/batch), который объединяет операции разных сущностей и ограничен 50 вызовами. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `action` | string | да | Тип операции: `create`, `update` или `delete` | | `items` | array | да при `create` и `update` | Список элементов, до 500. Для `create` — `[{ type, ownerId, name, color?, ... }]`. Для `update` — `[{ id, type, ownerId, name, ... }]`. Набор полей элемента совпадает с телом [`POST /v1/calendar-sections`](./create.md) и [`PATCH /v1/calendar-sections/:id`](./update.md) | | `ids` | number[] | да при `delete` | Идентификаторы секций для удаления, до 500 | | `type` | string | да при `delete` | Тип календаря, передаётся рядом с `ids`. Значения — `user`, `group`, `company_calendar`, `location` | | `ownerId` | number | да при `delete` | Идентификатор владельца календаря, передаётся рядом с `ids`. Для `type=user` — `id` сотрудника из [`GET /v1/users`](/docs/entities/users), для `type=group` — `id` рабочей группы, для `type=location` — `0` | Для `create` и `update` пара `type` + `ownerId` и поле `name` входят в каждый элемент `items`. Для `delete` `type` и `ownerId` общие для всего пакета и передаются на верхнем уровне рядом с `ids`. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/calendar-sections/batch" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "action": "create", "items": [ { "type": "user", "ownerId": 1, "name": "Командные встречи", "color": "#ff5b49" }, { "type": "user", "ownerId": 1, "name": "Личное", "color": "#2fc6f6" } ] }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/calendar-sections/batch" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "action": "create", "items": [ { "type": "user", "ownerId": 1, "name": "Командные встречи", "color": "#ff5b49" }, { "type": "user", "ownerId": 1, "name": "Личное", "color": "#2fc6f6" } ] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calendar-sections/batch', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ action: 'create', items: [ { type: 'user', ownerId: 1, name: 'Командные встречи', color: '#ff5b49' }, { type: 'user', ownerId: 1, name: 'Личное', color: '#2fc6f6' }, ], }), }) const { data } = await res.json() data.results.forEach((item) => { if (item.success) console.log(`#${item.index} → id=${item.id}`) else console.log(`#${item.index} → ошибка: ${item.error} ${item.message}`) }) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calendar-sections/batch', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ action: 'create', items: [ { type: 'user', ownerId: 1, name: 'Командные встречи', color: '#ff5b49' }, { type: 'user', ownerId: 1, name: 'Личное', color: '#2fc6f6' }, ], }), }) const { data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true`, если запрос прошёл верхнеуровневую валидацию. Результат каждого элемента — в `data.results[i].success` | | `data.results` | array | Массив результатов в том же порядке, что `items` или `ids` запроса | | `data.results[].index` | number | Индекс элемента, начиная с `0` | | `data.results[].success` | boolean | Результат этой операции | | `data.results[].id` | number | Идентификатор секции при `create`, `update` и `delete` | | `data.results[].error` | string | Код ошибки для упавшего элемента, `UNKNOWN` если код не определён. Может быть пустой строкой, если Битрикс24 прислал только текст без кода | | `data.results[].message` | string | Текст ошибки для упавшего элемента | | `data.summary.total` | number | Всего обработано элементов | | `data.summary.succeeded` | number | Сколько выполнено успешно | | `data.summary.failed` | number | Сколько завершилось ошибкой | ## Пример ответа `action: create` — обе секции созданы: ```json { "success": true, "data": { "results": [ { "index": 0, "success": true, "id": 181 }, { "index": 1, "success": true, "id": 183 } ], "summary": { "total": 2, "succeeded": 2, "failed": 0 } } } ``` `action: update` — элемент без `type` завершился ошибкой, а верхний `success` остался `true`: ```json { "success": true, "data": { "results": [ { "index": 0, "success": false, "error": "", "message": "Не задан обязательный параметр \"type\" для метода \"calendar.section.update\"" } ], "summary": { "total": 1, "succeeded": 0, "failed": 1 } } } ``` ## Пример ответа при ошибке 400 — при `action: delete` не переданы `type` и `ownerId` рядом с `ids`: ```json { "success": false, "error": { "code": "MISSING_REQUIRED_PARAMS", "message": "POST /v1/calendar-sections/batch { action: \"delete\" } requires type, ownerId alongside ids. Example: { \"action\": \"delete\", \"ids\": [...], \"type\": ..., \"ownerId\": ... }", "missing": ["type", "ownerId"] } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_PARAMS` | `action: delete` без `type` или `ownerId` рядом с `ids` | | 400 | `INVALID_BATCH_ACTION` | `action` не является поддерживаемой операцией | | 400 | `BATCH_ITEM_VALIDATION` | `items` или `ids` пустой либо не массив, или элемент `update` без `id` | | 400 | `BATCH_LIMIT_EXCEEDED` | В запросе передано более 500 элементов | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `calendar` | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ в режиме «только чтение» — запись запрещена | | 403 | `MANAGEMENT_KEY_NO_ENTITY_ACCESS` | Использован management-ключ вместо ключа приложения | | 401 | `TOKEN_MISSING` | У ключа нет настроенных токенов | Ошибки отдельных элементов приходят внутри `data.results[i]` — поле `error` с кодом или пустой строкой и `message` с текстом. Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Верхний `success` остаётся `true`, если запрос прошёл верхнеуровневую валидацию.** Упавшие элементы не превращают весь ответ в ошибку — это позволяет обработать частичный результат. Перед использованием результата проверяйте `data.results[i].success` для каждого элемента, а сводку смотрите в `data.summary`. **Пакетный `update` не дополняет `type`, `ownerId` и `name` из существующей секции.** В отличие от одиночного [`PATCH /v1/calendar-sections/:id`](./update.md), который подставляет эти поля сам, в пакете их нужно передать в каждом элементе `items`. Без них элемент завершается ошибкой, а остальные продолжают обрабатываться. ## Смотрите также - [Создать секцию](./create.md) - [Обновить секцию](./update.md) - [Удалить секцию](./delete.md) - [Секции календаря](/docs/entities/calendar-sections) - [Универсальный batch](/docs/batch) --- # Calendar Sections: Create ## Создать секцию `POST /v1/calendar-sections` Создаёт новую секцию календаря для сотрудника, группы или компании. Секция создаётся от имени сотрудника, чьи токены привязаны к API-ключу. Администратор портала может создавать секции для других сотрудников. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `type` | string | да | Тип календаря: `user`, `group` | | `ownerId` | number | да | Идентификатор владельца календаря. Для сотрудника — `GET /v1/users`, для рабочей группы — её id | | `name` | string | да | Название секции | | `description` | string | нет | Описание | | `color` | string | нет | Цвет секции в формате `#RRGGBB` | | `textColor` | string | нет | Цвет текста в формате `#RRGGBB` | | `export` | object | нет | Параметры экспорта в формате iCal: `{ "ALLOW": boolean, "SET": "all" \| "3_9" \| "6_12" }`. Ключи внутри объекта — в верхнем регистре. `SET` задаёт период экспорта: `all` — за всё время, `3_9` — 3 месяца назад и 9 вперёд, `6_12` — 6 месяцев назад и 12 вперёд | Поля только на чтение — `id`, `access`, `perm`, `isCollab`, `createdBy`, `dateCreate`, `updatedAt` — в теле запроса передавать нельзя, API Вайбкод вернёт `400 READONLY_FIELD`. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/calendar-sections" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "type": "user", "ownerId": 1, "name": "Командные встречи", "description": "Календарь для регулярных созвонов", "color": "#9cbeee", "textColor": "#283000", "export": { "ALLOW": true, "SET": "3_9" } }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/calendar-sections" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "type": "user", "ownerId": 1, "name": "Командные встречи", "description": "Календарь для регулярных созвонов", "color": "#9cbeee", "textColor": "#283000", "export": { "ALLOW": true, "SET": "3_9" } }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calendar-sections', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ type: 'user', ownerId: 1, name: 'Командные встречи', description: 'Календарь для регулярных созвонов', color: '#9cbeee', textColor: '#283000', export: { ALLOW: true, SET: '3_9', }, }), }) const { success, data } = await res.json() console.log('Идентификатор секции:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calendar-sections', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ type: 'user', ownerId: 1, name: 'Командные встречи', description: 'Календарь для регулярных созвонов', color: '#9cbeee', textColor: '#283000', export: { ALLOW: true, SET: '3_9', }, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Идентификатор созданной секции — единственное поле в ответе на создание | Чтобы получить остальные поля созданной секции, например `color`, `access` и `perm`, запросите [`GET /v1/calendar-sections?type=<...>&ownerId=<...>`](./list.md) и найдите запись по `id`. ## Пример ответа ```json { "success": true, "data": { "id": 99 } } ``` ## Пример ответа при ошибке 400 — передано поле только на чтение: ```json { "success": false, "error": { "code": "READONLY_FIELD", "message": "Field 'access' is read-only and cannot be set" } } ``` 422 — пропущено обязательное поле: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Недопустимое значение параметра \"name\"" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Пропущено обязательное поле `type`, `ownerId` или `name`, либо некорректное значение поля | | 400 | `READONLY_FIELD` | В теле запроса передано поле только на чтение — `id`, `access`, `perm`, `isCollab`, `createdBy`, `dateCreate`, `updatedAt` | | 400 | `EMPTY_CREATE_BODY` | Тело запроса пустое — передайте хотя бы одно поле | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `calendar` | | 403 | `WRITE_BLOCKED_READONLY_KEY` | API-ключ в режиме «только чтение» — запись запрещена | | 401 | `TOKEN_MISSING` | У API-ключа нет настроенных токенов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 временно недоступен — повторите запрос позже | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Ответ на создание содержит только `id`.** Остальные поля новой секции, включая присвоенные `access` и `perm`, в ответе не приходят — чтобы получить их, сделайте отдельный запрос к [`GET /v1/calendar-sections`](./list.md). **Поле `export` сохраняет регистр.** Передавайте именно `{ "ALLOW": true, "SET": "3_9" }` — ключи в верхнем регистре, API Вайбкод не преобразует их к camelCase. В нижнем регистре ключи `export` не применяются. ## Смотрите также - [Список секций](./list.md) - [Обновить секцию](./update.md) - [Удалить секцию](./delete.md) - [Пакет операций](./batch.md) - [События календаря](/docs/entities/calendar-events) --- # Calendar Sections: Delete ## Удалить секцию `DELETE /v1/calendar-sections/:id` Удаляет секцию календаря по идентификатору. Восстановить удалённую секцию через API нельзя — повторите [`POST /v1/calendar-sections`](./create.md), если потребуется снова. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор секции | | `type` (query или body) | string | да | Тип календаря: `user`, `group`. Секцию нельзя найти по одному `id` — нужна пара `type` + `ownerId` | | `ownerId` (query или body) | number | да | Идентификатор владельца календаря | Параметры `type` и `ownerId` принимаются и в строке запроса, и в теле — если переданы оба, **приоритет у строки запроса**. Если параметр опущен и там, и там — API Вайбкод возвращает `400 MISSING_REQUIRED_PARAMS` до обращения к Битрикс24. ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/calendar-sections/42?type=user&ownerId=1" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/calendar-sections/42?type=user&ownerId=1" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const params = new URLSearchParams({ type: 'user', ownerId: '1' }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/calendar-sections/42?${params}`, { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Секция удалена') } ``` ### JavaScript — OAuth-приложение ```javascript const params = new URLSearchParams({ type: 'user', ownerId: '1' }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/calendar-sections/42?${params}`, { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом. Признак успеха — код ответа, не содержимое. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 400 — пропущены `type` и `ownerId`: ```json { "success": false, "error": { "code": "MISSING_REQUIRED_PARAMS", "message": "DELETE /v1/calendar-sections/:id requires type, ownerId (query or body). Example: DELETE /v1/calendar-sections/:id?type=...&ownerId=...", "missing": ["type", "ownerId"] } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_PARAMS` | Не переданы `type` или `ownerId` — ни в строке запроса, ни в теле. Поле `missing` в ответе перечисляет конкретные пропущенные ключи | | 422 | `BITRIX_ERROR` | Секция с указанным `id` не существует, уже удалена или недоступна | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `calendar` | | 403 | `WRITE_BLOCKED_READONLY_KEY` | API-ключ в режиме «только чтение» — запись запрещена | | 401 | `TOKEN_MISSING` | У API-ключа нет настроенных токенов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 временно недоступен — повторите запрос позже | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Подтверждения нет.** Запрос выполняется без интерактивного подтверждения и без отмены — операция необратима. Перед удалением убедитесь, что секция вам больше не нужна. Если в ней остались нужные события, заранее перенесите их в другую секцию через [`PATCH /v1/calendar-events/:id`](/docs/entities/calendar-events/update) с новым `sectionId`. **Приоритет строки запроса над телом.** Если `type` и `ownerId` переданы и в `?type=...&ownerId=...`, и в JSON-теле — берутся значения из строки запроса. Тело используется только как запасной источник, когда параметров в строке нет. ## Смотрите также - [Список секций](./list.md) - [Пакет операций](./batch.md) - [События календаря](/docs/entities/calendar-events) --- # Calendar Sections: List ## Список секций `GET /v1/calendar-sections` Возвращает все секции календаря для пары `type` + `ownerId`. У одного сотрудника может быть несколько секций — например, «Работа», «Личное», «Командные встречи». ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `type` (query) | string | да | — | Тип календаря: `user` — личный, `group` — групповой, `company_calendar` — календарь компании, `location` — переговорная | | `ownerId` (query) | number | да | — | Идентификатор владельца календаря. Для сотрудника — `GET /v1/users`, для рабочей группы — её id, для `type=location` — `0` | | `limit` (query) | number | нет | `50` | Количество записей, до 5000. При `limit > 50` включается автопагинация | | `offset` (query) | number | нет | `0` | Принимается, но не влияет на выборку — список возвращает все секции пары `type` + `ownerId` | Фильтрация через `filter[...]` не поддерживается. Любой ключ `filter[name]=...` возвращает `400 UNSUPPORTED_FILTER` ещё до обращения к Битрикс24. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/calendar-sections?type=user&ownerId=1" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/calendar-sections?type=user&ownerId=1" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const params = new URLSearchParams({ type: 'user', ownerId: '1' }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/calendar-sections?${params}`, { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} секций`) ``` ### JavaScript — OAuth-приложение ```javascript const params = new URLSearchParams({ type: 'user', ownerId: '1' }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/calendar-sections?${params}`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив секций | | `meta.total` | number | Общее количество секций в выборке | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | Поля одной секции в массиве `data`: | Поле | Тип | RO | Описание | |------|-----|:--:|---------| | `id` | number | да | Идентификатор секции | | `name` | string | нет | Название | | `description` | string | нет | Описание | | `type` | string | нет | Тип календаря: `user`, `group`, `company_calendar`, `location` | | `ownerId` | number | нет | Идентификатор владельца календаря | | `color` | string | нет | Цвет секции в формате `#RRGGBB` | | `textColor` | string | нет | Цвет текста в формате `#RRGGBB` | | `export` | object | нет | Параметры экспорта в формате iCal: `{ "ALLOW": boolean, "SET": "all" \| "3_9" \| "6_12" }`. Ключи внутри объекта — в верхнем регистре, формат сохраняется на запись и чтение без преобразований | | `access` | object | да | Карта прав доступа: ключ — идентификатор права доступа, значение — числовой идентификатор разрешения | | `perm` | object | да | Карта разрешений текущего сотрудника: `view_time`, `view_title`, `view_full`, `add`, `edit`, `edit_section`, `access` | | `isCollab` | boolean | да | Принадлежность к коллабе | | `createdBy` | number | да | Идентификатор создателя секции | | `dateCreate` | datetime | да | Дата создания | | `updatedAt` | datetime | да | Дата последнего изменения | «RO» — поле доступно только на чтение, передавать в `POST` / `PATCH` нельзя, иначе Вайбкод вернёт `400 READONLY_FIELD`. ## Пример ответа ```json { "success": true, "data": [ { "id": 42, "name": "Работа", "description": "Основной рабочий календарь", "type": "user", "ownerId": 1, "color": "#9cbeee", "textColor": "#283000", "export": { "ALLOW": true, "SET": "3_9" }, "access": { "U1": "calendar_owner", "G2": 13 }, "perm": { "view_time": true, "view_title": true, "view_full": true, "add": true, "edit": true, "edit_section": true, "access": true }, "isCollab": false, "createdBy": 1, "dateCreate": "2026-05-15T09:34:33+03:00", "updatedAt": "2026-05-15T09:34:33+03:00" } ], "meta": { "total": 1, "hasMore": false } } ``` ## Пример ответа при ошибке 400 — не переданы обязательные `type` или `ownerId`: ```json { "success": false, "error": { "code": "MISSING_REQUIRED_PARAMS", "message": "GET /v1/calendar-sections requires query parameters: type, ownerId. Example: GET /v1/calendar-sections?type=...&ownerId=..." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_PARAMS` | Не переданы `type` или `ownerId` | | 400 | `UNSUPPORTED_FILTER` | Передан ключ `filter[...]` — фильтрация не поддерживается. Допустимы только `type`, `ownerId`, `limit`, `offset` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `calendar` | | 401 | `TOKEN_MISSING` | У API-ключа нет настроенных токенов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 временно недоступен — повторите запрос позже | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`limit` обрезает выдачу на стороне API Вайбкод, `offset` не действует.** Список всегда возвращает все секции указанной пары `type` + `ownerId`. `limit` обрезает полученный массив до N записей, а `offset` принимается, но игнорируется — пропустить записи через него нельзя. **Поле `export` сохраняет регистр Битрикс24.** Ключи внутри `export` остаются `ALLOW` и `SET` в верхнем регистре — не преобразуются к camelCase. То же при отправке через [`POST /v1/calendar-sections`](./create.md): передавайте именно `{ "ALLOW": true, "SET": "3_9" }`. **Получить секцию по одному `id` через API нельзя.** Эндпоинт `GET /v1/calendar-sections/:id` не поддерживается. Чтобы найти одну секцию по `id` — получите список и отфильтруйте на стороне клиента: `data.find(s => s.id === 42)`. ## Смотрите также - [Создать секцию](./create.md) - [Обновить секцию](./update.md) - [Удалить секцию](./delete.md) - [Пакет операций](./batch.md) - [События календаря](/docs/entities/calendar-events) --- # Calendar Sections: Update ## Обновить секцию `PATCH /v1/calendar-sections/:id` Обновляет поля существующей секции. `type`, `ownerId` и `name` обязательны в каждом вызове — даже если меняется только цвет или описание. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор секции | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `type` | string | да | Тип календаря: `user`, `group`. Должен соответствовать `type` существующей секции — иначе вернётся ошибка доступа | | `ownerId` | number | да | Идентификатор владельца календаря. Должен соответствовать `ownerId` существующей секции | | `name` | string | да | Название секции. Требуется даже при изменении других полей — передавайте текущее значение, если переименование не нужно | | `description` | string | нет | Описание | | `color` | string | нет | Цвет секции в формате `#RRGGBB` | | `textColor` | string | нет | Цвет текста в формате `#RRGGBB` | | `export` | object | нет | Параметры экспорта в формате iCal: `{ "ALLOW": boolean, "SET": "all" \| "3_9" \| "6_12" }`. Ключи внутри объекта — в верхнем регистре | Поля только на чтение — `id`, `access`, `perm`, `isCollab`, `createdBy`, `dateCreate`, `updatedAt` — в теле запроса передавать нельзя. ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/calendar-sections/42" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "type": "user", "ownerId": 1, "name": "Командные встречи", "color": "#FF5733", "description": "Обновлённое описание" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/calendar-sections/42" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "type": "user", "ownerId": 1, "name": "Командные встречи", "color": "#FF5733", "description": "Обновлённое описание" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calendar-sections/42', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ type: 'user', ownerId: 1, name: 'Командные встречи', color: '#FF5733', description: 'Обновлённое описание', }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calendar-sections/42', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ type: 'user', ownerId: 1, name: 'Командные встречи', color: '#FF5733', description: 'Обновлённое описание', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Идентификатор обновлённой секции — единственное поле в ответе на обновление | Чтобы получить актуальные значения остальных полей — запросите [`GET /v1/calendar-sections?type=<...>&ownerId=<...>`](./list.md). ## Пример ответа ```json { "success": true, "data": { "id": 42 } } ``` ## Пример ответа при ошибке 400 — пропущен обязательный якорь `type`, `ownerId` или `name`, проверяется до обращения к Битрикс24: ```json { "success": false, "error": { "code": "MISSING_REQUIRED_PARAMS", "message": "PATCH /v1/calendar-sections/{id} requires: name. Example: PATCH /v1/calendar-sections/{id} { \"name\": ..., ... }" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_PARAMS` | Пропущено обязательное поле `type`, `ownerId` или `name` — проверяется до обращения к Битрикс24 | | 422 | `BITRIX_ERROR` | Некорректное значение поля, например недопустимый `type` | | 400 | `READONLY_FIELD` | В теле запроса передано поле только на чтение | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `calendar` | | 403 | `WRITE_BLOCKED_READONLY_KEY` | API-ключ в режиме «только чтение» — запись запрещена | | 401 | `TOKEN_MISSING` | У API-ключа нет настроенных токенов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 временно недоступен — повторите запрос позже | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`type`, `ownerId`, `name` обязательны в каждом вызове.** Частичное обновление секции не поддерживается — три поля-якоря нужны, даже если меняется только цвет. Если переименование не нужно, передайте текущее `name` — его можно получить через [`GET /v1/calendar-sections`](./list.md). **Несуществующий `id` возвращает `200` без изменений.** Обновление секции, которой нет, не приводит к ошибке — приходит `{ "success": true, "data": { "id": } }`, но ничего не меняется. Прежде чем полагаться на результат, убедитесь, что секция есть в [`GET /v1/calendar-sections`](./list.md). **Ответ на обновление содержит только `id`.** Чтобы увидеть обновлённую секцию полностью, сделайте отдельный запрос к [`GET /v1/calendar-sections`](./list.md). ## Смотрите также - [Список секций](./list.md) - [Создать секцию](./create.md) - [Удалить секцию](./delete.md) - [Пакет операций](./batch.md) --- # Catalog Prices: Create ## Создать цену `POST /v1/catalog-prices` Создаёт цену товара. Поля передаются плоско в корне JSON. У одного товара может быть по одной цене на каждый тип цены (`catalogGroupId`). ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `productId` | number | да | ID товара, к которому относится цена. Список: `GET /v1/catalog-products?filter[iblockId]=` (значение `iblockId` — из `GET /v1/catalogs`) | | `catalogGroupId` | number | да | Тип цены. Базовая цена — `1`. Какие типы заведены на портале, видно по значениям `catalogGroupId` в [списке цен](/docs/entities/catalog-prices/list) | | `price` | number | да | Значение цены | | `currency` | string | да | Валюта цены, например `RUB`. Список: `GET /v1/currencies` | | `quantityFrom` | number | нет | Нижняя граница количественного диапазона | | `quantityTo` | number | нет | Верхняя граница количественного диапазона | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/catalog-prices" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "productId": 104, "catalogGroupId": 1, "price": 1500, "currency": "RUB" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/catalog-prices" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "productId": 104, "catalogGroupId": 1, "price": 1500, "currency": "RUB" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-prices', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ productId: 104, catalogGroupId: 1, price: 1500, currency: 'RUB', }), }) const { success, data } = await res.json() console.log('Price ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-prices', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ productId: 104, catalogGroupId: 1, price: 1500, currency: 'RUB', }), }) const { success, data } = await res.json() ``` ## Поля ответа Возвращается полный объект созданной цены. | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор созданной цены | | `productId` | number | ID товара | | `catalogGroupId` | number | Тип цены | | `price` | number | Значение цены | | `currency` | string | Валюта цены | | `quantityFrom` | number \| null | Нижняя граница количественного диапазона | | `quantityTo` | number \| null | Верхняя граница количественного диапазона | | `priceScale` | number | Цена в базовой валюте портала. При создании равна `price` | | `extraId` | number \| null | Идентификатор наценки (`catalog_extra`). Устаревшее поле Битрикс24 | | `timestampX` | string | Дата изменения (ISO 8601 с указанием часового пояса) | ## Пример ответа ```json { "success": true, "data": { "catalogGroupId": 1, "currency": "RUB", "extraId": null, "id": 5104, "price": 1500, "priceScale": 1500, "productId": 104, "quantityFrom": null, "quantityTo": null, "timestampX": "2026-06-08T14:58:52+03:00" } } ``` ## Пример ответа при ошибке 422 — не передано обязательное поле: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Required fields: currency" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 422 | `BITRIX_ERROR` | Не передано обязательное поле — сообщение перечисляет недостающие (`Required fields: <имя>`) | | 400 | `READONLY_FIELD` | В теле передан `id` — это поле заполняется системой и не принимается при создании | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `catalog` | | 401 | `TOKEN_MISSING` | Не передан `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список цен](/docs/entities/catalog-prices/list) - [Получить цену](/docs/entities/catalog-prices/get) - [Обновить цену](/docs/entities/catalog-prices/update) - [Удалить цену](/docs/entities/catalog-prices/delete) - [Товары каталога](/docs/entities/catalog-products) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Catalog Prices: Delete ## Удалить цену `DELETE /v1/catalog-prices/:id` Удаляет цену по идентификатору. Восстановить удалённую цену через API нельзя — при необходимости создайте новую. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор цены | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/catalog-prices/5104" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/catalog-prices/5104" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-prices/5104', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Цена удалена') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-prices/5104', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Цена удалена') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — успех проверяется по статусу. ## Пример ответа ```http HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 422 — цена с указанным `id` не существует: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "price does not exist." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 422 | `BITRIX_ERROR` | Цена с указанным `id` не существует (`price does not exist.`) | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `catalog` | | 401 | `TOKEN_MISSING` | Не передан `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать цену](/docs/entities/catalog-prices/create) - [Список цен](/docs/entities/catalog-prices/list) - [Получить цену](/docs/entities/catalog-prices/get) - [Обновить цену](/docs/entities/catalog-prices/update) - [Товары каталога](/docs/entities/catalog-products) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Catalog Prices: Fields ## Поля цены `GET /v1/catalog-prices/fields` Возвращает справочник полей цены товара с типами, признаками «только для чтения» и «допускает `null`», а также список операций, доступных в пакетном запросе. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-prices/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-prices/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-prices/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data.fields).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-prices/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа `data.fields` — объект, ключ которого совпадает с именем поля, а значение содержит `type` (тип поля), `readonly` (`true` — поле нельзя передать при создании и обновлении), `nullable` (присутствует, если поле может прийти со значением `null`), `label` (отображаемое название поля) и `description` (краткое описание). Значения `label`/`description` приходят на русском языке. `data.batch` — список операций, которые принимает [пакетный запрос](/docs/batch). | Поле | Тип | RO | Описание | |------|-----|:--:|---------| | `id` | number | да | Идентификатор записи цены | | `catalogGroupId` | number | нет | Тип цены. Базовая цена — `1`. Какие типы заведены на портале, видно по значениям `catalogGroupId` в [списке цен](./list.md) | | `currency` | string | нет | Валюта цены, например `RUB`. Список: [`GET /v1/currencies`](/docs/entities/currencies) | | `price` | number | нет | Значение цены | | `productId` | number | нет | ID товара, к которому относится цена. Список: [`GET /v1/catalog-products`](/docs/entities/catalog-products) | | `quantityFrom` | number \| null | нет | Нижняя граница количественного диапазона. В ответах `null`, если цена не зависит от количества | | `quantityTo` | number \| null | нет | Верхняя граница количественного диапазона. В ответах `null`, если цена не зависит от количества | | `priceScale` | number | да | Цена в базовой валюте портала. Заполняется системой | | `extraId` | number \| null | да | Идентификатор наценки (`catalog_extra`). Устаревшее поле Битрикс24. Заполняется системой. `null`, если наценка не задана | | `timestampX` | datetime | да | Дата и время последнего изменения записи цены в формате ISO 8601 (UTC) | | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.fields.<имя>.type` | string | Тип поля: `number`, `string`, `datetime` | | `data.fields.<имя>.readonly` | boolean | `true` — поле заполняется системой и не принимается при создании и обновлении | | `data.fields.<имя>.nullable` | boolean | `true` — поле может прийти со значением `null`. Ключ присутствует только у таких полей | | `data.fields.<имя>.label` | string | Отображаемое название поля на русском языке | | `data.fields.<имя>.description` | string | Краткое описание поля | | `data.batch` | string[] | Операции цены, доступные в [пакетном запросе](/docs/batch): `create`, `update`, `delete` | ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "ID", "description": "Идентификатор записи цены каталога." }, "catalogGroupId": { "type": "number", "readonly": false, "label": "Тип цены", "description": "Идентификатор типа цены; базовая цена — 1." }, "currency": { "type": "string", "readonly": false, "label": "Валюта", "description": "Код валюты цены." }, "price": { "type": "number", "readonly": false, "label": "Цена", "description": "Числовое значение цены." }, "productId": { "type": "number", "readonly": false, "label": "Товар", "description": "ID товара, к которому относится цена." }, "quantityFrom": { "type": "number", "readonly": false, "nullable": true, "label": "Количество от", "description": "Нижняя граница диапазона количества." }, "quantityTo": { "type": "number", "readonly": false, "nullable": true, "label": "Количество до", "description": "Верхняя граница диапазона количества." }, "priceScale": { "type": "number", "readonly": true, "label": "Базовая цена", "description": "Цена в базовой валюте портала." }, "extraId": { "type": "number", "readonly": true, "nullable": true, "label": "Идентификатор наценки", "description": "Идентификатор наценки (catalog_extra)." }, "timestampX": { "type": "datetime", "readonly": true, "label": "Дата изменения", "description": "Дата и время последнего изменения цены." } }, "batch": ["create", "update", "delete"] } } ``` Системные поля `priceScale`, `extraId` и `timestampX` заполняются Битрикс24 и доступны только для чтения — передать их при создании или обновлении нельзя. ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'catalog' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `TOKEN_MISSING` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список цен](/docs/entities/catalog-prices/list) - [Создать цену](/docs/entities/catalog-prices/create) - [Поиск цен](/docs/entities/catalog-prices/search) - [Товары каталога](/docs/entities/catalog-products) - [Справочник сущностей](/docs/entities-index) --- # Catalog Prices: Get ## Получить цену `GET /v1/catalog-prices/:id` Возвращает одну запись цены товара по идентификатору. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор записи цены | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-prices/5001" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-prices/5001" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-prices/5001', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Цена:', data.price, data.currency) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-prices/5001', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Идентификатор записи цены | | `data.catalogGroupId` | number | Тип цены. Базовая цена — `1` | | `data.currency` | string | Валюта цены, например `RUB` | | `data.price` | number | Значение цены | | `data.productId` | number | Идентификатор товара, к которому относится цена | | `data.quantityFrom` | number \| null | Нижняя граница количественного диапазона. `null`, если цена не зависит от количества | | `data.quantityTo` | number \| null | Верхняя граница количественного диапазона. `null`, если цена не зависит от количества | | `data.extraId` | number \| null | Идентификатор наценки (`catalog_extra`). Устаревшее поле Битрикс24 | | `data.priceScale` | number | Цена в базовой валюте портала | | `data.timestampX` | string | Дата последнего изменения (ISO 8601) | ## Пример ответа ```json { "success": true, "data": { "catalogGroupId": 2, "currency": "RUB", "extraId": null, "id": 5001, "price": 50, "priceScale": 50, "productId": 101, "quantityFrom": null, "quantityTo": null, "timestampX": "2024-06-17T16:53:24+03:00" } } ``` ## Пример ответа при ошибке 422 — записи с таким `id` нет: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "price does not exist." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Записи цены с указанным `id` не существует | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `TOKEN_MISSING` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать цену](/docs/entities/catalog-prices/create) - [Обновить цену](/docs/entities/catalog-prices/update) - [Удалить цену](/docs/entities/catalog-prices/delete) - [Список цен](/docs/entities/catalog-prices/list) - [Товары каталога](/docs/entities/catalog-products) - [Справочник сущностей](/docs/entities-index) --- # Catalog Prices: List ## Список цен `GET /v1/catalog-prices` Возвращает список цен товаров с поддержкой фильтрации, сортировки, выборки полей и пагинации. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям записи цены.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[productId]=101` | | `select` | string | — | Выборка полей: `?select=id,productId,price`. Возвращаются только перечисленные поля | | `sort` | string | — | Поле сортировки. Префикс `-` — по убыванию: `?sort=-price` | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Смещение от начала выборки | Для `limit > 50` ответ автоматически собирается из нескольких страниц на стороне сервера. Максимум — 5000 записей за вызов. Если под фильтр попадает больше записей, чем возвращено, в `meta.hasMore` придёт `true`. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-prices" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-prices" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-prices', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Цен: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-prices', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив цен | | `data[].id` | number | Идентификатор записи цены | | `data[].catalogGroupId` | number | Тип цены. Базовая цена — `1` | | `data[].currency` | string | Валюта цены, например `RUB` | | `data[].price` | number | Значение цены | | `data[].productId` | number | Идентификатор товара, к которому относится цена | | `data[].quantityFrom` | number \| null | Нижняя граница количественного диапазона. `null`, если цена не зависит от количества | | `data[].quantityTo` | number \| null | Верхняя граница количественного диапазона. `null`, если цена не зависит от количества | | `data[].extraId` | number \| null | Идентификатор наценки (`catalog_extra`). Устаревшее поле Битрикс24 | | `data[].priceScale` | number | Цена в базовой валюте портала | | `data[].timestampX` | string | Дата последнего изменения (ISO 8601) | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | ## Пример ответа ```json { "success": true, "data": [ { "catalogGroupId": 2, "currency": "RUB", "extraId": null, "id": 5001, "price": 50, "priceScale": 50, "productId": 101, "quantityFrom": null, "quantityTo": null, "timestampX": "2024-06-17T16:53:24+03:00" }, { "catalogGroupId": 1, "currency": "RUB", "extraId": null, "id": 5002, "price": 10, "priceScale": 10, "productId": 102, "quantityFrom": null, "quantityTo": null, "timestampX": "2021-09-27T16:32:20+03:00" }, { "catalogGroupId": 1, "currency": "RUB", "extraId": null, "id": 5003, "price": 32999, "priceScale": 32999, "productId": 103, "quantityFrom": null, "quantityTo": null, "timestampX": "2025-01-10T14:49:59+03:00" } ], "meta": { "total": 85, "hasMore": true } } ``` ## Пример ответа при ошибке 400 — фильтр по несуществующему полю: ```json { "success": false, "error": { "code": "UNKNOWN_FILTER_FIELD", "message": "Unknown filter field 'bogusField' for entity 'catalog-prices'. Available: id, catalogGroupId, currency, price, productId, quantityFrom, quantityTo" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет у записи цены. Сообщение содержит список доступных полей | | 400 | `UNKNOWN_SORT_FIELD` | Сортировка по полю, которого нет у записи цены. Сообщение содержит список доступных полей | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `TOKEN_MISSING` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Поля `extraId`, `priceScale` и `timestampX` недоступны для фильтра и сортировки.** Они приходят в ответе, но в `filter` или `sort` отвечают ошибкой. Какие поля доступны — на странице [Цены каталога](/docs/entities/catalog-prices). ## Смотрите также - [Создать цену](/docs/entities/catalog-prices/create) - [Получить цену](/docs/entities/catalog-prices/get) - [Обновить цену](/docs/entities/catalog-prices/update) - [Удалить цену](/docs/entities/catalog-prices/delete) - [Товары каталога](/docs/entities/catalog-products) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entities-index) --- # Catalog Prices: Search ## Поиск цен `POST /v1/catalog-prices/search` Поиск цен товаров по условиям, переданным в теле запроса. В отличие от [`GET /v1/catalog-prices`](./list.md), параметры `filter`, `select`, `sort`, `limit` и `offset` передаются в JSON-теле, а не в строке адреса — это удобнее для условий по нескольким полям. Формат ответа тот же, что у списка. ## Поля запроса (body) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям записи цены.
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "catalogGroupId": 1 }` | | `select` | string[] | — | Выборка полей: `["id", "productId", "price"]`. Возвращаются только перечисленные поля | | `sort` | string | — | Поле сортировки. Префикс `-` — по убыванию: `"-price"` | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Смещение от начала выборки. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки» | | `autoWindow` | boolean | `true` | Разбивать выборку по недельным окнам при фильтре по диапазону дат шире 14 дней. `false` отключает разбиение | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/catalog-prices/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "catalogGroupId": 1 }, "limit": 2 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/catalog-prices/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "catalogGroupId": 1 }, "limit": 2 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-prices/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { catalogGroupId: 1 }, limit: 2, }), }) const { success, data, meta } = await res.json() console.log(`Найдено: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-prices/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { catalogGroupId: 1 }, limit: 2, }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив цен | | `data[].id` | number | Идентификатор записи цены | | `data[].catalogGroupId` | number | Тип цены. Базовая цена — `1` | | `data[].currency` | string | Валюта цены, например `RUB` | | `data[].price` | number | Значение цены | | `data[].productId` | number | Идентификатор товара, к которому относится цена | | `data[].quantityFrom` | number \| null | Нижняя граница количественного диапазона. `null`, если цена не зависит от количества | | `data[].quantityTo` | number \| null | Верхняя граница количественного диапазона. `null`, если цена не зависит от количества | | `data[].extraId` | number \| null | Идентификатор наценки (`catalog_extra`). Устаревшее поле Битрикс24 | | `data[].priceScale` | number | Цена в базовой валюте портала | | `data[].timestampX` | string | Дата последнего изменения (ISO 8601) | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временны́м окнам | | `meta.windowCount` | number | Число окон. Приходит при `autoWindowed: true` | | `meta.batchWaves` | number | Число волн параллельных запросов. Приходит при `autoWindowed: true` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа ```json { "success": true, "data": [ { "catalogGroupId": 1, "currency": "RUB", "extraId": null, "id": 5002, "price": 10, "priceScale": 10, "productId": 102, "quantityFrom": null, "quantityTo": null, "timestampX": "2021-09-27T16:32:20+03:00" }, { "catalogGroupId": 1, "currency": "RUB", "extraId": null, "id": 5003, "price": 32999, "priceScale": 32999, "productId": 103, "quantityFrom": null, "quantityTo": null, "timestampX": "2025-01-10T14:49:59+03:00" } ], "meta": { "total": 22, "hasMore": true, "durationMs": 487 } } ``` С фильтром по диапазону дат шире 14 дней в `meta` дополнительно приходят `autoWindowed`, `windowCount` и `batchWaves`: ```json { "success": true, "data": [ /* ... */ ], "meta": { "total": 19, "hasMore": true, "autoWindowed": true, "windowCount": 131, "batchWaves": 3, "durationMs": 1092 } } ``` ## Пример ответа при ошибке 400 — фильтр по несуществующему полю: ```json { "success": false, "error": { "code": "UNKNOWN_FILTER_FIELD", "message": "Unknown filter field 'bogus' for entity 'catalog-prices'. Available: id, catalogGroupId, currency, price, productId, quantityFrom, quantityTo" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет у записи цены. Сообщение содержит список доступных полей | | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `TOKEN_MISSING` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Разбиение по временны́м окнам.** Фильтр по диапазону дат шире 14 дней автоматически разбивается на недельные окна, которые выполняются параллельными волнами — так выборка обходит потолок в 5000 записей на один вызов. В `meta` тогда приходят `autoWindowed: true`, число окон `windowCount` и число волн `batchWaves`. Отключает разбиение параметр `autoWindow: false`. При активном разбиении `offset` больше нуля отклоняется с `UNSTABLE_OFFSET_PAGINATION`. ## Смотрите также - [Список цен](/docs/entities/catalog-prices/list) - [Создать цену](/docs/entities/catalog-prices/create) - [Получить цену](/docs/entities/catalog-prices/get) - [Поля цены](/docs/entities/catalog-prices/fields) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entities-index) --- # Catalog Prices: Update ## Обновить цену `PATCH /v1/catalog-prices/:id` Изменяет существующую цену. Поля передаются плоско в корне JSON. Передавайте только изменяемые поля — остальные сохраняют текущие значения. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор цены | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `productId` | number | нет | ID товара, к которому относится цена. Список: `GET /v1/catalog-products?filter[iblockId]=` (значение `iblockId` — из `GET /v1/catalogs`) | | `catalogGroupId` | number | нет | Тип цены. Базовая цена — `1`. Какие типы заведены на портале, видно по значениям `catalogGroupId` в [списке цен](/docs/entities/catalog-prices/list) | | `price` | number | нет | Значение цены | | `currency` | string | нет | Валюта цены, например `RUB`. Список: `GET /v1/currencies` | | `quantityFrom` | number | нет | Нижняя граница количественного диапазона | | `quantityTo` | number | нет | Верхняя граница количественного диапазона | `id` передаётся в пути (`/v1/catalog-prices/:id`), в теле его передавать нельзя — он только для чтения. ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/catalog-prices/5104" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "price": 1750 }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/catalog-prices/5104" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "price": 1750 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-prices/5104', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ price: 1750, }), }) const { success, data } = await res.json() console.log('Новая цена:', data.price) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-prices/5104', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ price: 1750, }), }) const { success, data } = await res.json() ``` ## Поля ответа Возвращается полный обновлённый объект цены. | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор цены | | `productId` | number | ID товара | | `catalogGroupId` | number | Тип цены | | `price` | number | Значение цены | | `currency` | string | Валюта цены | | `quantityFrom` | number \| null | Нижняя граница количественного диапазона | | `quantityTo` | number \| null | Верхняя граница количественного диапазона | | `priceScale` | number | Цена в базовой валюте портала | | `extraId` | number \| null | Идентификатор наценки (`catalog_extra`). Устаревшее поле Битрикс24 | | `timestampX` | string | Дата изменения (ISO 8601 с указанием часового пояса) | ## Пример ответа ```json { "success": true, "data": { "catalogGroupId": 1, "currency": "RUB", "extraId": null, "id": 5104, "price": 1750, "priceScale": 1500, "productId": 104, "quantityFrom": null, "quantityTo": null, "timestampX": "2026-06-08T14:59:07+03:00" } } ``` ## Пример ответа при ошибке 422 — цена с указанным `id` не существует: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Price is not exists" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 422 | `BITRIX_ERROR` | Цена с указанным `id` не существует (`Price is not exists`) | | 400 | `READONLY_FIELD` | В теле передан `id` — это поле заполняется системой и не принимается при обновлении | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `catalog` | | 401 | `TOKEN_MISSING` | Не передан `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`priceScale` не пересчитывается при изменении `price`.** При создании `priceScale` совпадает с `price`. Если обновить только `price`, в ответе `priceScale` сохранит прежнее значение. ## Смотрите также - [Создать цену](/docs/entities/catalog-prices/create) - [Список цен](/docs/entities/catalog-prices/list) - [Получить цену](/docs/entities/catalog-prices/get) - [Удалить цену](/docs/entities/catalog-prices/delete) - [Товары каталога](/docs/entities/catalog-products) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Catalog Product Properties: Create ## Создать свойство товара `POST /v1/catalog-product-properties` Создаёт свойство товара в каталоге. Поля передаются плоско в корне JSON. В ответ приходит полный объект созданного свойства. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `iblockId` | number | да | ID каталога. Список: `GET /v1/catalogs` | | `name` | string | да | Название свойства для отображения | | `propertyType` | string | да | Базовый тип. `N` число, `S` строка, `L` список, `F` файл, `E` привязка к элементу, `G` привязка к разделу | | `code` | string | нет | Символьный код. Латинские буквы, цифры, подчёркивание. Первый символ не цифра | | `active` | boolean | нет | Активно ли свойство. По умолчанию `true` | | `sort` | number | нет | Индекс сортировки | | `defaultValue` | string | нет | Значение по умолчанию | | `userType` | string | нет | Пользовательский тип, например `directory`, `DateTime`, `Money`, `HTML` | | `userTypeSettings` | object | нет | Настройки пользовательского типа | | `listType` | string | нет | Вид списка. `L` выпадающий, `C` флажки | | `multiple` | boolean | нет | Множественное значение | | `multipleCnt` | number | нет | Число полей ввода для множественных значений | | `withDescription` | boolean | нет | Поле описания значения | | `searchable` | boolean | нет | Участвует в поиске | | `filtrable` | boolean | нет | Участвует в фильтре | | `isRequired` | boolean | нет | Обязательное к заполнению | | `linkIblockId` | number | нет | ID связанного каталога для типов привязки | | `fileType` | string | нет | Допустимые расширения файлов для типа `F` | | `xmlId` | string | нет | Внешний идентификатор | | `hint` | string | нет | Подсказка к полю | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/catalog-product-properties" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "iblockId": 19, "name": "Материал", "propertyType": "S" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/catalog-product-properties" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "iblockId": 19, "name": "Материал", "propertyType": "S" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-product-properties', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ iblockId: 19, name: 'Материал', propertyType: 'S', }), }) const { success, data } = await res.json() console.log('Property ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-product-properties', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ iblockId: 19, name: 'Материал', propertyType: 'S', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Полный объект созданного свойства. Набор полей — как у [`GET /v1/catalog-product-properties/:id`](./get.md) | Идентификатор созданного свойства `id` совпадает с `NNN` в ключе `propertyNNN`, которым значение этого свойства приходит у товара в [Товары каталога](/docs/entities/catalog-products): ``` propertyNNN → property659 ``` `NNN` — значение поля `id`. По нему строится сопоставление `id → name` для подписи значений `propertyNNN`. ## Пример ответа Показаны основные поля. ```json { "success": true, "data": { "id": 659, "iblockId": 19, "name": "Материал", "propertyType": "S", "code": "s12", "active": true, "sort": null, "defaultValue": null, "userType": "directory", "userTypeSettings": { "group": "N", "multiple": "N", "size": 1, "tableName": "b_hlbd_categories", "width": 0 }, "listType": "L", "multiple": false, "multipleCnt": null, "withDescription": null, "searchable": false, "filtrable": false, "isRequired": false, "linkIblockId": null, "fileType": null, "xmlId": null, "hint": null, "timestampX": "2026-03-19T18:23:02.000Z" } } ``` ## Пример ответа при ошибке 422 — не передано обязательное поле: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Required fields: name" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 422 | `BITRIX_ERROR` | Не передано обязательное поле — сообщение перечисляет недостающие (`Required fields: name`, `Required fields: propertyType`) | | 422 | `BITRIX_ERROR` | Каталог с указанным `iblockId` не найден (`Iblock Not Found`) | | 400 | `READONLY_FIELD` | В теле передано поле только для чтения, например `id` или `timestampX` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список свойств товаров](/docs/entities/catalog-product-properties/list) - [Получить свойство товара](/docs/entities/catalog-product-properties/get) - [Обновить свойство товара](/docs/entities/catalog-product-properties/update) - [Удалить свойство товара](/docs/entities/catalog-product-properties/delete) - [Товары каталога](/docs/entities/catalog-products) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Catalog Product Properties: Delete ## Удалить свойство `DELETE /v1/catalog-product-properties/:id` Удаляет определение свойства по идентификатору. Свойство пропадает из каталога вместе со значениями этого свойства у товаров. Восстановить удалённое свойство через API нельзя — при необходимости создайте новое. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор свойства | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/catalog-product-properties/659" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/catalog-product-properties/659" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-product-properties/659', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Свойство удалено') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-product-properties/659', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Свойство удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — успех проверяется по статусу. ## Пример ответа ```http HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 422 — свойства с указанным `id` не существует: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "property does not exist." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 422 | `BITRIX_ERROR` | Свойства с указанным `id` не существует (`property does not exist.`) | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать свойство](/docs/entities/catalog-product-properties/create) - [Список свойств](/docs/entities/catalog-product-properties/list) - [Получить свойство](/docs/entities/catalog-product-properties/get) - [Обновить свойство](/docs/entities/catalog-product-properties/update) - [Товары каталога](/docs/entities/catalog-products) - [Каталоги](/docs/entities/catalogs) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Catalog Product Properties: Fields ## Поля свойства `GET /v1/catalog-product-properties/fields` Возвращает справочник полей свойства товара с типами и признаком «только для чтения», а также операции, доступные в пакетном запросе. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-product-properties/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-product-properties/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-product-properties/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data.fields).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-product-properties/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа `data.fields` — объект, ключ которого совпадает с именем поля, а значение содержит `type` (тип поля) и `readonly` (`true` — поле нельзя передать при создании и обновлении). `data.batch` — операции, доступные в [пакетном запросе](/docs/batch). | Поле | Тип | RO | Описание | |------|-----|:--:|---------| | `id` | number | да | Идентификатор свойства. Это `NNN` в ключе `propertyNNN` у [товара каталога](/docs/entities/catalog-products) | | `iblockId` | number | нет¹ | ID каталога. Список: [`GET /v1/catalogs`](/docs/entities/catalogs). Обязателен при создании | | `name` | string | нет | Название свойства для отображения. Обязательно при создании | | `propertyType` | string | нет² | Базовый тип: `N` число, `S` строка, `L` список, `F` файл, `E` привязка к элементу, `G` привязка к разделу. Обязателен при создании | | `code` | string | нет | Символьный код: латинские буквы, цифры, подчёркивание, первый символ не цифра | | `active` | boolean | нет | Активно ли свойство | | `sort` | number | нет | Индекс сортировки | | `defaultValue` | string | нет | Значение по умолчанию | | `userType` | string | нет² | Пользовательский тип, например `directory`, `DateTime`, `Money`, `HTML` | | `userTypeSettings` | object | нет | Настройки пользовательского типа | | `listType` | string | нет | Вид списка: `L` выпадающий, `C` флажки | | `multiple` | boolean | нет | Множественное значение | | `multipleCnt` | number | нет | Число полей ввода для множественных значений | | `rowCount` | number | нет | Число строк поля ввода | | `colCount` | number | нет | Число столбцов поля ввода | | `withDescription` | boolean | нет | Поле с описанием значения | | `searchable` | boolean | нет | Участвует в поиске | | `filtrable` | boolean | нет | Доступно для фильтра | | `isRequired` | boolean | нет | Обязательно для заполнения | | `linkIblockId` | number | нет | ID связанного каталога для типов привязки | | `fileType` | string | нет | Допустимые расширения файлов для типа `F` | | `xmlId` | string | нет | Внешний идентификатор | | `hint` | string | нет | Подсказка к полю | | `timestampX` | datetime | да | Дата последнего изменения | ¹ `iblockId` доступен для записи только при создании (`createOnly`) — в справочнике приходит с `readonly: false` и `createOnly: true`. ² `propertyType` и `userType` доступны для записи только при создании (`createOnly`) — в справочнике приходят с `readonly: false` и `createOnly: true`, в `PATCH` отклоняются с `READONLY_FIELD`. | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.fields.<имя>.type` | string | Тип поля: `number`, `string`, `boolean`, `object`, `datetime` | | `data.fields.<имя>.readonly` | boolean | `true` — поле заполняется системой и не принимается при создании и обновлении | | `data.fields.<имя>.createOnly` | boolean | `true` — поле принимается только при создании, в `PATCH` отклоняется с `READONLY_FIELD` (есть у `iblockId`, `propertyType`, `userType`) | | `data.batch` | string[] | Операции свойства, доступные в [пакетном запросе](/docs/batch): `create`, `update`, `delete` | ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true }, "iblockId": { "type": "number", "readonly": false, "createOnly": true }, "name": { "type": "string", "readonly": false }, "propertyType": { "type": "string", "readonly": false, "createOnly": true }, "code": { "type": "string", "readonly": false }, "active": { "type": "boolean", "readonly": false }, "sort": { "type": "number", "readonly": false }, "defaultValue": { "type": "string", "readonly": false }, "userType": { "type": "string", "readonly": false, "createOnly": true }, "userTypeSettings": { "type": "object", "readonly": false }, "listType": { "type": "string", "readonly": false }, "multiple": { "type": "boolean", "readonly": false }, "multipleCnt": { "type": "number", "readonly": false }, "rowCount": { "type": "number", "readonly": false }, "colCount": { "type": "number", "readonly": false }, "withDescription": { "type": "boolean", "readonly": false }, "searchable": { "type": "boolean", "readonly": false }, "filtrable": { "type": "boolean", "readonly": false }, "isRequired": { "type": "boolean", "readonly": false }, "linkIblockId": { "type": "number", "readonly": false }, "fileType": { "type": "string", "readonly": false }, "xmlId": { "type": "string", "readonly": false }, "hint": { "type": "string", "readonly": false }, "timestampX": { "type": "datetime", "readonly": true } }, "batch": ["create", "update", "delete"] } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'catalog' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Тип свойства неизменяем.** `propertyType` и `userType` выбираются при создании. `PATCH` с любым из них отклоняется с `400 READONLY_FIELD` — базовый тип уже созданного свойства не меняется. **Свойство привязано к каталогу (`iblockId`).** Каталог выбирается при создании, смена через обновление не поддерживается. `PATCH` со сменой `iblockId` отклоняется с `400 READONLY_FIELD`. **Связь с полями товара.** Свойства списочного типа (`L`) возвращаются у [товара каталога](/docs/entities/catalog-products) в полях вида `propertyNNN`, где `NNN` — `id` свойства. Этот справочник переводит `id` в название и тип, чтобы построить карту `id → название` и подписать значения `propertyNNN`. **Настройки пользовательского типа.** Поле `userTypeSettings` — объект, состав которого зависит от значения `userType`. При создании и обновлении передаётся целиком. ## Смотрите также - [Список свойств](/docs/entities/catalog-product-properties/list) - [Создать свойство](/docs/entities/catalog-product-properties/create) - [Поиск свойств](/docs/entities/catalog-product-properties/search) - [Товары каталога](/docs/entities/catalog-products) - [Справочник сущностей](/docs/entities-index) --- # Catalog Product Properties: Get ## Получить свойство `GET /v1/catalog-product-properties/:id` Возвращает одно свойство товаров каталога по идентификатору. Ответ содержит полный набор полей: кроме `id`, `name` и `propertyType` приходят символьный код, настройки списка, настройки пользовательского типа и привязки. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор свойства | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-product-properties/659" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-product-properties/659" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-product-properties/659', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Свойство:', data.name) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-product-properties/659', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект свойства. Базовый набор полей — см. [Поля свойства](./fields.md) | Дополнительно к полям справочника одна запись содержит: - `code` — символьный код - `sort` — порядок сортировки - `propertyType` — базовый тип значения - `listType` — внешний вид списка - `multiple` — признак множественного значения - `userType` — пользовательский тип - `userTypeSettings` — настройки пользовательского типа - `linkIblockId` — идентификатор привязанного каталога Поля с пустым значением приходят как `null`. ## Пример ответа Показаны основные поля. ```json { "success": true, "data": { "id": 659, "iblockId": 19, "name": "Рубрика", "active": true, "code": "s12", "propertyType": "S", "listType": "L", "multiple": false, "multipleCnt": null, "rowCount": 1, "colCount": 30, "isRequired": false, "searchable": false, "filtrable": false, "withDescription": null, "defaultValue": null, "linkIblockId": null, "fileType": null, "sort": null, "userType": "directory", "userTypeSettings": { "group": "N", "multiple": "N", "size": 1, "tableName": "b_hlbd_categories", "width": 0 }, "hint": null, "xmlId": null, "timestampX": "2026-03-19T18:23:02.000Z" } } ``` ## Пример ответа при ошибке 404 — свойства с таким `id` нет: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "catalog product property not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Свойства с указанным `id` не существует | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать свойство](/docs/entities/catalog-product-properties/create) - [Обновить свойство](/docs/entities/catalog-product-properties/update) - [Удалить свойство](/docs/entities/catalog-product-properties/delete) - [Список свойств](/docs/entities/catalog-product-properties/list) - [Поля свойства](/docs/entities/catalog-product-properties/fields) - [Товары каталога](/docs/entities/catalog-products) - [Справочник сущностей](/docs/entities-index) --- # Catalog Product Properties: List ## Список свойств `GET /v1/catalog-product-properties` Возвращает список свойств товаров каталога с поддержкой фильтрации, сортировки, выборки полей и пагинации. Фильтр `filter[iblockId]` ограничивает выборку одним каталогом. ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `filter` | object | нет | — | Условия фильтрации. Ключ `filter[iblockId]` ограничивает выборку одним каталогом — ID каталога из [`GET /v1/catalogs`](/docs/entities/catalogs).
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[iblockId]=19&filter[active]=true` | | `select` | string | нет | — | Выборка полей: `?select=id,name,propertyType`. Без `select` возвращаются все поля свойства | | `sort` | string | нет | — | Поле сортировки. Префикс `-` — по убыванию: `?sort=-id` | | `limit` | number | нет | `50` | Количество записей (до 5000) | | `offset` | number | нет | `0` | Смещение от начала выборки | Для `limit > 50` ответ автоматически собирается из нескольких страниц на стороне сервера. Максимум — 5000 записей за вызов. Если под фильтр попадает больше записей, чем возвращено, в `meta.hasMore` придёт `true`. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-product-properties?filter[iblockId]=19&limit=10" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-product-properties?filter[iblockId]=19&limit=10" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const params = new URLSearchParams({ 'filter[iblockId]': '19', limit: '10' }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/catalog-product-properties?${params}`, { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Свойств: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const params = new URLSearchParams({ 'filter[iblockId]': '19', limit: '10' }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/catalog-product-properties?${params}`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив свойств. Состав полей элемента — см. [Поля свойства](./fields.md) | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | Свойства типа `L` (список) у товара из [Товаров каталога](/docs/entities/catalog-products) приходят полями вида `propertyNNN`, где `NNN` — это `id` свойства. Эта выборка превращает `NNN` в название и тип. Построив отображение `id` → `name`, можно подписать значения полей `propertyNNN`: ``` propertyNNN → data[i].id === NNN → data[i].name, data[i].propertyType ``` Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 152, "iblockId": 19, "name": "Характеристики товара", "active": true, "code": "CHARS", "propertyType": "L", "listType": "L", "multiple": true, "sort": 500, "userType": null, "userTypeSettings": null, "isRequired": false, "searchable": false, "filtrable": false, "xmlId": null, "timestampX": "2026-03-19T18:23:02.000Z" }, { "id": 154, "iblockId": 19, "name": "Наименование по РУ", "active": true, "code": "NAME_RU", "propertyType": "S", "listType": null, "multiple": false, "sort": 510, "userType": null, "userTypeSettings": null, "isRequired": false, "searchable": false, "filtrable": false, "xmlId": null, "timestampX": "2026-03-19T18:23:02.000Z" } ], "meta": { "total": 2, "hasMore": false } } ``` ## Пример ответа при ошибке 422 — каталог из фильтра не найден: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Iblock Not Found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Каталог из `filter[iblockId]` не найден (`Iblock Not Found`) | | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет у свойства. Сообщение содержит список доступных полей | | 400 | `UNKNOWN_SORT_FIELD` | Сортировка по полю, которого нет у свойства. Сообщение содержит список доступных полей | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать свойство](/docs/entities/catalog-product-properties/create) - [Получить свойство](/docs/entities/catalog-product-properties/get) - [Поиск свойств](/docs/entities/catalog-product-properties/search) - [Поля свойства](/docs/entities/catalog-product-properties/fields) - [Товары каталога](/docs/entities/catalog-products) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entities-index) --- # Catalog Product Properties: Search ## Поиск свойств товаров `POST /v1/catalog-product-properties/search` Поиск определений свойств товаров каталога по условиям, переданным в теле запроса. В отличие от [`GET /v1/catalog-product-properties`](./list.md), параметры `filter`, `select`, `sort`, `limit` и `offset` передаются в JSON-теле, а не в строке адреса — это удобнее для условий по нескольким полям. Как и список, поиск принимает `filter.iblockId` для ограничения выборки одним каталогом. Формат ответа тот же, что у списка. ## Поля запроса (body) | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `filter` | object | нет | — | Условия фильтрации. Ключ `iblockId` ограничивает выборку одним каталогом — ID каталога из [`GET /v1/catalogs`](/docs/entities/catalogs).
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "iblockId": 19, "active": true }` | | `select` | string[] | нет | — | Выборка полей: `["id", "name", "propertyType"]`. Без `select` возвращаются все поля свойства | | `sort` | string | нет | — | Поле сортировки. Префикс `-` — по убыванию: `"-id"` | | `limit` | number | нет | `50` | Количество записей (до 5000) | | `offset` | number | нет | `0` | Смещение от начала выборки. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки» | | `autoWindow` | boolean | нет | `true` | Разбивать выборку по недельным окнам при фильтре по диапазону дат шире 14 дней. `false` отключает разбиение | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/catalog-product-properties/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "iblockId": 19, "active": true }, "limit": 3 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/catalog-product-properties/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "iblockId": 19, "active": true }, "limit": 3 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-product-properties/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { iblockId: 19, active: true }, limit: 3, }), }) const { success, data, meta } = await res.json() console.log(`Найдено: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-product-properties/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { iblockId: 19, active: true }, limit: 3, }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив определений свойств. Состав полей элемента — см. [Поля свойства](./fields.md) | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временны́м окнам | | `meta.windowCount` | number | Число окон. Приходит при `autoWindowed: true` | | `meta.batchWaves` | number | Число волн параллельных запросов. Приходит при `autoWindowed: true` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. Поле `id` каждого определения из массива `data` — это `NNN` в ключе `propertyNNN` у элементов [Товаров каталога](/docs/entities/catalog-products): ``` propertyNNN → свойство с id = NNN ``` По этому соответствию строится карта `id` → `name` для подписи значений `propertyNNN`. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 152, "iblockId": 19, "name": "Характеристики товара", "propertyType": "L", "code": "FEATURES", "active": true, "sort": 100, "defaultValue": null, "userType": null, "userTypeSettings": null, "listType": "L", "multiple": true, "multipleCnt": null, "rowCount": 1, "colCount": 30, "withDescription": null, "searchable": false, "filtrable": false, "isRequired": false, "linkIblockId": null, "fileType": null, "xmlId": null, "hint": null, "timestampX": "2026-03-19T18:23:02.000Z" }, { "id": 154, "iblockId": 19, "name": "Наименование по РУ", "propertyType": "S", "code": "NAME_RU", "active": true, "sort": 110, "defaultValue": null, "userType": null, "userTypeSettings": null, "listType": "L", "multiple": false, "multipleCnt": null, "rowCount": 1, "colCount": 30, "withDescription": null, "searchable": false, "filtrable": false, "isRequired": false, "linkIblockId": null, "fileType": null, "xmlId": null, "hint": null, "timestampX": "2026-03-19T18:23:02.000Z" } ], "meta": { "total": 12, "hasMore": false, "durationMs": 540 } } ``` С фильтром по диапазону дат шире 14 дней в `meta` дополнительно приходят `autoWindowed`, `windowCount` и `batchWaves`: ```json { "success": true, "data": [ /* ... */ ], "meta": { "total": 5, "hasMore": true, "autoWindowed": true, "windowCount": 131, "batchWaves": 3, "durationMs": 1131 } } ``` ## Пример ответа при ошибке 400 — фильтр по полю, которого нет у свойства: ```json { "success": false, "error": { "code": "UNKNOWN_FILTER_FIELD", "message": "Unknown filter field" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет у свойства. Сообщение содержит список доступных полей | | 400 | `UNKNOWN_SORT_FIELD` | Сортировка по полю, которого нет у свойства. Сообщение содержит список доступных полей | | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Разбиение по временны́м окнам.** Фильтр по диапазону дат шире 14 дней автоматически разбивается на недельные окна, которые выполняются параллельными волнами — так выборка обходит потолок в 5000 записей на один вызов. В `meta` тогда приходят `autoWindowed: true`, число окон `windowCount` и число волн `batchWaves`. Отключает разбиение параметр `autoWindow: false`. При активном разбиении `offset` больше нуля отклоняется с `UNSTABLE_OFFSET_PAGINATION`. ## Смотрите также - [Список свойств](/docs/entities/catalog-product-properties/list) - [Создать свойство](/docs/entities/catalog-product-properties/create) - [Получить свойство](/docs/entities/catalog-product-properties/get) - [Поля свойства](/docs/entities/catalog-product-properties/fields) - [Товары каталога](/docs/entities/catalog-products) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entities-index) --- # Catalog Product Properties: Update ## Обновить свойство `PATCH /v1/catalog-product-properties/:id` Изменяет существующее определение свойства. Поля передаются плоско в корне JSON. Передавайте только изменяемые поля — остальные сохраняют текущие значения. В ответ приходит перечитанное определение свойства. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор свойства | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `name` | string | нет | Название свойства для отображения | | `code` | string | нет | Символьный код. Латинские буквы, цифры и подчёркивание, первый символ не цифра | | `active` | boolean | нет | Активно ли свойство | | `sort` | number | нет | Индекс сортировки | | `defaultValue` | string | нет | Значение по умолчанию | | `userTypeSettings` | object | нет | Настройки пользовательского типа | | `listType` | string | нет | Вид списка: `L` выпадающий, `C` флажки | | `multiple` | boolean | нет | Множественное значение | | `multipleCnt` | number | нет | Число полей ввода для множественного значения | | `rowCount` | number | нет | Число строк поля ввода | | `colCount` | number | нет | Число столбцов поля ввода | | `withDescription` | boolean | нет | Поле описания значения | | `searchable` | boolean | нет | Участвует в поиске | | `filtrable` | boolean | нет | Участвует в фильтре | | `isRequired` | boolean | нет | Обязательное к заполнению | | `linkIblockId` | number | нет | ID связанного каталога для типов привязки | | `fileType` | string | нет | Допустимые расширения файлов для типа `F` | | `xmlId` | string | нет | Внешний идентификатор | | `hint` | string | нет | Подсказка к полю | `id` передаётся в пути, в теле его передавать нельзя — он только для чтения. Поля `iblockId`, `propertyType` и `userType` задаются только при создании: `PATCH` с любым из них отклоняется с `400 READONLY_FIELD`. Поле `timestampX` заполняется системой. ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/catalog-product-properties/659" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Рубрика товара" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/catalog-product-properties/659" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Рубрика товара" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-product-properties/659', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Рубрика товара', }), }) const { success, data } = await res.json() console.log('Новое название:', data.name) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-product-properties/659', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Рубрика товара', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Перечитанное определение свойства. Набор полей — как у [`GET /v1/catalog-product-properties/:id`](./get.md) | ## Пример ответа Показаны основные поля. ```json { "success": true, "data": { "id": 659, "iblockId": 19, "name": "Рубрика товара", "propertyType": "S", "code": "s12", "active": true, "sort": null, "defaultValue": null, "userType": "directory", "userTypeSettings": { "group": "N", "multiple": "N", "size": 1, "tableName": "b_hlbd_categories", "width": 0 }, "listType": "L", "multiple": false, "multipleCnt": null, "rowCount": 1, "colCount": 30, "withDescription": null, "searchable": false, "filtrable": false, "isRequired": false, "linkIblockId": null, "fileType": null, "xmlId": null, "hint": null, "timestampX": "2026-03-19T18:23:02.000Z" } } ``` ## Пример ответа при ошибке 422 — свойства с указанным `id` не существует: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "property does not exist." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 422 | `BITRIX_ERROR` | Свойства с указанным `id` не существует (`property does not exist.`) | | 400 | `READONLY_FIELD` | В теле передано поле только для чтения, например `id` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать свойство](/docs/entities/catalog-product-properties/create) - [Список свойств](/docs/entities/catalog-product-properties/list) - [Получить свойство](/docs/entities/catalog-product-properties/get) - [Удалить свойство](/docs/entities/catalog-product-properties/delete) - [Товары каталога](/docs/entities/catalog-products) - [Каталоги](/docs/entities/catalogs) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Catalog Product Property Enums: Fields ## Поля значения `GET /v1/catalog-product-property-enums/fields` Возвращает справочник полей элемента перечисления с типами и признаком «только для чтения», а также операции, доступные в пакетном запросе. Ответ собирается из статической схемы сущности — обращения к Битрикс24 не происходит. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-product-property-enums/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-product-property-enums/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-product-property-enums/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data.fields).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-product-property-enums/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа `data.fields` — объект, ключ которого совпадает с именем поля, а значение содержит `type` (тип поля), `readonly` и человекочитаемые `label` и `description`. `data.batch` перечисляет **записывающие** операции, доступные в [пакетном запросе](/docs/batch); у этой сущности он пустой, потому что записи нет вовсе. Чтения в батче это не отменяет: подвызовы `list` и `get` через [`POST /v1/batch`](/docs/batch) и `POST /v1/catalog-product-property-enums/batch` работают. Подвызов `fields` в батче тоже принимается, но у этой сущности отвечает `200` с **пустым объектом** — обращения к Битрикс24 не происходит, и справочник полей так не получить. Берите его одиночным `GET /v1/catalog-product-property-enums/fields`. | Поле | Тип | RO | Описание | |------|-----|:--:|---------| | `id` | number | да | Идентификатор элемента перечисления. Именно он приходит у [товара каталога](/docs/entities/catalog-products) в `propertyNNN.value` | | `propertyId` | number | да | ID свойства-владельца. Обязателен в фильтре списка и поиска | | `value` | string | да | Читаемый текст варианта — тот же, что приходит у товара в `propertyNNN.valueEnum` | | `def` | boolean | да | Является ли вариант значением свойства по умолчанию | | `sort` | number | да | Индекс сортировки внутри свойства | | `xmlId` | string | да | Внешний код. Приходит `null`, если не задан | | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.fields.<имя>.type` | string | Тип поля: `number`, `string`, `boolean` | | `data.fields.<имя>.readonly` | boolean | У этой сущности `true` у всех полей | | `data.fields.<имя>.label` | string | Человекочитаемое название поля | | `data.fields.<имя>.description` | string | Пояснение к полю | | `data.batch` | string[] | Записывающие операции, доступные в [пакетном запросе](/docs/batch). У этой сущности — пустой массив; подвызовы чтения при этом работают | ## Пример ответа Поля `label` и `description` показаны только у первого поля, у остальных опущены для краткости. ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "ID", "description": "Идентификатор элемента перечисления. Именно он приходит в поле propertyNNN.value у товара каталога." }, "propertyId": { "type": "number", "readonly": true }, "value": { "type": "string", "readonly": true }, "def": { "type": "boolean", "readonly": true }, "sort": { "type": "number", "readonly": true }, "xmlId": { "type": "string", "readonly": true, "nullable": true } }, "batch": [] } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'catalog' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Сущность только для чтения.** Варианты списка заводятся в интерфейсе Битрикс24. `POST`, `PATCH`, `DELETE` и `POST /aggregate` не зарегистрированы и отвечают `404`, а `data.batch` приходит пустым массивом. Читающие подвызовы в [пакетном запросе](/docs/batch) при этом доступны. **Перечисление есть только у свойств типа `L`.** У свойства любого другого типа (`S`, `N`, `F`, `E`, `G`) список вариантов пуст. Тип свойства читается из [`GET /v1/catalog-product-properties/:id`](/docs/entities/catalog-product-properties/get) в поле `propertyType`. **Связь с полями товара.** Значение списочного свойства приходит у [товара каталога](/docs/entities/catalog-products) в поле `propertyNNN`, где `NNN` — `id` свойства. Внутри — `value` (это `id` элемента перечисления, строкой), `valueEnum` (готовый текст) и `valueId` (id строки значения). Сопоставление делается по `String(элемент.id) === товар.propertyNNN.value`. ## Смотрите также - [Список значений](/docs/entities/catalog-product-property-enums/list) - [Получить значение](/docs/entities/catalog-product-property-enums/get) - [Поиск значений](/docs/entities/catalog-product-property-enums/search) - [Свойства товаров каталога](/docs/entities/catalog-product-properties) - [Товары каталога](/docs/entities/catalog-products) - [Справочник сущностей](/docs/entities-index) --- # Catalog Product Property Enums: Get ## Получить значение `GET /v1/catalog-product-property-enums/:id` Возвращает один вариант списочного свойства по идентификатору элемента перечисления. Это тот же `id`, что приходит у товара каталога в `propertyNNN.value`. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор элемента перечисления | Фильтр по `propertyId` здесь не нужен: элемент адресуется своим собственным идентификатором. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-product-property-enums/116" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-product-property-enums/116" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-product-property-enums/116', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Значение:', data.value) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-product-property-enums/116', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект варианта. Состав полей — см. [Поля значения](./fields.md) | Поле `xmlId` приходит `null`, если внешний код не задан. Один вариант читается точечно, когда его `id` уже известен — например, взят из `propertyNNN.value` товара. Чтобы получить **все** варианты свойства, нужен [список](./list.md) с `filter[propertyId]`. ## Пример ответа ```json { "success": true, "data": { "id": 116, "propertyId": 166, "value": "L", "def": false, "sort": 400, "xmlId": null } } ``` ## Пример ответа при ошибке 404 — элемента с таким `id` нет: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "catalogProductPropertyEnum 116 not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Элемента перечисления с указанным `id` не существует | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список значений](/docs/entities/catalog-product-property-enums/list) - [Поиск значений](/docs/entities/catalog-product-property-enums/search) - [Поля значения](/docs/entities/catalog-product-property-enums/fields) - [Свойства товаров каталога](/docs/entities/catalog-product-properties) - [Товары каталога](/docs/entities/catalog-products) - [Справочник сущностей](/docs/entities-index) --- # Catalog Product Property Enums: List ## Список значений `GET /v1/catalog-product-property-enums` Возвращает варианты одного списочного свойства торгового каталога. Фильтр `filter[propertyId]` обязателен — справочник читается по одному свойству за раз. ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `filter[propertyId]` | number | **да** | — | ID свойства-владельца из [`GET /v1/catalog-product-properties`](/docs/entities/catalog-product-properties/list). Без него запрос отклоняется с `400 MISSING_REQUIRED_FILTER` до обращения к Битрикс24 | | `filter` | object | нет | — | Остальные условия фильтрации.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[propertyId]=166&filter[def]=true` | | `select` | string | нет | — | Выборка полей: `?select=id,value`. Без `select` возвращаются все поля элемента | | `sort` | string | нет | — | Поле сортировки. Префикс `-` — по убыванию: `?sort=-sort` | | `limit` | number | нет | `50` | Количество записей (до 5000) | | `offset` | number | нет | `0` | Смещение от начала выборки | Для `limit > 50` ответ автоматически собирается из нескольких страниц на стороне сервера. Максимум — 5000 записей за вызов. **Конец выборки определяется по `meta.hasMore`.** Битрикс24 сообщает общее количество, поэтому `meta.total` и `meta.hasMore` достоверны — обычный цикл `while (hasMore) { offset += limit }` работает. Редкий крайний случай: если общее количество не придёт, платформа подставит в `meta.total` длину полученного окна, и на полной странице `hasMore` окажется `false`; подстраховка — сверить `data.length` с размером страницы. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-product-property-enums?filter[propertyId]=166&limit=1000" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-product-property-enums?filter[propertyId]=166&limit=1000" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const params = new URLSearchParams({ 'filter[propertyId]': '166', limit: '1000' }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/catalog-product-property-enums?${params}`, { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() const byId = new Map(data.map(item => [String(item.id), item.value])) console.log(byId.get('116')) // L ``` ### JavaScript — OAuth-приложение ```javascript const params = new URLSearchParams({ 'filter[propertyId]': '166', limit: '1000' }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/catalog-product-property-enums?${params}`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив вариантов. Состав полей элемента — см. [Поля значения](./fields.md) | | `meta.total` | number | Количество записей, соответствующих фильтру. Если Битрикс24 не сообщил его, приходит длина окна | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit`. На границе окна ненадёжен — см. предупреждение выше | Поле `id` каждого элемента — это то, что приходит у товара каталога в `propertyNNN.value`: ``` товар.propertyNNN.value → String(элемент.id) → элемент.value ``` Свойство не списочного типа (`propertyType` не равен `L`) перечисления не имеет: запрос вернёт `200` с пустым `data`, а не ошибку. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 110, "propertyId": 166, "value": "XS", "def": false, "sort": 100, "xmlId": null }, { "id": 112, "propertyId": 166, "value": "S", "def": false, "sort": 200, "xmlId": null }, { "id": 114, "propertyId": 166, "value": "M", "def": false, "sort": 300, "xmlId": null }, { "id": 116, "propertyId": 166, "value": "L", "def": false, "sort": 400, "xmlId": null }, { "id": 118, "propertyId": 166, "value": "XL", "def": false, "sort": 500, "xmlId": null } ], "meta": { "total": 5, "hasMore": false } } ``` ## Пример ответа при ошибке 400 — не передан обязательный фильтр: ```json { "success": false, "error": { "code": "MISSING_REQUIRED_FILTER", "message": "GET /v1/catalog-product-property-enums requires filter fields: propertyId. Example: GET /v1/catalog-product-property-enums?filter[propertyId]=..." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_FILTER` | В запросе нет ключа `filter[propertyId]`. Обращения к Битрикс24 не происходит | | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет у элемента перечисления. Сообщение содержит список доступных полей | | 400 | `UNKNOWN_SORT_FIELD` | Сортировка по полю, которого нет у элемента перечисления. Сообщение содержит список доступных полей | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Справочники нескольких свойств забираются одним пакетным запросом** — до 50 подвызовов, по одному на `propertyId`: ```json { "calls": [ { "id": "sizes", "entity": "catalog-product-property-enums", "action": "list", "params": { "filter": { "propertyId": 166 }, "limit": 1000 } }, { "id": "colors", "entity": "catalog-product-property-enums", "action": "list", "params": { "filter": { "propertyId": 162 }, "limit": 1000 } } ] } ``` Подвызов `list` с `limit` больше 50 выходит из нативного пакета Битрикс24 и выполняется отдельным последовательным запросом со своей единицей rate-limit — см. [Пакетные запросы](/docs/batch). То есть пакетный вызов экономит обращения к API Вайбкод, но не единицы квоты Битрикс24. Явный `limit` при этом обязателен — см. предупреждение о полноте выдачи выше. Передать данные между подвызовами одного батча нельзя, поэтому `propertyId` нужно знать заранее — из [`GET /v1/catalog-product-properties`](/docs/entities/catalog-product-properties/list). Проверка обязательного фильтра на подвызовы батча не распространяется: за состав `params` в каждом подвызове отвечает вызывающий. Сам Битрикс24 этот фильтр обязательным не считает — подвызов без `propertyId` вернёт значения всех списочных свойств всех торговых каталогов сразу, то есть ответ, размер которого ничем не ограничен. ## Смотрите также - [Получить значение](/docs/entities/catalog-product-property-enums/get) - [Поиск значений](/docs/entities/catalog-product-property-enums/search) - [Поля значения](/docs/entities/catalog-product-property-enums/fields) - [Свойства товаров каталога](/docs/entities/catalog-product-properties) - [Товары каталога](/docs/entities/catalog-products) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entities-index) --- # Catalog Product Property Enums: Search ## Поиск значений `POST /v1/catalog-product-property-enums/search` Поиск вариантов списочного свойства по условиям, переданным в теле запроса. В отличие от [`GET /v1/catalog-product-property-enums`](./list.md), параметры `filter`, `select`, `sort`, `limit` и `offset` передаются в JSON-теле, а не в строке адреса — это удобнее для условий по нескольким полям. Требование к фильтру то же: ключ `propertyId` обязателен. Формат ответа совпадает со списком. ## Поля запроса (body) | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `filter.propertyId` | number | **да** | — | ID свойства-владельца из [`GET /v1/catalog-product-properties`](/docs/entities/catalog-product-properties/list). Без него запрос отклоняется с `400 MISSING_REQUIRED_FILTER` до обращения к Битрикс24 | | `filter` | object | нет | — | Остальные условия фильтрации.
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "propertyId": 166, "def": true }` | | `select` | string[] | нет | — | Выборка полей: `["id", "value"]`. Без `select` возвращаются все поля элемента | | `sort` | string | нет | — | Поле сортировки. Префикс `-` — по убыванию: `"-sort"` | | `limit` | number | нет | `50` | Количество записей (до 5000) | | `offset` | number | нет | `0` | Смещение от начала выборки | Как и в списке, конец выборки определяется по `meta.hasMore` — Битрикс24 сообщает общее количество, так что `meta.total` и `meta.hasMore` достоверны. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/catalog-product-property-enums/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "propertyId": 166 }, "sort": "sort", "limit": 1000 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/catalog-product-property-enums/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "propertyId": 166 }, "sort": "sort", "limit": 1000 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-product-property-enums/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { propertyId: 166 }, sort: 'sort', limit: 1000, }), }) const { success, data, meta } = await res.json() console.log(`Вариантов: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-product-property-enums/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { propertyId: 166 }, sort: 'sort', limit: 1000, }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив вариантов. Состав полей элемента — см. [Поля значения](./fields.md) | | `meta.total` | number | Сколько записей подошло под фильтр. Если Битрикс24 не сообщил его, приходит длина окна | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit`. На границе окна ненадёжен — см. предупреждение выше | | `meta.durationMs` | number | Длительность запроса в миллисекундах | Поля `meta` лежат рядом с `data`, а не внутри него. Свойство не списочного типа (`propertyType` не равен `L`) перечисления не имеет: запрос вернёт `200` с пустым `data`, а не ошибку. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 110, "propertyId": 166, "value": "XS", "def": false, "sort": 100, "xmlId": null }, { "id": 112, "propertyId": 166, "value": "S", "def": false, "sort": 200, "xmlId": null }, { "id": 114, "propertyId": 166, "value": "M", "def": false, "sort": 300, "xmlId": null }, { "id": 116, "propertyId": 166, "value": "L", "def": false, "sort": 400, "xmlId": null }, { "id": 118, "propertyId": 166, "value": "XL", "def": false, "sort": 500, "xmlId": null } ], "meta": { "total": 5, "hasMore": false, "durationMs": 148 } } ``` ## Пример ответа при ошибке 400 — не передан обязательный фильтр: ```json { "success": false, "error": { "code": "MISSING_REQUIRED_FILTER", "message": "POST /v1/catalog-product-property-enums/search requires filter fields: propertyId. Example body: { \"filter\": {\"propertyId\":\"...\"} }" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_FILTER` | В теле нет ключа `filter.propertyId`. Обращения к Битрикс24 не происходит | | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет у элемента перечисления. Сообщение содержит список доступных полей | | 400 | `UNKNOWN_SORT_FIELD` | Сортировка по полю, которого нет у элемента перечисления. Сообщение содержит список доступных полей | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список значений](/docs/entities/catalog-product-property-enums/list) - [Получить значение](/docs/entities/catalog-product-property-enums/get) - [Поля значения](/docs/entities/catalog-product-property-enums/fields) - [Свойства товаров каталога](/docs/entities/catalog-product-properties) - [Товары каталога](/docs/entities/catalog-products) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entities-index) --- # Catalog Products: Aggregate ## Агрегация товаров `POST /v1/catalog-products/aggregate` Подсчёт количества и числовые агрегации (сумма, среднее, минимум, максимум) по товарам каталога с фильтрацией и группировкой через `groupBy`. **Поля, доступные для агрегации:** - `purchasingPrice` - `quantity` - `iblockSectionId` ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `filter` | object | да | Фильтрация по полям товара. Ключ `iblockId` обязателен — каталог из [`GET /v1/catalogs`](/docs/entities/catalogs).
[Синтаксис фильтрации](/docs/filtering) | | `aggregate` | array | нет | Агрегации: `[{ "field": "purchasingPrice", "function": "sum" }]`. Функции: `sum`, `avg`, `min`, `max`, `count`. Для `count` поле — `"*"`. Без параметра — только `count` | | `groupBy` | string \| string[] | нет | Поле или массив полей для группировки (до 5). Значения — из списка выше | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/catalog-products/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "iblockId": 25 }, "aggregate": [ { "field": "purchasingPrice", "function": "sum" }, { "field": "purchasingPrice", "function": "avg" } ], "groupBy": "iblockSectionId" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/catalog-products/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "iblockId": 25 }, "aggregate": [ { "field": "purchasingPrice", "function": "sum" }, { "field": "purchasingPrice", "function": "avg" } ], "groupBy": "iblockSectionId" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-products/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { iblockId: 25 }, aggregate: [ { field: 'purchasingPrice', function: 'sum' }, { field: 'purchasingPrice', function: 'avg' }, ], groupBy: 'iblockSectionId', }), }) const { success, data } = await res.json() console.log(data.groups) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-products/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { iblockId: 25 }, aggregate: [ { field: 'purchasingPrice', function: 'sum' }, { field: 'purchasingPrice', function: 'avg' }, ], groupBy: 'iblockSectionId', }), }) const { success, data } = await res.json() ``` Для группировки по нескольким полям передайте массив: `"groupBy": ["iblockSectionId", "quantity"]` (максимум 5 полей). ## Другие сценарии Подсчёт записей — `count` с полем `"*"`, самый быстрый запрос без выгрузки записей. Для каталога обязателен фильтр `iblockId`: ```json { "aggregate": [{ "field": "*", "function": "count" }], "filter": { "iblockId": 25 } } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Общее количество товаров, соответствующих фильтру | | `data.aggregates` | object | Результаты агрегаций: `{ "purchasingPrice": { "sum": 0, "avg": 0 } }` | | `data.groups` | array | Группы — присутствуют только при `groupBy`. Каждый элемент: поля группировки + `count` + `aggregates` | | `data.meta.totalRecords` | number | Общее количество записей | | `data.meta.recordsProcessed` | number | Количество обработанных записей (до 5000). Для запроса без числовых функций — `0` | | `data.meta.truncated` | boolean | `true`, если записей больше 5000 — агрегация по первым 5000 | | `data.meta.groupTotal` | number | Количество групп. Присутствует только при `groupBy` | | `data.meta.groupsTruncated` | boolean | `true`, если число групп было ограничено. Присутствует только при `groupBy` | ## Пример ответа ```json { "success": true, "data": { "count": 19, "aggregates": { "purchasingPrice": { "sum": 22120, "avg": 3686.67 } }, "groups": [ { "iblockSectionId": 19, "count": 2, "aggregates": { "purchasingPrice": { "sum": 0, "avg": 0 } } }, { "iblockSectionId": null, "count": 15, "aggregates": { "purchasingPrice": { "sum": 120, "avg": 60 } } }, { "iblockSectionId": 85, "count": 2, "aggregates": { "purchasingPrice": { "sum": 22000, "avg": 11000 } } } ], "meta": { "totalRecords": 19, "recordsProcessed": 19, "truncated": false, "groupTotal": 3, "groupsTruncated": false } } } ``` Без `groupBy` поле `data.groups` в ответе отсутствует. ## Пример ответа при ошибке 400 — поле вне списка доступных для агрегации: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "groupBy field 'nonexistent' is not aggregatable on this entity. Available: purchasingPrice, quantity, iblockSectionId." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_FILTER` | Не передан обязательный фильтр `filter[iblockId]` — проверяется до вызова Битрикс24 (пример тела в сообщении) | | 400 | `INVALID_PARAMS` | Поле `groupBy` вне списка доступных — сообщение перечисляет допустимые | | 400 | `INVALID_PARAMS` | Числовая функция по неизвестному полю — `Field '<имя>' not found. Available numeric fields: ...` | | 400 | `INVALID_PARAMS` | Передано более 5 полей в `groupBy` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`count` обходится одним запросом, числовые функции — нет.** `count` подсчитывается за один вызов независимо от объёма выборки. Функции `sum`, `avg`, `min`, `max` загружают записи постранично — до 5000 — и считают значения на стороне сервера. Если под фильтр попадает больше 5000 записей, `meta.truncated` равен `true`, а агрегаты и группы строятся по первым 5000. **Поля для группировки и для расчёта.** В `groupBy` имеет смысл передавать `iblockSectionId` — раздел каталога. По числовым полям `purchasingPrice` и `quantity` считают `sum`, `avg`, `min`, `max`. ## Смотрите также - [Список товаров](/docs/entities/catalog-products/list) - [Поиск товаров](/docs/entities/catalog-products/search) - [Поля товара](/docs/entities/catalog-products/fields) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Catalog Products: Create ## Создать товар `POST /v1/catalog-products` Создаёт товар в каталоге. Поля передаются плоско в корне JSON. В ответ приходит полный объект созданного товара. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `name` | string | да | Название товара | | `iblockId` | number | да | ID каталога. Список: `GET /v1/catalogs` | | `active` | boolean | нет | Активен ли товар. По умолчанию `true` | | `iblockSectionId` | number | нет | ID раздела каталога. Список: `GET /v1/catalog-sections` | | `measure` | number | нет | ID единицы измерения | | `weight` | number | нет | Вес единицы товара | | `vatIncluded` | boolean | нет | НДС включён в цену | | `canBuyZero` | boolean | нет | Разрешить покупку при нулевом остатке | | `quantityTrace` | boolean | нет | Включить учёт количества | | `subscribe` | boolean | нет | Разрешить подписку на товар | | `barcodeMulti` | boolean | нет | Отдельные штрихкоды для единиц товара | | `withoutOrder` | boolean | нет | Доступен к заказу без наличия на складе | | `purchasingPrice` | number | нет | Закупочная цена. Не применяется при включённом управлении складом | | `purchasingCurrency` | string | нет | Валюта закупочной цены. Не применяется при включённом управлении складом | | `quantity` | number | нет | Остаток на складе. Не применяется при включённом управлении складом | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/catalog-products" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Кабель USB-C", "iblockId": 25, "active": true, "measure": 9 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/catalog-products" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Кабель USB-C", "iblockId": 25, "active": true, "measure": 9 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-products', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Кабель USB-C', iblockId: 25, active: true, measure: 9, }), }) const { success, data } = await res.json() console.log('Product ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-products', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Кабель USB-C', iblockId: 25, active: true, measure: 9, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Полный объект созданного товара. Набор полей — как у [`GET /v1/catalog-products/:id`](./get.md) | URL карточки созданного товара в Битрикс24 строится из `iblockId` и `id`: ``` https://.bitrix24.ru/shop/catalog//product// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа Показаны основные поля. ```json { "success": true, "data": { "id": 7027, "iblockId": 25, "iblockSectionId": null, "name": "Кабель USB-C", "active": true, "code": null, "measure": 9, "available": true, "bundle": false, "canBuyZero": true, "quantityTrace": true, "subscribe": true, "barcodeMulti": false, "withoutOrder": false, "vatIncluded": false, "purchasingPrice": null, "purchasingCurrency": null, "quantity": null, "dateCreate": "2026-06-15T13:11:32.000Z", "timestampX": "2026-06-15T13:11:32.000Z", "xmlId": "7027" } } ``` ## Пример ответа при ошибке 422 — не передано обязательное поле: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Required fields: name" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 422 | `BITRIX_ERROR` | Не передано обязательное поле — сообщение перечисляет недостающие (`Required fields: name`, `Required fields: iblockId`) | | 422 | `BITRIX_ERROR` | Каталог с указанным `iblockId` не найден (`Iblock Not Found`) | | 400 | `READONLY_FIELD` | В теле передано поле только для чтения, например `available` или `bundle` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список товаров](/docs/entities/catalog-products/list) - [Получить товар](/docs/entities/catalog-products/get) - [Обновить товар](/docs/entities/catalog-products/update) - [Удалить товар](/docs/entities/catalog-products/delete) - [Цены каталога](/docs/entities/catalog-prices) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Catalog Products: Delete ## Удалить товар `DELETE /v1/catalog-products/:id` Удаляет товар по идентификатору. Восстановить удалённый товар через API нельзя — при необходимости создайте новый. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор товара | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/catalog-products/7027" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/catalog-products/7027" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-products/7027', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Товар удалён') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-products/7027', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Товар удалён') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — успех проверяется по статусу. ## Пример ответа ```http HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 422 — товара с указанным `id` не существует: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "product does not exist." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 422 | `BITRIX_ERROR` | Товара с указанным `id` не существует (`product does not exist.`) | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать товар](/docs/entities/catalog-products/create) - [Список товаров](/docs/entities/catalog-products/list) - [Получить товар](/docs/entities/catalog-products/get) - [Обновить товар](/docs/entities/catalog-products/update) - [Цены каталога](/docs/entities/catalog-prices) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Catalog Products: Fields ## Поля товара `GET /v1/catalog-products/fields` Возвращает справочник полей товара с подписями, типами, признаками «только для чтения» и «допускает `null`», описаниями и словарями `enum` там, где набор значений фиксирован, список полей, доступных для агрегации, а также операции, доступные в пакетном запросе. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-products/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-products/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-products/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data.fields).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-products/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа `data.fields` — объект, ключ которого совпадает с именем поля, а значение содержит тип, признаки доступности на запись, подпись для отображения и — у полей с фиксированным набором значений — их словарь. Состав ключей разобран в таблице после списка полей. `data.aggregatable` — поля, по которым работает [агрегация](./aggregate.md). `data.batch` — операции, доступные в [пакетном запросе](/docs/batch). | Поле | Тип | RO | Описание | |------|-----|:--:|---------| | `id` | number | да | Идентификатор товара | | `name` | string | нет | Название товара | | `active` | boolean | нет | Активен ли товар | | `iblockId` | number | нет¹ | ID каталога. Список: [`GET /v1/catalogs`](/docs/entities/catalogs). Задаётся только при создании. Смена через `PATCH` отклоняется — товар нельзя перенести между каталогами | | `iblockSectionId` | number \| null | нет | ID раздела каталога. `null` — товар не привязан к разделу. Список: [`GET /v1/catalog-sections`](/docs/entities/catalog-sections) | | `purchasingPrice` | number \| null | нет | Закупочная цена. `null`, если не задана | | `purchasingCurrency` | string \| null | нет | Валюта закупочной цены, например `RUB`. `null`, если закупочная цена не задана. Список: [`GET /v1/currencies`](/docs/entities/currencies) | | `quantity` | number \| null | нет | Остаток на складе. `null`, если не задан | | `weight` | number \| null | нет | Вес единицы товара. `null`, если не указан | | `measure` | number | нет | ID единицы измерения | | `available` | boolean | да | Доступен ли товар к покупке. Вычисляется Битрикс24 | | `vatIncluded` | boolean | нет | НДС включён в цену | | `bundle` | boolean | да | Является ли товар набором. Вычисляется Битрикс24 | | `canBuyZero` | boolean | нет | Разрешить покупку при нулевом остатке | | `quantityTrace` | boolean | нет | Включён учёт количества | | `subscribe` | boolean | нет | Разрешить подписку на товар | | `barcodeMulti` | boolean | нет | Разрешены отдельные штрихкоды для единиц товара | | `withoutOrder` | boolean | нет | Доступен к заказу без наличия на складе | | `dateActiveFrom` | datetime | нет | Дата начала активности товара | | `dateActiveTo` | datetime | нет | Дата окончания активности товара | | `createdBy` | number | да | ID пользователя, создавшего товар. Заполняется системой | | `modifiedBy` | number | да | ID пользователя, изменившего товар. Заполняется системой | | `dateCreate` | datetime | да | Дата создания товара | | `timestampX` | datetime | да | Дата последнего изменения | | `code` | string \| null | нет | Символьный код товара. `null`, если не задан | | `xmlId` | string | нет | Внешний идентификатор | | `sort` | number | нет | Порядок сортировки | | `vatId` | number | нет | ID ставки НДС по умолчанию | | `previewText` | string | нет | Текст анонса | | `detailText` | string | нет | Подробное описание | | `previewTextType` | string | нет | Формат текста анонса: `text` или `html` | | `detailTextType` | string | нет | Формат подробного описания: `text` или `html` | | `previewPicture` | object | нет | Изображение анонса | | `detailPicture` | object | нет | Детальное изображение | | `iblockSection` | object | нет | В справочнике `/fields` тип — `object`. Принимает массив ID разделов при создании и обновлении. На чтении не возвращается — основной раздел доступен как скалярный `iblockSectionId`. Список: [`GET /v1/catalog-sections`](/docs/entities/catalog-sections) | | `width` | number | нет | Ширина товара | | `height` | number | нет | Высота товара | | `length` | number | нет | Длина товара | | `quantityReserved` | number \| null | нет | Зарезервированное количество. `null`, если резерва нет | | `recurSchemeLength` | number | нет | Длина периода оплаты. Только для коробочной версии Битрикс24 при продаже контента | | `recurSchemeType` | string | нет | Единица времени периода оплаты: `H` — час, `D` — день, `W` — неделя, `M` — месяц, `Q` — квартал, `S` — полугодие, `Y` — год. Только для коробочной версии Битрикс24 при продаже контента | | `trialPriceId` | number | нет | ID товара для пробной оплаты. Только для коробочной версии Битрикс24 при продаже контента | ¹ `iblockId` доступен для записи только при создании (`createOnly`) — в справочнике приходит с `readonly: false` и `createOnly: true`. | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.fields.<имя>.type` | string | Тип поля: `number`, `string`, `boolean`, `datetime`, `object` | | `data.fields.<имя>.label` | string | Короткая подпись поля на русском языке | | `data.fields.<имя>.description` | string | Расширенное описание поля: назначение, где взять список допустимых значений, поведение при записи. Ключ есть у тех полей, у которых есть что добавить к подписи | | `data.fields.<имя>.readonly` | boolean | `true` — поле заполняется системой и не принимается при создании и обновлении | | `data.fields.<имя>.createOnly` | boolean | `true` — поле принимается только при создании. В `PATCH` отклоняется с `READONLY_FIELD` (есть у `iblockId`) | | `data.fields.<имя>.nullable` | boolean | `true` — поле может прийти со значением `null`. Ключ присутствует только у таких полей | | `data.fields.<имя>.enum` | array | Словарь допустимых значений: массив `{ value, label }`. Ключ есть у полей с фиксированным набором — `previewTextType` и `detailTextType` (`text` и `html`). Отправлять нужно `value`, `label` предназначен для показа человеку | | `data.aggregatable` | string[] | Поля, по которым работает [агрегация](./aggregate.md) | | `data.batch` | string[] | Операции товара, доступные в [пакетном запросе](/docs/batch): `create`, `update`, `delete` | ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "Идентификатор товара" }, "iblockId": { "type": "number", "readonly": false, "createOnly": true, "label": "ID каталога", "description": "Каталог, которому принадлежит товар. Список: GET /v1/catalogs. Задаётся только при создании — смена через PATCH отклоняется, товар нельзя перенести между каталогами." }, "purchasingPrice": { "type": "number", "readonly": false, "nullable": true, "label": "Закупочная цена", "description": "Закупочная цена товара; null, если не задана." }, "previewTextType": { "type": "string", "readonly": false, "label": "Формат текста анонса", "description": "Формат поля previewText.", "enum": [ { "value": "text", "label": "Текст" }, { "value": "html", "label": "HTML" } ] } }, "aggregatable": [ "purchasingPrice", "quantity", "iblockSectionId" ], "batch": [ "create", "update", "delete" ] } } ``` Пример сокращён до четырёх полей — по одному на каждый признак (`readonly`, `createOnly`, `nullable`) и одно с машиночитаемым словарём `enum`. В ответе приходят все сорок два. ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'catalog' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Запись зависит от управления складом.** Поля `quantity`, `purchasingPrice` и `purchasingCurrency` помечены в справочнике как доступные для записи, но при включённом на портале управлении складом не применяются при создании и изменении товара — остатки и закупочные цены ведутся складскими документами. **Часть полей не приходит в списке по умолчанию.** Символьный код `code`, габариты `width`, `height`, `length`, тексты `previewText`, `detailText`, сортировка `sort` и ещё ряд полей из справочника не возвращаются в ответе `GET /v1/catalog-products` без явного `?select=`. Перечислите нужные имена в `?select=`, чтобы получить их в списке — эти поля доступны и в фильтрации, и в сортировке. В ответе одного товара `GET /v1/catalog-products/:id` они возвращаются всегда. **Изображения и привязка к разделам не фильтруются.** `previewPicture` и `detailPicture` задаются при создании и обновлении и возвращаются в ответах — в `GET /v1/catalog-products/:id` и в списке по явному `?select=`, — но не поддерживают фильтрацию и сортировку. Поле `iblockSection` принимает массив ID разделов при создании и обновлении, но не возвращается в `GET /v1/catalog-products/:id` или списке. Для чтения, фильтрации и сортировки доступен скалярный `iblockSectionId` с ID основного раздела. **Ответ `GET /:id` содержит поля сверх справочника.** Запрос одного товара дополнительно возвращает тип товара `type` и пользовательские свойства каталога вида `propertyNNN`. Они не входят в справочник полей `GET /v1/catalog-products/fields` и недоступны для фильтрации и сортировки. **Каталог товара (`iblockId`) неизменяем.** Каталог выбирается при создании. Битрикс24 не переносит товар между каталогами через обновление. `PATCH` со сменой `iblockId` отклоняется с `400 READONLY_FIELD` — раньше такой запрос возвращал `200`, но товар оставался в прежнем каталоге (ложный успех). **Поля аудита защищены.** `createdBy` и `modifiedBy` заполняются Битрикс24 и не принимаются при создании и обновлении — попытка передать их отклоняется с `400 READONLY_FIELD`. ## Смотрите также - [Список товаров](/docs/entities/catalog-products/list) - [Создать товар](/docs/entities/catalog-products/create) - [Поиск товаров](/docs/entities/catalog-products/search) - [Цены каталога](/docs/entities/catalog-prices) - [Справочник сущностей](/docs/entities-index) --- # Catalog Products: Get ## Получить товар `GET /v1/catalog-products/:id` Возвращает один товар каталога по идентификатору. Ответ содержит больше полей, чем список: кроме полей из [справочника](./fields.md) приходят символьный код, размеры, тип и пользовательские свойства каталога. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор товара | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-products/541" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-products/541" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-products/541', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Товар:', data.name) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-products/541', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект товара. Базовый набор полей — см. [Поля товара](./fields.md) | Дополнительно к полям справочника одна запись содержит: - `code` — символьный код - `sort` — порядок сортировки - `type` — тип товара - `vatId` — ID ставки НДС - `quantityReserved` — зарезервированный остаток - `weight`, `width`, `height`, `length` — габариты товара - `xmlId` — внешний код - пользовательские свойства каталога вида `propertyNNN` — см. раздел «Значения списочных свойств» ниже Поля с пустым значением приходят как `null`. ## Пример ответа Показаны основные поля. ```json { "success": true, "data": { "id": 541, "iblockId": 25, "iblockSectionId": null, "name": "Кабель USB-C", "active": true, "code": null, "measure": 9, "weight": null, "vatId": 1, "vatIncluded": false, "available": true, "bundle": false, "canBuyZero": true, "quantityTrace": false, "subscribe": true, "barcodeMulti": false, "withoutOrder": false, "purchasingPrice": 110, "purchasingCurrency": "RUB", "quantity": null, "quantityReserved": null, "sort": 500, "type": 1, "dateCreate": "2021-08-06T12:59:15.000Z", "timestampX": "2025-10-31T10:24:18.000Z", "xmlId": "541" } } ``` ## Значения списочных свойств (`propertyNNN`) Пользовательские свойства каталога приходят в полях вида `propertyNNN`, где `NNN` — `id` свойства из [`GET /v1/catalog-product-properties`](/docs/entities/catalog-product-properties). У свойства-списка значение приходит объектом, и **читаемый текст уже лежит в ответе** — отдельный запрос за расшифровкой не нужен: ```json { "id": 160, "iblockId": 26, "name": "Футболка (L)", "property166": { "value": "116", "valueEnum": "L", "valueId": "674" } } ``` | Ключ | Что это | |------|---------| | `value` | ID элемента перечисления, **строкой**. Это `id` записи в [Значениях списочных свойств](/docs/entities/catalog-product-property-enums) | | `valueEnum` | Читаемый текст выбранного варианта. Здесь `L` — это размер, а не код `listType` | | `valueId` | ID строки значения у товара. Служебный, для сопоставления со справочником не нужен | **Форма зависит от `listType` свойства.** Прочитайте её в [`GET /v1/catalog-product-properties/:id`](/docs/entities/catalog-product-properties/get): | `listType` свойства | Что приходит в `propertyNNN` | |---|---| | `L` (выпадающий список) | объект `{ value, valueEnum, valueId }`, как выше | | `C` (флажок) | голый скаляр `"Y"` или `"N"` — состояние галочки, а не id варианта | При `multiple: true` та же форма приходит **массивом** — разворачивать нужно каждый элемент. За **всеми** возможными вариантами свойства (выпадашка, фильтр, экспорт) — [`GET /v1/catalog-product-property-enums?filter[propertyId]=166&limit=1000`](/docs/entities/catalog-product-property-enums/list). Сопоставление с товаром идёт по `String(элемент.id) === товар.propertyNNN.value`. ## Пример ответа при ошибке 422 — товара с таким `id` нет: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "product does not exist." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Товара с указанным `id` не существует (`product does not exist.`) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать товар](/docs/entities/catalog-products/create) - [Обновить товар](/docs/entities/catalog-products/update) - [Удалить товар](/docs/entities/catalog-products/delete) - [Список товаров](/docs/entities/catalog-products/list) - [Поля товара](/docs/entities/catalog-products/fields) - [Свойства товаров каталога](/docs/entities/catalog-product-properties) - [Значения списочных свойств](/docs/entities/catalog-product-property-enums) - [Справочник сущностей](/docs/entities-index) --- # Catalog Products: List ## Список товаров `GET /v1/catalog-products` Возвращает список товаров каталога с поддержкой фильтрации, сортировки, выборки полей и пагинации. Требует фильтр `filter[iblockId]` — каталог, по товарам которого идёт выборка. Без этого фильтра запрос возвращает `400`. ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `filter` | object | да | — | Условия фильтрации. Ключ `filter[iblockId]` обязателен — ID каталога из [`GET /v1/catalogs`](/docs/entities/catalogs).
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[iblockId]=25&filter[active]=true` | | `select` | string | нет | — | Выборка полей: `?select=iblockId,id,name,active`. Если параметр передан, в нём обязателен `iblockId`. Без `select` возвращаются все поля товара | | `sort` | string | нет | — | Поле сортировки. Префикс `-` — по убыванию: `?sort=-id` | | `limit` | number | нет | `50` | Количество записей (до 5000) | | `offset` | number | нет | `0` | Смещение от начала выборки | Для `limit > 50` ответ автоматически собирается из нескольких страниц на стороне сервера. Максимум — 5000 записей за вызов. Если под фильтр попадает больше записей, чем возвращено, в `meta.hasMore` придёт `true`. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-products?filter[iblockId]=25&limit=10" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-products?filter[iblockId]=25&limit=10" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const params = new URLSearchParams({ 'filter[iblockId]': '25', limit: '10' }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/catalog-products?${params}`, { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Товаров: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const params = new URLSearchParams({ 'filter[iblockId]': '25', limit: '10' }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/catalog-products?${params}`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив товаров. Состав полей элемента — см. [Поля товара](./fields.md) | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | URL карточки любого товара из массива `data` строится из его `iblockId` и `id`: ``` https://.bitrix24.ru/shop/catalog//product// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 533, "iblockId": 25, "iblockSectionId": 19, "name": "Колонка настольная", "active": true, "available": true, "barcodeMulti": false, "bundle": false, "canBuyZero": true, "measure": 9, "purchasingCurrency": "RUB", "purchasingPrice": 0, "quantity": null, "quantityTrace": true, "subscribe": true, "vatIncluded": false, "weight": null, "withoutOrder": false, "dateCreate": "2021-07-20T10:01:36.000Z", "timestampX": "2023-08-21T08:12:18.000Z" }, { "id": 541, "iblockId": 25, "iblockSectionId": null, "name": "Кабель USB-C", "active": true, "available": true, "barcodeMulti": false, "bundle": false, "canBuyZero": true, "measure": 9, "purchasingCurrency": "RUB", "purchasingPrice": 110, "quantity": null, "quantityTrace": false, "subscribe": true, "vatIncluded": false, "weight": null, "withoutOrder": false, "dateCreate": "2021-08-06T12:59:15.000Z", "timestampX": "2025-10-31T10:24:18.000Z" } ], "meta": { "total": 19, "hasMore": false } } ``` ## Пример ответа при ошибке 400 — не передан обязательный фильтр: ```json { "success": false, "error": { "code": "MISSING_REQUIRED_FILTER", "message": "GET /v1/catalog-products requires filter fields: iblockId. Example: GET /v1/catalog-products?filter[iblockId]=..." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_FILTER` | Не передан обязательный фильтр `filter[iblockId]`. Запрос отклоняется до обращения к Битрикс24 — сообщение содержит имя недостающего поля и пример вызова | | 422 | `BITRIX_ERROR` | Каталог с указанным `iblockId` не найден (`Iblock Not Found`) | | 422 | `BITRIX_ERROR` | В `select` передан без `iblockId` (`Required select fields: iblockId`) | | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет у товара. Сообщение содержит список доступных полей | | 400 | `UNKNOWN_SORT_FIELD` | Сортировка по полю, которого нет у товара. Сообщение содержит список доступных полей | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать товар](/docs/entities/catalog-products/create) - [Получить товар](/docs/entities/catalog-products/get) - [Поиск товаров](/docs/entities/catalog-products/search) - [Поля товара](/docs/entities/catalog-products/fields) - [Цены каталога](/docs/entities/catalog-prices) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entities-index) --- # Catalog Products: Search ## Поиск товаров `POST /v1/catalog-products/search` Поиск товаров каталога по условиям, переданным в теле запроса. В отличие от [`GET /v1/catalog-products`](./list.md), параметры `filter`, `select`, `sort`, `limit` и `offset` передаются в JSON-теле, а не в строке адреса — условия по нескольким полям задаются вложенной структурой. Как и список, поиск требует `filter.iblockId` — без этого поля запрос возвращает `400`. Формат ответа тот же, что у списка. ## Поля запроса (body) | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `filter` | object | да | — | Условия фильтрации. Ключ `iblockId` обязателен — ID каталога из [`GET /v1/catalogs`](/docs/entities/catalogs).
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "iblockId": 25, "active": true }` | | `select` | string[] | нет | — | Выборка полей: `["iblockId", "id", "name"]`. Если параметр передан, в нём обязателен `iblockId`. Без `select` возвращаются все поля товара | | `sort` | string | нет | — | Поле сортировки. Префикс `-` — по убыванию: `"-id"` | | `limit` | number | нет | `50` | Количество записей (до 5000) | | `offset` | number | нет | `0` | Смещение от начала выборки. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки» | | `autoWindow` | boolean | нет | `true` | Разбивать выборку по недельным окнам при фильтре по диапазону дат шире 14 дней. `false` отключает разбиение | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/catalog-products/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "iblockId": 25, "active": true }, "limit": 3 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/catalog-products/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "iblockId": 25, "active": true }, "limit": 3 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-products/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { iblockId: 25, active: true }, limit: 3, }), }) const { success, data, meta } = await res.json() console.log(`Найдено: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-products/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { iblockId: 25, active: true }, limit: 3, }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив товаров. Состав полей элемента — см. [Поля товара](./fields.md) | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временны́м окнам | | `meta.windowCount` | number | Число окон. Приходит при `autoWindowed: true` | | `meta.batchWaves` | number | Число волн параллельных запросов. Приходит при `autoWindowed: true` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. URL карточки любого товара из массива `data` строится из его `iblockId` и `id`: ``` https://.bitrix24.ru/shop/catalog//product// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 6975, "iblockId": 25, "iblockSectionId": null, "name": "Услуга доставки", "active": true, "available": true, "barcodeMulti": false, "bundle": false, "canBuyZero": true, "measure": 9, "purchasingCurrency": null, "purchasingPrice": null, "quantity": 1, "quantityTrace": false, "subscribe": false, "vatIncluded": false, "weight": null, "withoutOrder": false, "dateCreate": "2025-12-02T09:14:05.000Z", "timestampX": "2025-12-02T09:14:05.000Z" } ], "meta": { "total": 19, "hasMore": true, "durationMs": 540 } } ``` С фильтром по диапазону дат шире 14 дней в `meta` дополнительно приходят `autoWindowed`, `windowCount` и `batchWaves`: ```json { "success": true, "data": [ /* ... */ ], "meta": { "total": 19, "hasMore": true, "autoWindowed": true, "windowCount": 131, "batchWaves": 3, "durationMs": 8745 } } ``` ## Пример ответа при ошибке 400 — не передан обязательный фильтр: ```json { "success": false, "error": { "code": "MISSING_REQUIRED_FILTER", "message": "POST /v1/catalog-products/search requires filter fields: iblockId. Example body: { \"filter\": {\"iblockId\":\"...\"} }" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_FILTER` | Не передан обязательный фильтр `filter.iblockId`. Запрос отклоняется до обращения к Битрикс24 — сообщение содержит имя недостающего поля и пример тела запроса | | 422 | `BITRIX_ERROR` | В `select` передан без `iblockId` (`Required select fields: iblockId`) | | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет у товара. Сообщение содержит список доступных полей | | 400 | `UNKNOWN_SORT_FIELD` | Сортировка по полю, которого нет у товара. Сообщение содержит список доступных полей | | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Разбиение по временны́м окнам.** Фильтр по диапазону дат шире 14 дней автоматически разбивается на недельные окна, которые выполняются параллельными волнами — так выборка обходит потолок в 5000 записей на один вызов. В `meta` тогда приходят `autoWindowed: true`, число окон `windowCount` и число волн `batchWaves`. Отключает разбиение параметр `autoWindow: false`. При активном разбиении `offset` больше нуля отклоняется с `UNSTABLE_OFFSET_PAGINATION`. ## Смотрите также - [Список товаров](/docs/entities/catalog-products/list) - [Создать товар](/docs/entities/catalog-products/create) - [Получить товар](/docs/entities/catalog-products/get) - [Поля товара](/docs/entities/catalog-products/fields) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entities-index) --- # Catalog Products: Update ## Обновить товар `PATCH /v1/catalog-products/:id` Изменяет существующий товар. Поля передаются плоско в корне JSON. Передавайте только изменяемые поля — остальные сохраняют текущие значения. В ответ приходит полный объект обновлённого товара. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор товара | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `name` | string | нет | Название товара | | `active` | boolean | нет | Активен ли товар | | `iblockSectionId` | number | нет | ID раздела каталога. Список: `GET /v1/catalog-sections` | | `measure` | number | нет | ID единицы измерения | | `weight` | number | нет | Вес единицы товара | | `vatIncluded` | boolean | нет | НДС включён в цену | | `canBuyZero` | boolean | нет | Разрешить покупку при нулевом остатке | | `quantityTrace` | boolean | нет | Включить учёт количества | | `subscribe` | boolean | нет | Разрешить подписку на товар | | `barcodeMulti` | boolean | нет | Отдельные штрихкоды для единиц товара | | `withoutOrder` | boolean | нет | Доступен к заказу без наличия на складе | | `purchasingPrice` | number | нет | Закупочная цена. Не применяется при включённом управлении складом | | `purchasingCurrency` | string | нет | Валюта закупочной цены. Не применяется при включённом управлении складом | | `quantity` | number | нет | Остаток на складе. Не применяется при включённом управлении складом | | `code` | string | нет | Символьный код товара | | `xmlId` | string | нет | Внешний код | | `sort` | number | нет | Индекс сортировки | | `vatId` | number | нет | ID ставки НДС | | `height` | number | нет | Высота | | `length` | number | нет | Длина | | `width` | number | нет | Ширина | | `dateActiveFrom` | datetime | нет | Начало активности | | `dateActiveTo` | datetime | нет | Конец активности | | `previewText` | string | нет | Описание для анонса | | `detailText` | string | нет | Детальное описание | | `previewTextType` | string | нет | Тип описания анонса: `text` или `html` | | `detailTextType` | string | нет | Тип детального описания: `text` или `html` | | `previewPicture` | object | нет | Картинка анонса: `{ "fileData": ["имя.png", ""] }` или `{ "remove": "Y" }` | | `detailPicture` | object | нет | Детальная картинка (тот же формат) | | `iblockSection` | object | нет | Массив всех разделов, к которым привязан товар | | `propertyNNN` | object/array | нет | Значение свойства товара, где `NNN` — ID свойства: `{ "valueId": …, "value": … }` (или массив для множественных) | Пользовательские свойства товара передаются как `propertyNNN`; on-premise-поля (`recurSchemeType`, `recurSchemeLength`, `trialPriceId`) тоже принимаются. Полный список полей — в [`GET /v1/catalog-products/fields`](./fields.md). **Тело должно содержать хотя бы одно записываемое поле.** Пустой `PATCH` (`{}`) отклоняется с `400 EMPTY_UPDATE_BODY`, а `PATCH`, в котором нет ни одного распознанного записываемого поля (например только опечатки), — с `400 NO_RECOGNIZED_UPDATE_FIELDS`. Раньше такой запрос возвращал `200` с неизменённым объектом, вводя клиента в заблуждение. Поля-объекты `iblockSection`/`previewPicture`/`detailPicture` пишутся, но по ним нельзя фильтровать и сортировать (запрос отклоняется явной ошибкой `UNKNOWN_FILTER_FIELD`/`UNKNOWN_SORT_FIELD`); для надёжной фильтрации используйте индексируемые поля (`code`, `xmlId`, `sort`, `vatId`, размеры). `id` передаётся в пути, в теле его передавать нельзя — он только для чтения. Поля `available` и `bundle` вычисляются Битрикс24 и при записи отвечают `READONLY_FIELD`. `iblockId` задаётся только при создании: смена каталога через `PATCH` отклоняется с `READONLY_FIELD` — Битрикс24 не переносит товар между каталогами (раньше такой запрос возвращал `200`, но товар оставался на месте). Поля аудита `createdBy` и `modifiedBy` заполняются системой и при записи тоже отвечают `READONLY_FIELD`. ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/catalog-products/541" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Кабель USB-C, 2 м" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/catalog-products/541" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Кабель USB-C, 2 м" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-products/541', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Кабель USB-C, 2 м', }), }) const { success, data } = await res.json() console.log('Новое название:', data.name) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-products/541', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Кабель USB-C, 2 м', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Полный объект обновлённого товара. Набор полей — как у [`GET /v1/catalog-products/:id`](./get.md) | ## Пример ответа Показаны основные поля. ```json { "success": true, "data": { "id": 541, "iblockId": 25, "iblockSectionId": null, "name": "Кабель USB-C, 2 м", "active": true, "measure": 9, "available": true, "bundle": false, "canBuyZero": true, "quantityTrace": false, "subscribe": true, "vatIncluded": false, "purchasingPrice": 110, "purchasingCurrency": "RUB", "quantity": null, "dateCreate": "2021-08-06T12:59:15.000Z", "timestampX": "2026-06-15T13:11:33.000Z", "xmlId": "541" } } ``` ## Пример ответа при ошибке 422 — товара с указанным `id` не существует: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "product does not exist." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 422 | `BITRIX_ERROR` | Товара с указанным `id` не существует (`product does not exist.`) | | 400 | `EMPTY_UPDATE_BODY` | Тело запроса пустое — передайте хотя бы одно поле | | 400 | `NO_RECOGNIZED_UPDATE_FIELDS` | В теле нет ни одного распознанного записываемого поля (только опечатки/мусор) | | 400 | `READONLY_FIELD` | В теле передано поле только для чтения, например `id`, `available` или `bundle` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать товар](/docs/entities/catalog-products/create) - [Список товаров](/docs/entities/catalog-products/list) - [Получить товар](/docs/entities/catalog-products/get) - [Удалить товар](/docs/entities/catalog-products/delete) - [Цены каталога](/docs/entities/catalog-prices) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Catalog Sections: Create ## Создать раздел `POST /v1/catalog-sections` Создаёт раздел каталога. Поля передаются плоско в корне JSON. ## Поля запроса (body) | Поле | Тип | Обяз. | По умолч. | Описание | |------|-----|:-----:|-----------|---------| | `iblockId` | number | да | — | ID каталога, которому принадлежит раздел. Список: `GET /v1/catalogs` | | `name` | string | да | — | Название раздела | | `iblockSectionId` | number | нет | `null` | ID родительского раздела. `null` — раздел верхнего уровня | | `code` | string | нет | `null` | Символьный код раздела | | `xmlId` | string | нет | `null` | Внешний идентификатор | | `sort` | number | нет | `500` | Индекс сортировки | | `active` | boolean | нет | `true` | Активен ли раздел | | `description` | string | нет | `null` | Описание раздела | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/catalog-sections" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "iblockId": 25, "name": "Новинки", "sort": 100 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/catalog-sections" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "iblockId": 25, "name": "Новинки", "sort": 100 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-sections', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ iblockId: 25, name: 'Новинки', sort: 100, }), }) const { success, data } = await res.json() console.log('Section ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-sections', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ iblockId: 25, name: 'Новинки', sort: 100, }), }) const { success, data } = await res.json() ``` ## Поля ответа Возвращается полный объект созданного раздела. | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор созданного раздела | | `iblockId` | number | ID каталога | | `iblockSectionId` | number \| null | ID родительского раздела. `null` — раздел верхнего уровня | | `name` | string | Название раздела | | `code` | string \| null | Символьный код раздела | | `xmlId` | string \| null | Внешний идентификатор | | `sort` | number | Индекс сортировки | | `active` | boolean | Активен ли раздел | | `description` | string \| null | Описание раздела | | `descriptionType` | string | Формат описания: `text` или `html` | ## Пример ответа ```json { "success": true, "data": { "active": true, "code": null, "description": null, "descriptionType": "text", "iblockId": 25, "iblockSectionId": null, "id": 215, "name": "Новинки", "sort": 100, "xmlId": null } } ``` ## Пример ответа при ошибке 422 — не передано обязательное поле: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Required fields: name" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 422 | `BITRIX_ERROR` | Не передано обязательное поле — сообщение называет недостающее (`Required fields: iblockId` или `Required fields: name`) | | 400 | `READONLY_FIELD` | В теле передан `id` — это поле заполняется системой и не принимается при создании | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список разделов](/docs/entities/catalog-sections/list) - [Получить раздел](/docs/entities/catalog-sections/get) - [Обновить раздел](/docs/entities/catalog-sections/update) - [Удалить раздел](/docs/entities/catalog-sections/delete) - [Каталоги](/docs/entities/catalogs) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Catalog Sections: Delete ## Удалить раздел `DELETE /v1/catalog-sections/:id` Удаляет раздел каталога по идентификатору. Восстановить удалённый раздел через API нельзя — при необходимости создайте новый. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор раздела | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/catalog-sections/215" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/catalog-sections/215" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-sections/215', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Раздел удалён') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-sections/215', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Раздел удалён') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — успех проверяется по статусу. ## Пример ответа ```http HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 422 — раздел нельзя удалить или его нет: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Access Denied" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 422 | `BITRIX_ERROR` | Раздела с указанным `id` нет, либо Битрикс24 отказал в удалении — ответ `Access Denied` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать раздел](/docs/entities/catalog-sections/create) - [Список разделов](/docs/entities/catalog-sections/list) - [Получить раздел](/docs/entities/catalog-sections/get) - [Обновить раздел](/docs/entities/catalog-sections/update) - [Каталоги](/docs/entities/catalogs) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Catalog Sections: Fields ## Поля раздела `GET /v1/catalog-sections/fields` Возвращает справочник полей раздела каталога с типами, признаками «только для чтения» и «допускает `null`», а также список операций, доступных в пакетном запросе. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-sections/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-sections/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-sections/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data.fields).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-sections/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа `data.fields` — объект, ключ которого совпадает с именем поля, а значение содержит `type` (тип поля), `readonly` (`true` — поле нельзя передать при создании и обновлении) и `nullable` (присутствует, если поле может прийти со значением `null`). `data.batch` — список операций, которые принимает [пакетный запрос](/docs/batch). | Поле | Тип | RO | Описание | |------|-----|:--:|---------| | `id` | number | да | Идентификатор раздела | | `iblockId` | number | нет | ID каталога, которому принадлежит раздел. Список: [`GET /v1/catalogs`](/docs/entities/catalogs) | | `iblockSectionId` | number \| null | нет | ID родительского раздела. `null` — раздел верхнего уровня | | `name` | string | нет | Название раздела | | `xmlId` | string \| null | нет | Внешний идентификатор. `null`, если не задан | | `code` | string \| null | нет | Символьный код раздела. `null`, если не задан | | `sort` | number | нет | Индекс сортировки | | `active` | boolean | нет | Активен ли раздел | | `description` | string \| null | нет | Описание раздела. `null`, если не задано | | `descriptionType` | string | нет | Формат описания: `text` или `html` | | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.fields.<имя>.type` | string | Тип поля: `number`, `string`, `boolean`, `datetime` | | `data.fields.<имя>.readonly` | boolean | `true` — поле заполняется системой и не принимается при создании и обновлении | | `data.fields.<имя>.nullable` | boolean | `true` — поле может прийти со значением `null`. Ключ присутствует только у таких полей | | `data.batch` | string[] | Операции раздела, доступные в [пакетном запросе](/docs/batch): `create`, `update`, `delete` | ## Пример ответа Каждое поле, помимо `type` и `readonly`, содержит `label` (короткое название) и `description` (пояснение) на русском языке. В примере ниже они опущены для краткости. ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true }, "iblockId": { "type": "number", "readonly": false }, "iblockSectionId": { "type": "number", "readonly": false, "nullable": true }, "name": { "type": "string", "readonly": false }, "xmlId": { "type": "string", "readonly": false, "nullable": true }, "code": { "type": "string", "readonly": false, "nullable": true }, "sort": { "type": "number", "readonly": false }, "active": { "type": "boolean", "readonly": false }, "description": { "type": "string", "readonly": false, "nullable": true }, "descriptionType": { "type": "string", "readonly": false } }, "batch": ["create", "update", "delete"] } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'catalog' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список разделов](/docs/entities/catalog-sections/list) - [Создать раздел](/docs/entities/catalog-sections/create) - [Поиск разделов](/docs/entities/catalog-sections/search) - [Каталоги](/docs/entities/catalogs) - [Справочник сущностей](/docs/entities-index) --- # Catalog Sections: Get ## Получить раздел `GET /v1/catalog-sections/:id` Возвращает один раздел каталога по идентификатору. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор раздела | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-sections/31" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-sections/31" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-sections/31', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Раздел:', data.name) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-sections/31', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Идентификатор раздела | | `data.iblockId` | number | ID каталога, которому принадлежит раздел | | `data.iblockSectionId` | number \| null | ID родительского раздела. `null` — раздел верхнего уровня | | `data.name` | string | Название раздела | | `data.code` | string \| null | Символьный код раздела | | `data.xmlId` | string \| null | Внешний идентификатор | | `data.sort` | number | Индекс сортировки | | `data.active` | boolean | Активен ли раздел | | `data.description` | string \| null | Описание раздела | | `data.descriptionType` | string | Формат описания: `text` или `html` | ## Пример ответа ```json { "success": true, "data": { "active": true, "code": "clothes", "description": null, "descriptionType": "text", "iblockId": 25, "iblockSectionId": null, "id": 31, "name": "Одежда", "sort": 50, "xmlId": null } } ``` ## Пример ответа при ошибке 422 — раздела с таким `id` нет: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Access Denied" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Раздела с указанным `id` не существует или нет доступа — Битрикс24 отвечает `Access Denied` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список разделов](/docs/entities/catalog-sections/list) - [Создать раздел](/docs/entities/catalog-sections/create) - [Обновить раздел](/docs/entities/catalog-sections/update) - [Удалить раздел](/docs/entities/catalog-sections/delete) - [Каталоги](/docs/entities/catalogs) - [Справочник сущностей](/docs/entities-index) --- # Catalog Sections: List ## Список разделов `GET /v1/catalog-sections` Возвращает список разделов каталога с поддержкой фильтрации, сортировки, выборки полей и пагинации. Требует фильтр `filter[iblockId]` — каталог, по разделам которого идёт выборка. Без этого фильтра запрос возвращает `400`. ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `filter` | object | да | — | Условия фильтрации. Ключ `filter[iblockId]` обязателен — ID каталога из [`GET /v1/catalogs`](/docs/entities/catalogs).
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[iblockId]=25` | | `select` | string | нет | — | Выборка полей: `?select=id,name,sort`. Возвращаются только перечисленные поля | | `sort` | string | нет | — | Поле сортировки. Префикс `-` — по убыванию: `?sort=-sort` | | `limit` | number | нет | `50` | Количество записей (до 5000) | | `offset` | number | нет | `0` | Смещение от начала выборки | Для выборки разделов одного родителя добавьте `filter[iblockSectionId]`. Для `limit > 50` ответ автоматически собирается из нескольких страниц на стороне сервера. Максимум — 5000 записей за вызов. Если под фильтр попадает больше записей, чем возвращено, в `meta.hasMore` придёт `true`. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-sections?filter[iblockId]=25" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/catalog-sections?filter[iblockId]=25" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const url = 'https://vibecode.bitrix24.tech/v1/catalog-sections?filter[iblockId]=25' const res = await fetch(url, { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Разделов: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const url = 'https://vibecode.bitrix24.tech/v1/catalog-sections?filter[iblockId]=25' const res = await fetch(url, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив разделов | | `data[].id` | number | Идентификатор раздела | | `data[].iblockId` | number | ID каталога, которому принадлежит раздел | | `data[].iblockSectionId` | number \| null | ID родительского раздела. `null` — раздел верхнего уровня | | `data[].name` | string | Название раздела | | `data[].code` | string \| null | Символьный код раздела | | `data[].xmlId` | string \| null | Внешний идентификатор | | `data[].sort` | number | Индекс сортировки | | `data[].active` | boolean | Активен ли раздел | | `data[].description` | string \| null | Описание раздела | | `data[].descriptionType` | string | Формат описания: `text` или `html` | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | ## Пример ответа ```json { "success": true, "data": [ { "active": true, "code": "clothes", "description": null, "descriptionType": "text", "iblockId": 25, "iblockSectionId": null, "id": 31, "name": "Одежда", "sort": 50, "xmlId": null }, { "active": true, "code": "shoes", "description": null, "descriptionType": "text", "iblockId": 25, "iblockSectionId": 31, "id": 35, "name": "Обувь", "sort": 100, "xmlId": null } ], "meta": { "total": 37, "hasMore": false } } ``` ## Пример ответа при ошибке 400 — фильтр по несуществующему полю: ```json { "success": false, "error": { "code": "UNKNOWN_FILTER_FIELD", "message": "Unknown filter field 'bogus' for entity 'catalog-sections'. Available: id, iblockId, iblockSectionId, name, xmlId, code, sort, active, description, descriptionType" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_FILTER` | Не передан обязательный фильтр `filter[iblockId]`. Запрос отклоняется до обращения к Битрикс24 — сообщение содержит имя недостающего поля и пример вызова | | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет у раздела. Сообщение содержит список доступных полей | | 400 | `UNKNOWN_SORT_FIELD` | Сортировка по полю, которого нет у раздела | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать раздел](/docs/entities/catalog-sections/create) - [Получить раздел](/docs/entities/catalog-sections/get) - [Поиск разделов](/docs/entities/catalog-sections/search) - [Каталоги](/docs/entities/catalogs) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entities-index) --- # Catalog Sections: Search ## Поиск разделов `POST /v1/catalog-sections/search` Поиск разделов каталога по условиям, переданным в теле запроса. В отличие от [`GET /v1/catalog-sections`](./list.md), параметры `filter`, `select`, `sort`, `limit` и `offset` передаются в JSON-теле, а не в строке адреса — условия по нескольким полям задаются вложенной структурой. Как и список, поиск требует `filter.iblockId` — без этого поля запрос возвращает `400`. Формат ответа тот же, что у списка. ## Поля запроса (body) | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `filter` | object | да | — | Условия фильтрации. Ключ `iblockId` обязателен — ID каталога из [`GET /v1/catalogs`](/docs/entities/catalogs).
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "iblockId": 25, "active": true }` | | `select` | string[] | нет | — | Выборка полей: `["id", "name", "sort"]`. Возвращаются только перечисленные поля | | `sort` | string | нет | — | Поле сортировки. Префикс `-` — по убыванию: `"-sort"` | | `limit` | number | нет | `50` | Количество записей (до 5000) | | `offset` | number | нет | `0` | Смещение от начала выборки | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/catalog-sections/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "iblockId": 25, "active": true }, "limit": 2 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/catalog-sections/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "iblockId": 25, "active": true }, "limit": 2 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-sections/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { iblockId: 25, active: true }, limit: 2, }), }) const { success, data, meta } = await res.json() console.log(`Найдено: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-sections/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { iblockId: 25, active: true }, limit: 2, }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив разделов | | `data[].id` | number | Идентификатор раздела | | `data[].iblockId` | number | ID каталога, которому принадлежит раздел | | `data[].iblockSectionId` | number \| null | ID родительского раздела. `null` — раздел верхнего уровня | | `data[].name` | string | Название раздела | | `data[].code` | string \| null | Символьный код раздела | | `data[].xmlId` | string \| null | Внешний идентификатор | | `data[].sort` | number | Индекс сортировки | | `data[].active` | boolean | Активен ли раздел | | `data[].description` | string \| null | Описание раздела | | `data[].descriptionType` | string | Формат описания: `text` или `html` | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа ```json { "success": true, "data": [ { "active": true, "code": "clothes", "description": null, "descriptionType": "text", "iblockId": 25, "iblockSectionId": null, "id": 31, "name": "Одежда", "sort": 50, "xmlId": null }, { "active": true, "code": "shoes", "description": null, "descriptionType": "text", "iblockId": 25, "iblockSectionId": 31, "id": 35, "name": "Обувь", "sort": 100, "xmlId": null } ], "meta": { "total": 37, "hasMore": true, "durationMs": 165 } } ``` ## Пример ответа при ошибке 400 — фильтр по несуществующему полю: ```json { "success": false, "error": { "code": "UNKNOWN_FILTER_FIELD", "message": "Unknown filter field 'bogus' for entity 'catalog-sections'. Available: id, iblockId, iblockSectionId, name, xmlId, code, sort, active, description, descriptionType" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_FILTER` | Не передан обязательный фильтр `filter.iblockId`. Запрос отклоняется до обращения к Битрикс24 — сообщение содержит имя недостающего поля и пример тела запроса | | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет у раздела. Сообщение содержит список доступных полей | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список разделов](/docs/entities/catalog-sections/list) - [Создать раздел](/docs/entities/catalog-sections/create) - [Получить раздел](/docs/entities/catalog-sections/get) - [Поля раздела](/docs/entities/catalog-sections/fields) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entities-index) --- # Catalog Sections: Update ## Обновить раздел `PATCH /v1/catalog-sections/:id` Изменяет существующий раздел каталога. Поля передаются плоско в корне JSON. Передавайте только изменяемые поля — остальные сохраняют текущие значения. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор раздела | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `name` | string | нет | Название раздела | | `iblockSectionId` | number | нет | ID родительского раздела. `0` переносит раздел на верхний уровень | | `code` | string | нет | Символьный код раздела | | `xmlId` | string | нет | Внешний идентификатор | | `sort` | number | нет | Индекс сортировки | | `active` | boolean | нет | Активен ли раздел | | `description` | string | нет | Описание раздела | | `iblockId` | number | нет | ID каталога. Подставляется автоматически из текущей записи, если не передан | `id` передаётся в пути (`/v1/catalog-sections/:id`), в теле его передавать нельзя — он только для чтения. Поля `iblockId` и `name` нужны Битрикс24 на каждое изменение, поэтому при их отсутствии в теле они берутся из текущей записи — достаточно передать одно изменяемое поле. ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/catalog-sections/215" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "sort": 200 }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/catalog-sections/215" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "sort": 200 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-sections/215', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ sort: 200, }), }) const { success, data } = await res.json() console.log('Новый порядок:', data.sort) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-sections/215', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ sort: 200, }), }) const { success, data } = await res.json() ``` ## Поля ответа Возвращается полный обновлённый объект раздела. | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор раздела | | `iblockId` | number | ID каталога | | `iblockSectionId` | number \| null | ID родительского раздела. `null` — раздел верхнего уровня | | `name` | string | Название раздела | | `code` | string \| null | Символьный код раздела | | `xmlId` | string \| null | Внешний идентификатор | | `sort` | number | Индекс сортировки | | `active` | boolean | Активен ли раздел | | `description` | string \| null | Описание раздела | | `descriptionType` | string | Формат описания: `text` или `html` | ## Пример ответа ```json { "success": true, "data": { "active": true, "code": null, "description": null, "descriptionType": "text", "iblockId": 25, "iblockSectionId": null, "id": 215, "name": "Новинки", "sort": 200, "xmlId": null } } ``` ## Пример ответа при ошибке 422 — раздела с указанным `id` не существует: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Required fields: iblockId" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 422 | `BITRIX_ERROR` | Раздела с указанным `id` не существует — подстановка `iblockId` из текущей записи не сработала, Битрикс24 отвечает `Required fields: iblockId` | | 400 | `READONLY_FIELD` | В теле передан `id` — это поле заполняется системой и не принимается при обновлении | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать раздел](/docs/entities/catalog-sections/create) - [Список разделов](/docs/entities/catalog-sections/list) - [Получить раздел](/docs/entities/catalog-sections/get) - [Удалить раздел](/docs/entities/catalog-sections/delete) - [Каталоги](/docs/entities/catalogs) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Catalogs: Fields ## Поля каталога `GET /v1/catalogs/fields` Возвращает справочник полей торгового каталога с типами. Все поля доступны только для чтения. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/catalogs/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/catalogs/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalogs/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data.fields).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalogs/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа `data.fields` — объект, ключ которого совпадает с именем поля, а значение содержит `type` (тип поля), `readonly` (`true` — поле нельзя передать при создании и обновлении), `label` (отображаемое название) и `description` (краткое описание). Значения `label`/`description` приходят на русском языке. | Поле | Тип | RO | Описание | |------|-----|:--:|---------| | `id` | number | да | Идентификатор каталога. Совпадает с `iblockId` | | `iblockId` | number | да | ID информационного блока каталога. По нему фильтруются [`GET /v1/catalog-products`](/docs/entities/catalog-products), [`GET /v1/catalog-sections`](/docs/entities/catalog-sections), [`GET /v1/catalog-prices`](/docs/entities/catalog-prices) | | `iblockTypeId` | string | да | Тип информационного блока, например `CRM_PRODUCT_CATALOG` | | `lid` | string | да | ID сайта, к которому привязан каталог | | `name` | string | да | Название каталога | | `productIblockId` | number | да | У каталога предложений — `iblockId` связанного каталога товаров. У базового каталога товаров — `null` | | `skuPropertyId` | number | да | У каталога предложений — ID свойства связи предложения с товаром. У базового каталога — `null` | | `subscription` | string | да | Признак каталога подписок: `Y` или `N` | | `vatId` | number | да | ID ставки НДС по умолчанию для товаров каталога | | `yandexExport` | boolean | да | Признак выгрузки каталога в Яндекс.Маркет (`true` / `false`) | ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "ID", "description": "Уникальный идентификатор торгового каталога." }, "iblockId": { "type": "number", "readonly": true, "label": "Информационный блок", "description": "ID информационного блока, на котором построен каталог; нужен для /v1/catalog-products и /v1/catalog-sections." }, "iblockTypeId": { "type": "string", "readonly": true, "label": "Тип информационного блока", "description": "Символьный код типа информационного блока." }, "lid": { "type": "string", "readonly": true, "label": "Сайт", "description": "Символьный код сайта, которому принадлежит каталог." }, "name": { "type": "string", "readonly": true, "label": "Название", "description": "Название каталога, отображаемое пользователю." }, "productIblockId": { "type": "number", "readonly": true, "label": "Инфоблок товаров", "description": "ID информационного блока товаров для каталога с торговыми предложениями." }, "skuPropertyId": { "type": "number", "readonly": true, "label": "Свойство привязки предложений", "description": "ID свойства, связывающего торговые предложения с родительским товаром." }, "subscription": { "type": "string", "readonly": true, "label": "Подписка", "description": "Является ли каталог каталогом подписки (Y/N)." }, "vatId": { "type": "number", "readonly": true, "label": "Ставка НДС", "description": "ID ставки НДС, применяемой к каталогу по умолчанию." }, "yandexExport": { "type": "boolean", "readonly": true, "label": "Экспорт в Яндекс.Маркет", "description": "Выгружается ли каталог в Яндекс.Маркет." } } } } ``` Все поля помечены `readonly: true` — изменить каталог через API нельзя. ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'catalog' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список каталогов](/docs/entities/catalogs/list) - [Получить каталог](/docs/entities/catalogs/get) - [Товары каталога](/docs/entities/catalog-products) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entities-index) --- # Catalogs: Get ## Получить каталог `GET /v1/catalogs/:id` Возвращает один торговый каталог по идентификатору со всеми полями. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID каталога | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/catalogs/25" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/catalogs/25" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalogs/25', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Каталог:', data.name, '— iblockId', data.iblockId) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalogs/25', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа Объект каталога со всеми полями — см. [Поля каталога](/docs/entities/catalogs/fields). ## Пример ответа ```json { "success": true, "data": { "id": 25, "iblockId": 25, "iblockTypeId": "CRM_PRODUCT_CATALOG", "lid": "s1", "name": "Товарный каталог CRM", "productIblockId": null, "skuPropertyId": null, "subscription": "N", "vatId": 1, "yandexExport": false } } ``` ## Пример ответа при ошибке 422 — каталог не найден: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "catalog does not exist." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Каталога с таким `id` нет — в сообщении «catalog does not exist.». Тот же ответ возвращается для нечислового `id` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Каталог товаров или каталог предложений.** Тип каталога видно по полям `productIblockId` и `skuPropertyId`: у базового каталога товаров оба `null`; у каталога предложений они заполнены, причём `productIblockId` — это `iblockId` связанного каталога товаров. ## Смотрите также - [Поля каталога](/docs/entities/catalogs/fields) - [Список каталогов](/docs/entities/catalogs/list) - [Товары каталога](/docs/entities/catalog-products) - [Справочник сущностей](/docs/entities-index) --- # Catalogs: List ## Список каталогов `GET /v1/catalogs` Возвращает список торговых каталогов портала с поддержкой фильтрации, сортировки и выборки полей. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` ответ автоматически собирается из нескольких страниц Битрикс24 | | `select` | string | — | Выборка полей: `?select=id,name`. Возвращаются только перечисленные поля | | `sort` | string | — | Поле сортировки. Префикс `-` — по убыванию: `?sort=-id` | | `filter` | object | — | Фильтрация по полям `GET /v1/catalogs/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[iblockTypeId]=CRM_PRODUCT_CATALOG` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/catalogs" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/catalogs" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalogs', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Каталогов: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalogs', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив каталогов (все поля — см. [Поля каталога](/docs/entities/catalogs/fields)) | | `meta.total` | number | Общее количество каталогов, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | ## Пример ответа ```json { "success": true, "data": [ { "id": 25, "iblockId": 25, "iblockTypeId": "CRM_PRODUCT_CATALOG", "lid": "s1", "name": "Товарный каталог CRM", "productIblockId": null, "skuPropertyId": null, "subscription": "N", "vatId": 1, "yandexExport": false }, { "id": 27, "iblockId": 27, "iblockTypeId": "CRM_PRODUCT_CATALOG", "lid": "s1", "name": "Товарный каталог CRM (предложения)", "productIblockId": 25, "skuPropertyId": 101, "subscription": "N", "vatId": 1, "yandexExport": false } ], "meta": { "total": 2, "hasMore": false } } ``` ## Пример ответа при ошибке 400 — фильтр по несуществующему полю: ```json { "success": false, "error": { "code": "UNKNOWN_FILTER_FIELD", "message": "Unknown filter field 'nonExistentField' for entity 'catalogs'. Available: id, iblockId, iblockTypeId, lid, name, productIblockId, skuPropertyId, subscription, vatId, yandexExport" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет у каталога. Сообщение содержит список доступных полей | | 400 | `UNKNOWN_SORT_FIELD` | Сортировка по полю, которого нет у каталога | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Каталог товаров или каталог предложений.** Тип каталога в выдаче видно по полям `productIblockId` и `skuPropertyId`: у базового каталога товаров оба `null`; у каталога предложений они заполнены, причём `productIblockId` — это `iblockId` связанного каталога товаров. **Когда использовать search вместо list:** для условий по нескольким полям удобнее [`POST /v1/catalogs/search`](./search.md) — фильтр передаётся в теле запроса. ## Смотрите также - [Получить каталог](/docs/entities/catalogs/get) - [Поиск каталогов](/docs/entities/catalogs/search) - [Поля каталога](/docs/entities/catalogs/fields) - [Товары каталога](/docs/entities/catalog-products) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entities-index) --- # Catalogs: Search ## Поиск каталогов `POST /v1/catalogs/search` Поиск торговых каталогов с фильтрами. Аналог [`GET /v1/catalogs`](./list.md) с фильтрами, но через POST — удобнее для условий по нескольким полям. ## Поля запроса (body) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям `GET /v1/catalogs/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "iblockTypeId": "CRM_PRODUCT_CATALOG" }` | | `limit` | number | `50` | Количество записей (до 5000) | | `select` | string[] | — | Выборка полей: `["id", "name"]` | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/catalogs/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "iblockTypeId": "CRM_PRODUCT_CATALOG" }, "limit": 10 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/catalogs/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "iblockTypeId": "CRM_PRODUCT_CATALOG" }, "limit": 10 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalogs/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { iblockTypeId: 'CRM_PRODUCT_CATALOG' }, limit: 10, }), }) const { success, data, meta } = await res.json() console.log('Найдено:', meta.total) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/catalogs/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { iblockTypeId: 'CRM_PRODUCT_CATALOG' }, limit: 10, }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив каталогов (все поля — см. [Поля каталога](/docs/entities/catalogs/fields)) | | `meta.total` | number | Общее количество каталогов, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа ```json { "success": true, "data": [ { "id": 25, "iblockId": 25, "iblockTypeId": "CRM_PRODUCT_CATALOG", "lid": "s1", "name": "Товарный каталог CRM", "productIblockId": null, "skuPropertyId": null, "subscription": "N", "vatId": 1 }, { "id": 27, "iblockId": 27, "iblockTypeId": "CRM_PRODUCT_CATALOG", "lid": "s1", "name": "Товарный каталог CRM (предложения)", "productIblockId": 25, "skuPropertyId": 101, "subscription": "N", "vatId": 1 } ], "meta": { "total": 2, "hasMore": false, "durationMs": 142 } } ``` ## Пример ответа при ошибке 400 — фильтр по несуществующему полю: ```json { "success": false, "error": { "code": "UNKNOWN_FILTER_FIELD", "message": "Unknown filter field 'nonExistentField' for entity 'catalogs'. Available: id, iblockId, iblockTypeId, lid, name, productIblockId, skuPropertyId, subscription, vatId, yandexExport" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет у каталога. Сообщение содержит список доступных полей | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Каталог товаров или каталог предложений.** Тип каталога в выдаче видно по полям `productIblockId` и `skuPropertyId`: у базового каталога товаров оба `null`. У каталога предложений они заполнены, причём `productIblockId` — это `iblockId` связанного каталога товаров. **Когда использовать list вместо search:** для одного простого условия проще [`GET /v1/catalogs`](./list.md) с query-параметром `filter`. ## Смотрите также - [Список каталогов](/docs/entities/catalogs/list) - [Получить каталог](/docs/entities/catalogs/get) - [Поля каталога](/docs/entities/catalogs/fields) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entities-index) --- # Categories: Create ## Создать воронку `POST /v1/categories/:entityTypeId` Создаёт новую воронку для указанного типа CRM-сущности. Поля передаются плоско в корне JSON — без обёртки `fields`. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `entityTypeId` (path) | number | да | ID типа CRM-сущности. Для сделок `2`, для счетов `31`, для смарт-процесса — значение из [GET /v1/smart-processes](/docs/entities/smart-processes/list) | ## Поля запроса (body) | Поле | Битрикс24 | Тип | Обяз. | Описание | |------|-----------|-----|:-----:|---------| | `name` | `name` | string | да | Название воронки | | `sort` | `sort` | number | нет | Порядок сортировки среди воронок типа | ## Примеры В примерах `entityTypeId = 2` (сделки) — замените на нужный тип. ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/categories/2" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Воронка партнёров", "sort": 500 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/categories/2" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Воронка партнёров", "sort": 500 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/categories/2', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Воронка партнёров', sort: 500, }), }) const { success, data } = await res.json() console.log('ID воронки:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/categories/2', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Воронка партнёров', sort: 500, }), }) const { success, data } = await res.json() ``` ## Поля ответа Возвращается полный объект созданной воронки с присвоенным `id`. | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор созданной воронки | | `entityTypeId` | number | ID типа CRM-сущности, повторяет параметр пути | | `name` | string | Название воронки | | `sort` | number | Порядок сортировки | | `isDefault` | boolean | Признак основной воронки типа | | `originId` | string | Внешний идентификатор источника, пустая строка при отсутствии | | `originatorId` | string | Идентификатор внешней системы, пустая строка при отсутствии | ## Пример ответа ```json { "success": true, "data": { "id": 15, "name": "Воронка партнёров", "sort": 500, "entityTypeId": 2, "isDefault": false, "originId": "", "originatorId": "" } } ``` ## Пример ответа при ошибке 422 — не передано обязательное поле `name`: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Field 'NAME' is required." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `READONLY_FIELD` | Передано поле только для чтения — `code` или `isDefault`. Сообщение называет конкретное поле | | 422 | `BITRIX_ERROR` | Не передано обязательное поле `name` — сообщение `Field 'NAME' is required.` | | 404 | `ENTITY_NOT_FOUND` | `entityTypeId` не соответствует существующему типу — сообщение `Смарт-процесс не найден` | | 422 | `BITRIX_ERROR` | Тип сущности не поддерживает воронки, например предложения `7` — сообщение `Сущность CRM Предложение не поддерживается` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Поля `code` и `isDefault` — только чтение.** Передача `code` или `isDefault` в теле запроса возвращает `400 READONLY_FIELD` — уберите эти поля из запроса. Основная воронка типа назначается в интерфейсе Битрикс24. ## Смотрите также - [Список воронок](/docs/entities/categories/list) - [Обновить воронку](/docs/entities/categories/update) - [Удалить воронку](/docs/entities/categories/delete) - [Типы смарт-процессов](/docs/entities/smart-processes) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Categories: Delete ## Удалить воронку `DELETE /v1/categories/:entityTypeId/:id` Удаляет воронку указанного типа CRM-сущности по идентификатору. Восстановить удалённую воронку через API нельзя — создавайте новую при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `entityTypeId` (path) | number | да | ID типа CRM-сущности. Для сделок `2`, для счетов `31`, для смарт-процесса — значение из [GET /v1/smart-processes](/docs/entities/smart-processes/list) | | `id` (path) | number | да | Идентификатор воронки | ## Примеры В примерах `entityTypeId = 2` (сделки), `id = 15` — замените на ваши значения. ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/categories/2/15" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/categories/2/15" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/categories/2/15', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) if (res.status === 204) { console.log('Воронка удалена') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/categories/2/15', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — воронка с указанным `id` не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Воронка с указанным `id` не найдена — сообщение `Элемент не найден` | | 404 | `ENTITY_NOT_FOUND` | `entityTypeId` не соответствует существующему типу — сообщение `Смарт-процесс не найден` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список воронок](/docs/entities/categories/list) - [Получить воронку](/docs/entities/categories/get) - [Создать воронку](/docs/entities/categories/create) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Categories: Fields ## Поля воронки `GET /v1/categories/:entityTypeId/fields` Возвращает схему полей воронки для указанного типа CRM-сущности: имена, типы и признак «только чтение». ## Параметры | Параметр | Тип | Описание | |----------|-----|---------| | `entityTypeId` (path) | number | ID типа CRM-сущности. Сделки — `2`, счета — `31`, смарт-процессы — из `GET /v1/smart-processes` | ## Примеры В примерах `entityTypeId = 2` (сделки) — замените на нужный тип. ### curl — личный ключ ```bash curl -X GET https://vibecode.bitrix24.tech/v1/categories/2/fields \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X GET https://vibecode.bitrix24.tech/v1/categories/2/fields \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/categories/2/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data.fields).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/categories/2/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Битрикс24 | Тип | RO | Описание | |------|-----------|-----|:---:|---------| | `id` | id | number | RO | ID воронки. Для сделок основная воронка имеет id `0` | | `entityTypeId` | entityTypeId | number | RO | ID типа CRM-сущности, повторяет параметр пути | | `name` | name | string | | Название воронки. Обязательно при создании | | `sort` | sort | number | | Порядок сортировки | | `isDefault` | isDefault | boolean | RO | Признак основной воронки. Только чтение — запись отклоняется с `400 READONLY_FIELD` | | `code` | code | string | RO | Символьный код. Только чтение — запись отклоняется с `400 READONLY_FIELD`. В ответах `list`, `get` и `search` не возвращается | | `createdDate` | createdDate | datetime | RO | Дата создания. Не возвращается в ответах `list`, `get` | | `originId` | ORIGIN_ID | string | | Внешний идентификатор | | `originatorId` | ORIGINATOR_ID | string | | Источник внешней привязки | Поле `batch` перечисляет операции, доступные через [Batch-запросы](/docs/batch): `create`, `update`, `delete`. ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true }, "entityTypeId": { "type": "number", "readonly": true }, "name": { "type": "string", "readonly": false }, "sort": { "type": "number", "readonly": false }, "isDefault": { "type": "boolean", "readonly": true }, "code": { "type": "string", "readonly": true }, "createdDate": { "type": "datetime", "readonly": true }, "originId": { "type": "string", "readonly": false, "label": "ORIGIN_ID" }, "originatorId": { "type": "string", "readonly": false, "label": "ORIGINATOR_ID" } }, "batch": ["create", "update", "delete"] } } ``` ## Пример ответа при ошибке 404 — тип не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Смарт-процесс не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | `entityTypeId` не соответствует существующему типу CRM | | 422 | `BITRIX_ERROR` | Тип CRM не поддерживает воронки. Предложения `7` воронок не имеют | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список воронок](/docs/entities/categories/list) - [Создать воронку](/docs/entities/categories/create) - [Получить воронку](/docs/entities/categories/get) - [Типы смарт-процессов](/docs/entities/smart-processes) - [Entity API](/docs/entity-api) --- # Categories: Get ## Получить воронку `GET /v1/categories/:entityTypeId/:id` Возвращает одну воронку по ID в рамках указанного типа CRM-сущности. ## Параметры | Параметр | Тип | Описание | |----------|-----|---------| | `entityTypeId` (path) | number | ID типа CRM-сущности. Сделки — `2`, счета — `31`, смарт-процессы — из `GET /v1/smart-processes` | | `id` (path) | number | ID воронки. Список: `GET /v1/categories/:entityTypeId` | ## Примеры В примерах `entityTypeId = 2`, `id = 1` — замените на ваши значения. ### curl — личный ключ ```bash curl -X GET https://vibecode.bitrix24.tech/v1/categories/2/1 \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X GET https://vibecode.bitrix24.tech/v1/categories/2/1 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/categories/2/1', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() console.log('Воронка:', data.name) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/categories/2/1', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | ID воронки. Для сделок основная воронка имеет id `0` | | `data.name` | string | Название воронки | | `data.sort` | number | Порядок сортировки | | `data.entityTypeId` | number | ID типа CRM-сущности, повторяет параметр пути | | `data.isDefault` | boolean | Признак основной воронки типа | | `data.originId` | string | Внешний идентификатор. Пустая строка у воронок без внешней привязки | | `data.originatorId` | string | Источник внешней привязки. Пустая строка у воронок без неё | Для основной воронки сделок (id `0`) поля `originId` и `originatorId` в ответе отсутствуют. Стадии воронки запрашиваются отдельно: `GET /v1/statuses?filter[entityId]=DEAL_STAGE_{id}`. ## Пример ответа ```json { "success": true, "data": { "id": 1, "name": "Newest", "sort": 100, "entityTypeId": 2, "isDefault": false, "originId": "", "originatorId": "" } } ``` Основная воронка сделок (id `0`) приходит без `originId` и `originatorId`: ```json { "success": true, "data": { "id": 0, "name": "Общая", "sort": 300, "entityTypeId": 2, "isDefault": true } } ``` ## Пример ответа при ошибке 404 — воронка не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Воронки с указанным `id` нет в этом типе | | 404 | `ENTITY_NOT_FOUND` | `entityTypeId` не соответствует существующему типу CRM | | 422 | `BITRIX_ERROR` | Тип CRM не поддерживает воронки. Предложения `7` воронок не имеют | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список воронок](/docs/entities/categories/list) - [Обновить воронку](/docs/entities/categories/update) - [Поля воронки](/docs/entities/categories/fields) - [Типы смарт-процессов](/docs/entities/smart-processes) - [Стадии и статусы](/docs/entities/statuses) - [Entity API](/docs/entity-api) --- # Categories: List ## Список воронок `GET /v1/categories/:entityTypeId` Возвращает все воронки указанного типа CRM-сущности. Параметры `filter`, `select` и `order` принимаются без ошибки, но не влияют на результат — в ответ всегда приходит полный набор воронок типа. ## Параметры | Параметр | Тип | Описание | |----------|-----|---------| | `entityTypeId` (path) | number | ID типа CRM-сущности. Сделки — `2`, счета — `31`, смарт-процессы — из `GET /v1/smart-processes` | ## Примеры В примерах `entityTypeId = 2` (сделки) — замените на нужный тип. ### curl — личный ключ ```bash curl -X GET https://vibecode.bitrix24.tech/v1/categories/2 \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X GET https://vibecode.bitrix24.tech/v1/categories/2 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/categories/2', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() console.log(`Воронок: ${data.length}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/categories/2', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив воронок типа | | `data[].id` | number | ID воронки. Для сделок основная воронка имеет id `0` | | `data[].name` | string | Название воронки | | `data[].sort` | number | Порядок сортировки | | `data[].entityTypeId` | number | ID типа CRM-сущности, повторяет параметр пути | | `data[].isDefault` | boolean | Признак основной воронки типа | | `data[].originId` | string | Внешний идентификатор. Пустая строка у воронок без внешней привязки | | `data[].originatorId` | string | Источник внешней привязки. Пустая строка у воронок без неё | | `meta.total` | number | Количество воронок в ответе | | `meta.hasMore` | boolean | Всегда `false` — список возвращается целиком | Для основной воронки сделок (id `0`) поля `originId` и `originatorId` в ответе отсутствуют. Стадии воронки запрашиваются отдельно: `GET /v1/statuses?filter[entityId]=DEAL_STAGE_{id}`. ## Пример ответа Ответ всегда содержит `meta`. У дополнительных воронок сделок есть `originId` и `originatorId`, у основной воронки (id `0`) их нет: ```json { "success": true, "data": [ { "id": 1, "name": "Newest", "sort": 100, "entityTypeId": 2, "isDefault": false, "originId": "", "originatorId": "" }, { "id": 11, "name": "English", "sort": 200, "entityTypeId": 2, "isDefault": false, "originId": "", "originatorId": "" }, { "id": 0, "name": "Общая", "sort": 300, "entityTypeId": 2, "isDefault": true } ], "meta": { "total": 3, "hasMore": false } } ``` У воронок смарт-процесса набор полей короче: ```json { "success": true, "data": [ { "id": 3, "name": "Общее", "sort": 500, "entityTypeId": 174, "isDefault": true }, { "id": 23, "name": "Доп воронка", "sort": 510, "entityTypeId": 174, "isDefault": false } ], "meta": { "total": 2, "hasMore": false } } ``` ## Пример ответа при ошибке 404 — тип не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Смарт-процесс не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | `entityTypeId` не соответствует существующему типу CRM | | 422 | `BITRIX_ERROR` | Тип CRM не поддерживает воронки. Предложения `7` воронок не имеют | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить воронку](/docs/entities/categories/get) - [Создать воронку](/docs/entities/categories/create) - [Поля воронки](/docs/entities/categories/fields) - [Типы смарт-процессов](/docs/entities/smart-processes) - [Стадии и статусы](/docs/entities/statuses) - [Entity API](/docs/entity-api) --- # Categories: Update ## Обновить воронку `PATCH /v1/categories/:entityTypeId/:id` Обновляет поля существующей воронки указанного типа CRM-сущности. Передавайте только изменяемые поля плоско в корне JSON — без обёртки `fields`. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `entityTypeId` (path) | number | да | ID типа CRM-сущности. Для сделок `2`, для счетов `31`, для смарт-процесса — значение из [GET /v1/smart-processes](/docs/entities/smart-processes/list) | | `id` (path) | number | да | Идентификатор воронки | ## Поля для обновления (body) | Поле | Битрикс24 | Тип | Описание | |------|-----------|-----|---------| | `name` | `name` | string | Название воронки | | `sort` | `sort` | number | Порядок сортировки среди воронок типа | ## Примеры В примерах `entityTypeId = 2` (сделки), `id = 15` — замените на ваши значения. ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/categories/2/15" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Воронка партнёров — обновлено", "sort": 700 }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/categories/2/15" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Воронка партнёров — обновлено", "sort": 700 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/categories/2/15', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Воронка партнёров — обновлено', sort: 700, }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/categories/2/15', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Воронка партнёров — обновлено', sort: 700, }), }) const { success, data } = await res.json() ``` ## Поля ответа Возвращается полный объект воронки с применёнными изменениями. | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор воронки | | `entityTypeId` | number | ID типа CRM-сущности, повторяет параметр пути | | `name` | string | Название воронки | | `sort` | number | Порядок сортировки | | `isDefault` | boolean | Признак основной воронки типа | | `originId` | string | Внешний идентификатор источника, пустая строка при отсутствии | | `originatorId` | string | Идентификатор внешней системы, пустая строка при отсутствии | ## Пример ответа ```json { "success": true, "data": { "id": 15, "name": "Воронка партнёров — обновлено", "sort": 700, "entityTypeId": 2, "isDefault": false, "originId": "", "originatorId": "" } } ``` ## Пример ответа при ошибке 404 — воронка с указанным `id` не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `READONLY_FIELD` | Передано поле только для чтения — `code` или `isDefault`. Сообщение называет конкретное поле | | 404 | `ENTITY_NOT_FOUND` | Воронка с указанным `id` не найдена — сообщение `Элемент не найден` | | 404 | `ENTITY_NOT_FOUND` | `entityTypeId` не соответствует существующему типу — сообщение `Смарт-процесс не найден` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Поля `code` и `isDefault` — только чтение.** Передача `code` или `isDefault` в теле запроса возвращает `400 READONLY_FIELD` — уберите эти поля из запроса. Основная воронка типа назначается в интерфейсе Битрикс24. ## Смотрите также - [Получить воронку](/docs/entities/categories/get) - [Список воронок](/docs/entities/categories/list) - [Создать воронку](/docs/entities/categories/create) - [Удалить воронку](/docs/entities/categories/delete) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Companies: Aggregate ## Агрегация компаний `POST /v1/companies/aggregate` Подсчёт количества, сумма, среднее, минимум и максимум по компаниям с фильтрацией и группировкой. **Стандартные поля:** - `revenue` — годовая выручка (числовое агрегирование имеет смысл) - `typeId` — тип компании (для `groupBy`) - `industry` — отрасль (для `groupBy`) - `assignedById` — ответственный (для `groupBy`) - `sourceId` — источник (для `groupBy`) **Пользовательские поля (UF):** UF-поля типов `integer`, `double`, `money` — для числовых функций; UF любого типа — для `groupBy`. Полный список UF-полей конкретного портала приходит в тексте ошибки `INVALID_PARAMS`, если передать несуществующее имя. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций. Каждый элемент: `{ "field": "revenue", "function": "sum" }`. Функции: `count`, `sum`, `avg`, `min`, `max`. Для `count` поле — `"*"`. Без массива — только `count` | | `filter` | object | нет | Фильтрация по полям `GET /v1/companies/fields`. [Синтаксис фильтрации](/docs/filtering) | | `groupBy` | string \| string[] | нет | Поле или массив полей для группировки (максимум 5). Допустимые значения — из списка выше | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/companies/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "revenue", "function": "sum" }, { "field": "revenue", "function": "avg" } ], "filter": { "typeId": "CUSTOMER" }, "groupBy": "industry" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/companies/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "revenue", "function": "sum" }, { "field": "revenue", "function": "avg" } ], "filter": { "typeId": "CUSTOMER" }, "groupBy": "industry" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/companies/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [ { field: 'revenue', function: 'sum' }, { field: 'revenue', function: 'avg' }, ], filter: { typeId: 'CUSTOMER' }, groupBy: 'industry', }), }) const { success, data } = await res.json() console.log('Всего компаний:', data.count) console.log('По отраслям:', data.groups) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/companies/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [ { field: 'revenue', function: 'sum' }, { field: 'revenue', function: 'avg' }, ], filter: { typeId: 'CUSTOMER' }, groupBy: 'industry', }), }) const { success, data } = await res.json() ``` > Для группировки по нескольким полям передайте массив: `"groupBy": ["industry", "typeId"]` (максимум 5). ## Другие сценарии Подсчёт записей — `count` с полем `"*"`, самый быстрый запрос без выгрузки записей. Без массива `aggregate` результат тот же: ```json { "aggregate": [{ "field": "*", "function": "count" }] } ``` Работа с пользовательскими полями (UF) — `sum` по UF + группировка по другому UF: ```json { "aggregate": [{ "field": "UF_CRM_BUDGET", "function": "sum" }], "groupBy": "UF_CRM_SEGMENT" } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Общее количество записей под фильтр | | `data.aggregates` | object | Результаты агрегаций: `{ "revenue": { "sum": 3000000, "avg": 50000 } }` | | `data.groups` | array | Группы (только при `groupBy`). Каждый элемент: поля группировки + `count` + `aggregates` | | `data.meta.totalRecords` | number | Общее количество записей под фильтр | | `data.meta.recordsProcessed` | number | Сколько записей обработано для числовых агрегаций (максимум 5000) | | `data.meta.truncated` | boolean | `true`, если под фильтр попало больше 5000 записей | ## Пример ответа Ответ на основной запрос (агрегации + `groupBy: "industry"`): ```json { "success": true, "data": { "count": 60, "aggregates": { "revenue": { "sum": 3000000, "avg": 50000 } }, "groups": [ { "industry": "IT", "count": 35, "aggregates": { "revenue": { "sum": 2000000 } } }, { "industry": "RETAIL", "count": 25, "aggregates": { "revenue": { "sum": 1000000 } } } ], "meta": { "totalRecords": 60, "recordsProcessed": 60, "truncated": false } } } ``` Без `groupBy` поле `data.groups` в ответе отсутствует. ## Пример ответа при ошибке 400 — неверное имя функции, несуществующее поле или `groupBy` по неаггрегируемому полю: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "Field 'foo' not found. Available numeric fields: typeId, industry, revenue, assignedById, sourceId" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Некорректное имя функции, несуществующее поле, нечисловое поле в `sum`/`avg`/`min`/`max`, `groupBy` по неаггрегируемому полю или больше 5 полей в `groupBy` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`count` vs числовые функции.** `count` считается одним вызовом в Битрикс24 на любом объёме данных. Функции `sum`/`avg`/`min`/`max` подгружают записи постранично (максимум 5000) и считают на стороне Вайбкод — если под фильтр попадает больше 5000 записей, `meta.truncated` будет `true`, агрегация выполнится по первым 5000. Для точных счётчиков на больших выборках используйте `count` или сужайте фильтр. **Money-поля.** UF-поля типа `money` хранятся в формате `"сумма|валюта"` (`"1500|RUB"`) — агрегат извлекает числовую часть автоматически, складывать можно без парсинга. **Фильтрация по UF работает.** В `filter` можно передавать любые поля — стандартные и пользовательские, любого типа. Например, `{ "filter": { "ufCrm_1234": "value" } }` вернёт количество компаний с этим значением UF. ## Смотрите также - [Список компаний](/docs/entities/companies/list) - [Поиск компаний](/docs/entities/companies/search) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Companies: Create ## Создать компанию `POST /v1/companies` Создаёт новую компанию в CRM. ## Поля запроса (body) | Параметр | Тип | Описание | |----------|-----|---------| | `title` | string | Название компании | | `typeId` | string | Тип компании: `CUSTOMER`, `SUPPLIER`, `COMPETITOR`. Список значений: `GET /v1/statuses?filter[entityId]=COMPANY_TYPE` | | `industry` | string | Отрасль: `IT`, `TELECOM`, `MANUFACTURING` и др. Список: `GET /v1/statuses?filter[entityId]=INDUSTRY` | | `revenue` | number | Годовой оборот | | `currencyId` | string | Валюта оборота. Список: `GET /v1/currencies` | | `phone` | string \| string[] \| object[] | Телефон. Принимает три формы: строка `"+7..."`, массив строк `["+7...", "+7..."]`, или массив объектов `[{ "value": "+7...", "typeId": "WORK" }, …]`. `typeId`: `WORK \| HOME \| MOBILE \| OTHER` (по умолчанию `WORK`). ⚠ UPPER-форма `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` **не принимается** — вернёт `400 INVALID_MULTIFIELD_SHAPE`. Используйте camelCase: `[{ "value": "...", "typeId": "WORK" }]` | | `email` | string \| string[] \| object[] | Email. Принимает три формы: строка `"a@b.com"`, массив строк `["a@b.com", "b@c.com"]`, или массив объектов `[{ "value": "a@b.com", "typeId": "WORK" }, …]`. `typeId`: `WORK \| HOME \| MAILING \| OTHER` (по умолчанию `WORK`). ⚠ UPPER-форма `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` **не принимается** — вернёт `400 INVALID_MULTIFIELD_SHAPE`. Используйте camelCase: `[{ "value": "...", "typeId": "WORK" }]` | | `web` | string \| string[] \| object[] | Веб-сайт. Принимает три формы: строка `"https://acme.com"`, массив строк, или массив объектов `[{ "value": "https://...", "typeId": "WORK" }]`. `typeId`: `WORK \| HOME \| OTHER` (по умолчанию `WORK`). ⚠ UPPER-форма `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` **не принимается** — вернёт `400 INVALID_MULTIFIELD_SHAPE`. Используйте camelCase: `[{ "value": "...", "typeId": "WORK" }]` | | `comments` | string | Комментарий | | `sourceId` | string | Источник. Список: `GET /v1/statuses?filter[entityId]=SOURCE` | | `sourceDescription` | string | Описание источника | | `assignedById` | number | Ответственный. Список: `GET /v1/users` | | `opened` | boolean | Доступна для всех | | `leadId` | number | ID лида, из которого создана компания | Полный список полей: [GET /v1/companies/fields](/docs/entities/companies/fields). ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/companies \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "ООО Ромашка", "typeId": "CUSTOMER", "industry": "IT", "phone": "+74951234567", "email": "info@romashka.ru", "web": "https://romashka.ru" }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/companies \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "ООО Ромашка", "typeId": "CUSTOMER", "industry": "IT", "phone": "+74951234567", "email": "info@romashka.ru", "web": "https://romashka.ru" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/companies', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'ООО Ромашка', typeId: 'CUSTOMER', industry: 'IT', phone: '+74951234567', email: 'info@romashka.ru', web: 'https://romashka.ru', }), }) const { success, data } = await res.json() console.log('Company ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/companies', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'ООО Ромашка', typeId: 'CUSTOMER', industry: 'IT', phone: '+74951234567', email: 'info@romashka.ru', web: 'https://romashka.ru', }), }) const { success, data } = await res.json() ``` ### Альтернативная форма — массив объектов с явным `typeId` Если нужно указать несколько значений или явный тип (`HOME`, `OTHER`): ```json { "phone": [ { "value": "+74951234567", "typeId": "WORK" }, { "value": "+74951112233", "typeId": "OTHER" } ], "email": [ { "value": "info@romashka.ru", "typeId": "WORK" }, { "value": "sales@romashka.ru", "typeId": "MAILING" } ], "web": [ { "value": "https://romashka.ru", "typeId": "WORK" }, { "value": "https://shop.romashka.ru", "typeId": "OTHER" } ] } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID созданной компании | | `title` | string | Название | | `typeId` | string | Тип компании | | `industry` | string | Отрасль | | `assignedById` | number | Ответственный | | `createdBy` | number | Создатель | | `createdTime` | datetime | Дата создания | | `updatedTime` | datetime | Дата изменения | Ответ содержит все поля компании, включая пользовательские (`ufCrm_*`). URL карточки компании в Битрикс24 строится из `id`: ``` https://.bitrix24.ru/crm/company/details// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": { "id": 2923, "title": "ООО Ромашка", "typeId": "CUSTOMER", "industry": "IT", "revenue": 0, "currencyId": "RUB", "assignedById": 1, "createdBy": 1, "createdTime": "2026-04-15T12:53:59+03:00", "updatedTime": "2026-04-15T12:53:59+03:00", "opened": true } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 400 | `INVALID_REQUEST` | Невалидные поля | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Работа с файлами в полях CRM](/docs/recipes/crm-files) - [Список компаний](/docs/entities/companies/list) - [Поля компании](/docs/entities/companies/fields) - [Поиск дубликатов](/docs/duplicates) - [Контакты](/docs/entities/contacts) - [Сделки](/docs/entities/deals) - [Entity API](/docs/entity-api) - [Лимиты и оптимизация](/docs/optimization) --- # Companies: Delete ## Удалить компанию `DELETE /v1/companies/:id` Удаляет компанию по ID. Восстановить удалённую компанию через API нельзя — создавайте новую при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID компании | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/companies/2923" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/companies/2923" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/companies/2923', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Компания удалена') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/companies/2923', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — компания не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Компания не найдена | | 403 | `ACCESS_DENIED` | Нет доступа | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список компаний](/docs/entities/companies/list) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Companies: Fields ## Поля компании `GET /v1/companies/fields` Возвращает полный список доступных полей, включая пользовательские (`ufCrm_*`). ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/companies/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/companies/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/companies/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/companies/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | RO | Описание | |------|-----|:--:|---------| | `id` | number | да | ID компании | | `title` | string | | Название | | `typeId` | string | | Тип компании: `CUSTOMER`, `SUPPLIER`, `COMPETITOR`. Список значений: `GET /v1/statuses?filter[entityId]=COMPANY_TYPE` | | `industry` | string | | Отрасль. Список: `GET /v1/statuses?filter[entityId]=INDUSTRY` | | `revenue` | number | | Годовой оборот | | `currencyId` | string | | Валюта. Список: `GET /v1/currencies` | | `phone` | multifield | | Телефон. На вход (POST/PATCH) принимает `string \| string[] \| object[]`. На выходе `phone` — строка с первичным значением, значения по типам — в полях `phoneWork`/`phoneMobile`, полный перечень с типами — в массиве `fm[]` (формат `{ id, typeId, valueType, value }`). ⚠ PATCH **только добавляет** новые записи — старые `phone` не удаляются. См. [Обновить компанию](/docs/entities/companies/update). ⚠ UPPER-форма `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` **не принимается** — вернёт `400 INVALID_MULTIFIELD_SHAPE`. Используйте camelCase: `[{ "value": "...", "typeId": "WORK" }]`. | | `email` | multifield | | Email. На вход принимает `string \| string[] \| object[]`. На выходе `email` — строка с первичным значением, значения по типам — в полях `emailWork`/`emailHome`/`emailMailing`, полный перечень — в массиве `fm[]`. ⚠ PATCH **только добавляет** новые записи — старые `email` не удаляются. ⚠ UPPER-форма `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` **не принимается** — вернёт `400 INVALID_MULTIFIELD_SHAPE`. Используйте camelCase: `[{ "value": "...", "typeId": "WORK" }]`. | | `web` | multifield | | Сайт. На вход принимает `string \| string[] \| object[]`. На выходе `web` — строка с первичным значением, значения по типам — в поле `webWork`, полный перечень — в массиве `fm[]`. ⚠ PATCH **только добавляет** новые записи — старые `web` не удаляются. ⚠ UPPER-форма `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` **не принимается** — вернёт `400 INVALID_MULTIFIELD_SHAPE`. Используйте camelCase: `[{ "value": "...", "typeId": "WORK" }]`. | | `hasPhone` | boolean | да | Указан ли телефон | | `hasEmail` | boolean | да | Указан ли email | | `hasImol` | boolean | да | Есть ли контакт в открытой линии | | `comments` | string | | Комментарий | | `sourceId` | string | | Источник. Список: `GET /v1/statuses?filter[entityId]=SOURCE` | | `sourceDescription` | string | | Описание источника | | `assignedById` | number | | Ответственный. Список: `GET /v1/users` | | `createdBy` | number | да | Создатель. Поиск: `GET /v1/users` | | `updatedBy` | number | да | Кто изменил. Поиск: `GET /v1/users` | | `createdTime` | datetime | да | Дата создания | | `updatedTime` | datetime | да | Дата изменения | | `opened` | boolean | | Доступна для всех | | `leadId` | number | | ID лида-источника | | `entityTypeId` | number | да | ID типа CRM-сущности; у компании всегда `4` | | `emailWork` | string \| null | да | Рабочий e-mail из мультиполя `email`. Записывается через `email` | | `emailHome` | string \| null | да | Личный e-mail из мультиполя `email`. Записывается через `email` | | `emailMailing` | string \| null | да | E-mail для рассылок из мультиполя `email`. Записывается через `email` | | `phoneWork` | string \| null | да | Рабочий телефон из мультиполя `phone`. Записывается через `phone` | | `phoneMobile` | string \| null | да | Мобильный телефон из мультиполя `phone`. Записывается через `phone` | | `phoneMailing` | string \| null | да | Телефон для рассылок из мультиполя `phone`. Записывается через `phone` | | `imol` | string \| null | да | Контакт в открытой линии из коллекции мультиполей | | `address` | string \| null | да | Фактический адрес одной строкой. Правится в реквизитах компании | | `addressLegal` | string \| null | да | Юридический адрес одной строкой. Правится в реквизитах компании | | `searchContent` | string \| null | да | **Служебное поле.** Строка, которую Битрикс24 склеивает из текста карточки для своего полнотекстового поиска. Фильтр по ней принимается, но опираться на него не стоит: состав может меняться без предупреждения. Показывать человеку тоже не следует | Одиннадцать полей выше приходят в данных `list`/`get`, но записать их напрямую нельзя: Битрикс24 отвечает успехом и значение не сохраняет, поэтому платформа отклоняет их с `400 READONLY_FIELD`. Адреса правятся в реквизитах компании, телефоны и адреса e-mail — через мультиполя `phone` и `email`. **Пользовательские поля** (`ufCrm_*`) также возвращаются и принимаются. Набор таких полей свой на каждом портале, поэтому в статическую схему они не входят — их описания приходят от Битрикс24. ## Доступные include Эндпоинт `GET /v1/companies/fields` возвращает список доступных include: `requisite`. Пример использования: [Получить companies](/docs/entities/companies/get#связанные-данные). Подробнее об include: [Связанные данные](/docs/includes). ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "ID", "description": "Идентификатор компании." }, "title": { "type": "string", "readonly": false, "label": "Название", "description": "Название компании." }, "assignedById": { "type": "number", "readonly": false, "label": "Ответственный", "description": "Ответственный за компанию сотрудник." } }, "batch": ["create", "update", "delete"] } } ``` Показаны 3 из множества полей. Полный список в таблице выше. Каждое поле, помимо `type` и `readonly`, содержит `label` (понятное человеку название) и `description` (краткое описание) на русском языке. ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать компанию](/docs/entities/companies/create) - [Пользовательские поля](/docs/userfields) - [Entity API](/docs/entity-api) - [Лимиты и оптимизация](/docs/optimization) --- # Companies: Get ## Получить компанию `GET /v1/companies/:id` Возвращает компанию по ID. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID компании | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/companies/1" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/companies/1" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/companies/1', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Компания:', data.title) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/companies/1', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` Подробнее об include: [Связанные данные](/docs/includes). ## Поля ответа Объект компании со всеми полями — см. [Поля компании](/docs/entities/companies/fields). ## Связанные данные (include) ``` GET /v1/companies/1?include=requisite ``` Доступные include: `requisite`. Результат в поле `_included`. ## Пример ответа ```json { "success": true, "data": { "id": 1, "title": "ЗАО Ложки", "industry": "IT", "typeId": "CUSTOMER", "assignedById": 1, "phone": "+70000000001", "phoneWork": "+70000000001", "email": "info@example.com", "emailWork": "info@example.com", "emailHome": "home@example.com", "hasPhone": true, "hasEmail": true, "fm": [ { "id": 65, "typeId": "PHONE", "valueType": "WORK", "value": "+70000000001" }, { "id": 67, "typeId": "EMAIL", "valueType": "WORK", "value": "info@example.com" }, { "id": 69, "typeId": "EMAIL", "valueType": "HOME", "value": "home@example.com" } ], "createdTime": "2020-05-08T10:48:20+03:00", "updatedTime": "2025-08-22T13:01:31+03:00" } } ``` Телефон и почта в ответе — строки с первичным значением, значения по типам — в полях `phoneWork`, `phoneMobile`, `emailWork`, `emailHome`. Полный перечень с типами — в массиве `fm[]` (`{ id, typeId, valueType, value }`, где `id` — идентификатор записи). Наличие проверяйте по `hasPhone`/`hasEmail`: при отсутствии телефона `phone` приходит пустой строкой. Отдельную запись `fm[]` по её `id` через API не изменить и не удалить — PATCH добавляет новые записи. ## Пример ответа при ошибке 404 — компания не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Компания не найдена | | 403 | `ACCESS_DENIED` | Нет доступа | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Работа с файлами в полях CRM](/docs/recipes/crm-files) - [Обновить компанию](/docs/entities/companies/update) - [Поля компании](/docs/entities/companies/fields) - [Контакты](/docs/entities/contacts) - [Лимиты и оптимизация](/docs/optimization) --- # Companies: List ## Список компаний `GET /v1/companies` Возвращает список компаний с фильтрацией, сортировкой и авто-пагинацией. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей. Для обхода всей коллекции дешевле курсор — `order[id]=asc` и `filter[>id]` из `meta.nextAfterId` | | `select` | string | — | Выборка полей: `?select=id,title,phone,industry` | | `order` | object | — | Сортировка: `?order[title]=asc` | | `filter` | object | — | Фильтрация по полям `GET /v1/companies/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[industry]=IT` | | `withTotal` | string | — | Нужно ли количество: `true` или `false`. `false` — не заказывать подсчёт. Это единственный способ гарантированно убрать `meta.total` из ответа. Без параметра — настройка ключа, затем платформенное умолчание, и тогда на короткой странице точное количество приходит и без заказа. [Листание и количество](/docs/entity-api#листание-и-количество-записей) | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/companies?limit=10&filter[industry]=IT&select=id,title,phone" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/companies?limit=10&filter[industry]=IT&select=id,title,phone" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/companies?limit=10&filter[industry]=IT', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} компаний`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/companies?limit=10&filter[industry]=IT', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив компаний (поля — см. [Поля](/docs/entities/companies/fields)) | | `meta.total` | number | Общее количество записей. Необязательное поле: если количество не заказывалось, его в ответе нет | | `meta.hasMore` | boolean | Есть ещё записи | | `meta.nextAfterId` | string | Идентификатор последней отданной записи. Приходит при сортировке строго по `id` по возрастанию, пока `hasMore` равен `true`. Передайте его обратно как `filter[>id]` — это дешёвая замена растущему `offset` | URL карточки любой компании из массива `data` — её `id`: ``` https://.bitrix24.ru/crm/company/details// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 1, "title": "ЗАО \"Ложки\"", "phone": "+15555555555", "email": "info@lozzka.ru", "assignedById": 1, "industry": "IT" } ], "meta": { "total": 1430, "hasMore": true } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Фильтр по телефону подходит не для всякого поиска.** Значение без оператора сравнивается со всей сохранённой строкой: компания с номером `+7 (999) 123-45-67` найдётся по этой же строке и не найдётся по `79991234567`, потому что плюс, пробелы, скобки и дефисы — часть значения. Вдобавок фильтр видит только первый номер записи: если записаны рабочий и мобильный, по мобильному он вернёт пустой список. Чтобы найти компанию по номеру телефона в любом написании и по любому из его номеров, используйте [Поиск дубликатов](/docs/duplicates). **Когда использовать поиск.** Для составных условий подходит `POST /v1/companies/search`. См. [Поиск компаний](/docs/entities/companies/search). ## Смотрите также - [Поиск компаний](/docs/entities/companies/search) - [Создать компанию](/docs/entities/companies/create) - [Поиск дубликатов](/docs/duplicates) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Companies: Search ## Поиск компаний `POST /v1/companies/search` Поиск компаний по условиям в теле запроса. Принимает те же фильтры, что и список компаний, и рассчитан на составные условия и большие выборки. ## Поля запроса (body) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям `GET /v1/companies/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "industry": "IT" }` | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки» | | `order` | object | — | Сортировка: `{ "title": "asc" }` | | `select` | string[] | — | Выборка полей | | `autoWindow` | boolean | `true` | Разбивать выборку по недельным окнам при фильтре по диапазону дат шире 14 дней. `false` отключает разбиение | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/companies/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "industry": "IT" }, "limit": 10 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/companies/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "industry": "IT" }, "limit": 10 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/companies/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { industry: 'IT' }, limit: 10, }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/companies/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { industry: 'IT' }, limit: 10, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив компаний (поля — см. [Поля](/docs/entities/companies/fields)) | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.nextAfterId` | string | Идентификатор последней отданной записи. Приходит при сортировке строго по `id` по возрастанию, пока `hasMore` равен `true`. Передайте его обратно в фильтр `>id` — это дешёвая замена растущему `offset` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временны́м окнам | | `meta.windowCount` | number | Число окон. Приходит при `autoWindowed: true` | | `meta.batchWaves` | number | Число волн параллельных запросов. Приходит при `autoWindowed: true` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. URL карточки любой компании из массива `data` — её `id`: ``` https://.bitrix24.ru/crm/company/details// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 1, "title": "ЗАО \"Ложки\"", "industry": "IT", "assignedById": 1 } ], "meta": { "total": 74, "hasMore": true, "durationMs": 537 } } ``` С фильтром по диапазону дат шире 14 дней в `meta` дополнительно приходят `autoWindowed`, `windowCount` и `batchWaves`: ```json { "success": true, "data": [ /* ... */ ], "meta": { "total": 8, "hasMore": true, "autoWindowed": true, "windowCount": 131, "batchWaves": 3, "durationMs": 1494 } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Разбиение по временны́м окнам.** Фильтр по диапазону дат шире 14 дней автоматически разбивается на недельные окна, которые выполняются параллельными волнами — так выборка обходит потолок в 5000 записей на один вызов. В `meta` тогда приходят `autoWindowed: true`, число окон `windowCount` и число волн `batchWaves`. Отключает разбиение параметр `autoWindow: false`. При активном разбиении `offset` больше нуля отклоняется с `UNSTABLE_OFFSET_PAGINATION`. **Фильтр по телефону подходит не для всякого поиска.** Значение без оператора сравнивается со всей сохранённой строкой: компания с номером `+7 (999) 123-45-67` найдётся по этой же строке и не найдётся по `79991234567`, потому что плюс, пробелы, скобки и дефисы — часть значения. Вдобавок фильтр видит только первый номер записи: если записаны рабочий и мобильный, по мобильному он вернёт пустой список. Чтобы найти компанию по номеру телефона в любом написании и по любому из его номеров, используйте [Поиск дубликатов](/docs/duplicates). Оператор `$contains` при этом работает — он ищет кусок текста внутри значения, это рабочий способ для почты: `{ "email": { "$contains": "@example.com" } }`. ## Смотрите также - [Список компаний](/docs/entities/companies/list) - [Поиск дубликатов](/docs/duplicates) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Companies: Update ## Обновить компанию `PATCH /v1/companies/:id` Обновляет поля компании. Передайте только изменяемые поля. Полный список в [справочнике полей](/docs/entities/companies/fields), включая пользовательские (`ufCrm_*`). > ⚠ **Важно про `email` / `phone` / `web` (multifield):** При обновлении Битрикс24 **только добавляет** новые multifield-записи. PATCH `{"email": "new@y.com"}` к компании, у которой уже есть email, **не заменит** старый — у компании станет два email. Это особенность Битрикс24, не Вайбкод. Чтобы заменить или удалить email/phone/web — отредактируйте компанию через интерфейс Битрикс24. ## Часто обновляемые поля | Параметр | Тип | Описание | |----------|-----|---------| | `title` | string | Название | | `phone` | string \| string[] \| object[] | Телефон. Принимает три формы: строка `"+7..."`, массив строк `["+7...", "+7..."]`, или массив объектов `[{ "value": "+7...", "typeId": "WORK" }, …]`. `typeId`: `WORK \| HOME \| MOBILE \| OTHER` (по умолчанию `WORK`). ⚠ UPPER-форма `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` **не принимается** — вернёт `400 INVALID_MULTIFIELD_SHAPE`. Используйте camelCase: `[{ "value": "...", "typeId": "WORK" }]` | | `email` | string \| string[] \| object[] | Email. Принимает три формы: строка `"a@b.com"`, массив строк `["a@b.com", "b@c.com"]`, или массив объектов `[{ "value": "a@b.com", "typeId": "WORK" }, …]`. `typeId`: `WORK \| HOME \| MAILING \| OTHER` (по умолчанию `WORK`). ⚠ UPPER-форма `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` **не принимается** — вернёт `400 INVALID_MULTIFIELD_SHAPE`. Используйте camelCase: `[{ "value": "...", "typeId": "WORK" }]` | | `web` | string \| string[] \| object[] | Веб-сайт. Принимает три формы: строка `"https://acme.com"`, массив строк, или массив объектов `[{ "value": "https://...", "typeId": "WORK" }]`. `typeId`: `WORK \| HOME \| OTHER` (по умолчанию `WORK`). ⚠ UPPER-форма `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` **не принимается** — вернёт `400 INVALID_MULTIFIELD_SHAPE`. Используйте camelCase: `[{ "value": "...", "typeId": "WORK" }]` | | `assignedById` | number | Ответственный. Список: `GET /v1/users` | | `industry` | string | Отрасль. Список: `GET /v1/statuses?filter[entityId]=INDUSTRY` | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/companies/1" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "ЗАО Ложки (обновлено)", "industry": "MANUFACTURING" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/companies/1" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "ЗАО Ложки (обновлено)", "industry": "MANUFACTURING" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/companies/1', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'ЗАО Ложки (обновлено)', industry: 'MANUFACTURING' }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/companies/1', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'ЗАО Ложки (обновлено)', industry: 'MANUFACTURING' }), }) const { success, data } = await res.json() ``` ### Альтернативная форма — массив объектов с явным `typeId` Если нужно указать несколько значений или явный тип (`HOME`, `OTHER`): ```json { "phone": [ { "value": "+74951234567", "typeId": "WORK" }, { "value": "+74951112233", "typeId": "OTHER" } ], "email": [ { "value": "info@romashka.ru", "typeId": "WORK" }, { "value": "sales@romashka.ru", "typeId": "MAILING" } ], "web": [ { "value": "https://romashka.ru", "typeId": "WORK" }, { "value": "https://shop.romashka.ru", "typeId": "OTHER" } ] } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | object | Обновлённый объект компании со всеми полями — см. [Поля](/docs/entities/companies/fields) | Обновлённый объект компании — см. [Поля компании](/docs/entities/companies/fields). ## Пример ответа ```json { "success": true, "data": { "id": 1, "title": "ЗАО Ложки (обновлено)", "industry": "MANUFACTURING", "assignedById": 1, "createdTime": "2020-05-08T10:48:20+03:00", "updatedTime": "2026-04-15T12:00:00+03:00" } } ``` ## Пример ответа при ошибке 404 — компания не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Компания не найдена | | 403 | `ACCESS_DENIED` | Нет доступа | | 400 | `INVALID_REQUEST` | Некорректные поля | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Работа с файлами в полях CRM](/docs/recipes/crm-files) - [Получить компанию](/docs/entities/companies/get) - [Поля компании](/docs/entities/companies/fields) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Contacts: Aggregate ## Агрегация контактов `POST /v1/contacts/aggregate` Подсчёт количества контактов с фильтрацией и группировкой. **Стандартные поля:** - `typeId` — тип контакта (для `groupBy`) - `sourceId` — источник (для `groupBy`) - `assignedById` — ответственный (для `groupBy`) Все поля в `aggregatable` — категориальные идентификаторы, поэтому по стандартным полям работают `count` и `groupBy`. Для числовых функций (`sum`/`avg`/`min`/`max`) используйте пользовательские поля. **Пользовательские поля (UF):** UF-поля типов `integer`, `double`, `money` — для числовых функций; UF любого типа — для `groupBy`. Полный список UF-полей конкретного портала приходит в тексте ошибки `INVALID_PARAMS`, если передать несуществующее имя. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций. Каждый элемент: `{ "field": "*", "function": "count" }`. Без массива — только `count` | | `filter` | object | нет | Фильтрация по полям `GET /v1/contacts/fields`. [Синтаксис фильтрации](/docs/filtering) | | `groupBy` | string \| string[] | нет | Поле или массив полей для группировки (максимум 5). Допустимые значения — из списка выше | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/contacts/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "assignedById": 1 }, "groupBy": "typeId" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/contacts/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "assignedById": 1 }, "groupBy": "typeId" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/contacts/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { assignedById: 1 }, groupBy: 'typeId', }), }) const { success, data } = await res.json() console.log('Всего контактов:', data.count) console.log('По типам:', data.groups) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/contacts/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { assignedById: 1 }, groupBy: 'typeId', }), }) const { success, data } = await res.json() ``` > Для группировки по нескольким полям передайте массив: `"groupBy": ["typeId", "sourceId"]` (максимум 5). ## Другие сценарии Общее количество контактов в портале — самый быстрый запрос, без выгрузки записей: ```json {} ``` Работа с пользовательскими полями (UF) — `sum` по UF + группировка по другому UF: ```json { "aggregate": [{ "field": "UF_CRM_LTV", "function": "sum" }], "groupBy": "UF_CRM_SEGMENT" } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Общее количество записей под фильтр | | `data.aggregates` | object | Результаты агрегаций (для контактов обычно пустой) | | `data.groups` | array | Группы (только при `groupBy`). Каждый элемент: поля группировки + `count` | | `data.meta.totalRecords` | number | Общее количество записей под фильтр | | `data.meta.recordsProcessed` | number | Сколько записей обработано (для `count` — `0`, записи не выгружаются) | | `data.meta.truncated` | boolean | `true`, если под фильтр попало больше 5000 записей | ## Пример ответа Ответ на основной запрос (`groupBy: "typeId"`): ```json { "success": true, "data": { "count": 1200, "aggregates": {}, "groups": [ { "typeId": "CLIENT", "count": 800 }, { "typeId": "SUPPLIER", "count": 300 }, { "typeId": "PARTNER", "count": 100 } ], "meta": { "totalRecords": 1200, "recordsProcessed": 1200, "truncated": false } } } ``` Без `groupBy` поле `data.groups` в ответе отсутствует. ## Пример ответа при ошибке 400 — `groupBy` по неаггрегируемому полю или несуществующему полю: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "groupBy field 'name' is not aggregatable on this entity. Available: typeId, sourceId, assignedById" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `groupBy` по неаггрегируемому полю или больше 5 полей в `groupBy` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Money-поля.** UF-поля типа `money` хранятся в формате `"сумма|валюта"` (`"1500|RUB"`) — агрегат извлекает числовую часть автоматически, складывать можно без парсинга. **Фильтрация по UF работает.** В `filter` можно передавать любые поля — стандартные и пользовательские, любого типа. Например, `{ "filter": { "ufCrm_1234": "value" } }` вернёт количество контактов с этим значением UF. ## Смотрите также - [Список контактов](/docs/entities/contacts/list) - [Поиск контактов](/docs/entities/contacts/search) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Contacts: Create ## Создать контакт `POST /v1/contacts` Создаёт новый контакт в CRM. ## Поля запроса (body) | Параметр | Тип | Описание | |----------|-----|---------| | `name` | string | Имя | | `lastName` | string | Фамилия | | `secondName` | string | Отчество | | `phone` | string \| string[] \| object[] | Телефон. Принимает три формы: строка `"+7..."`, массив строк `["+7...", "+7..."]`, или массив объектов `[{ "value": "+7...", "typeId": "WORK" }, …]`. `typeId`: `WORK \| HOME \| MOBILE \| OTHER` (по умолчанию `WORK`). ⚠ UPPER-форма `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` **не принимается** — вернёт `400 INVALID_MULTIFIELD_SHAPE`. Используйте camelCase: `[{ "value": "...", "typeId": "WORK" }]` | | `email` | string \| string[] \| object[] | Email. Принимает три формы: строка `"a@b.com"`, массив строк `["a@b.com", "b@c.com"]`, или массив объектов `[{ "value": "a@b.com", "typeId": "WORK" }, …]`. `typeId`: `WORK \| HOME \| MAILING \| OTHER` (по умолчанию `WORK`). ⚠ UPPER-форма `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` **не принимается** — вернёт `400 INVALID_MULTIFIELD_SHAPE`. Используйте camelCase: `[{ "value": "...", "typeId": "WORK" }]` | | `companyId` | number | ID компании. Поиск: `GET /v1/companies` | | `post` | string | Должность | | `comments` | string | Комментарий | | `typeId` | string | Тип контакта. Список: `GET /v1/statuses?filter[entityId]=CONTACT_TYPE` | | `sourceId` | string | Источник. Список: `GET /v1/statuses?filter[entityId]=SOURCE` | | `sourceDescription` | string | Описание источника | | `assignedById` | number | Ответственный. Список: `GET /v1/users` | | `opened` | boolean | Доступен для всех | | `leadId` | number | ID лида, из которого создан контакт | Полный список полей: [GET /v1/contacts/fields](/docs/entities/contacts/fields). Пользовательские поля (`ufCrm_*`) также принимаются. ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/contacts \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Иван", "lastName": "Петров", "phone": "+79161234567", "email": "ivan@company.ru", "companyId": 15, "post": "Менеджер", "typeId": "CLIENT" }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/contacts \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Иван", "lastName": "Петров", "phone": "+79161234567", "email": "ivan@company.ru", "companyId": 15, "post": "Менеджер", "typeId": "CLIENT" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/contacts', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Иван', lastName: 'Петров', phone: '+79161234567', email: 'ivan@company.ru', companyId: 15, post: 'Менеджер', typeId: 'CLIENT', }), }) const { success, data } = await res.json() console.log('Contact ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/contacts', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Иван', lastName: 'Петров', phone: '+79161234567', email: 'ivan@company.ru', companyId: 15, post: 'Менеджер', typeId: 'CLIENT', }), }) const { success, data } = await res.json() ``` ### Альтернативная форма — массив объектов с явным `typeId` Если нужно указать несколько значений или явный тип (`HOME`, `MOBILE`): ```json { "phone": [ { "value": "+79161234567", "typeId": "WORK" }, { "value": "+79161112233", "typeId": "MOBILE" } ], "email": [ { "value": "work@company.ru", "typeId": "WORK" }, { "value": "personal@me.ru", "typeId": "HOME" } ] } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID созданного контакта | | `name` | string | Имя | | `lastName` | string | Фамилия | | `companyId` | number | ID компании | | `assignedById` | number | Ответственный | | `createdBy` | number | Создатель | | `createdTime` | datetime | Дата создания | | `updatedTime` | datetime | Дата изменения | | `typeId` | string | Тип контакта | | `sourceId` | string | Источник | Ответ содержит все поля контакта, включая пользовательские (`ufCrm_*`). URL карточки контакта в Битрикс24 строится из `id`: ``` https://.bitrix24.ru/crm/contact/details// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": { "id": 2457, "name": "Иван", "lastName": "Петров", "secondName": null, "companyId": 15, "assignedById": 1, "createdBy": 1, "createdTime": "2026-04-15T12:26:17+03:00", "updatedTime": "2026-04-15T12:26:17+03:00", "opened": true, "typeId": "CLIENT", "sourceId": "CALL", "post": "Менеджер" } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 400 | `INVALID_REQUEST` | Невалидные поля | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Работа с файлами в полях CRM](/docs/recipes/crm-files) - [Список контактов](/docs/entities/contacts/list) - [Поля контакта](/docs/entities/contacts/fields) - [Поиск дубликатов](/docs/duplicates) - [Компании](/docs/entities/companies) - [Сделки](/docs/entities/deals) - [Entity API](/docs/entity-api) - [Лимиты и оптимизация](/docs/optimization) --- # Contacts: Delete ## Удалить контакт `DELETE /v1/contacts/:id` Удаляет контакт по ID. Восстановить удалённый контакт через API нельзя — создавайте новый при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID контакта | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/contacts/2457" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/contacts/2457" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/contacts/2457', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Контакт удалён') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/contacts/2457', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — контакт не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Контакт не найден | | 403 | `ACCESS_DENIED` | Нет доступа | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список контактов](/docs/entities/contacts/list) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Contacts: Fields ## Поля контакта `GET /v1/contacts/fields` Возвращает полный список доступных полей, включая пользовательские (`ufCrm_*`). ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/contacts/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/contacts/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/contacts/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/contacts/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | RO | Описание | |------|-----|:--:|---------| | `id` | number | да | ID контакта | | `name` | string | | Имя | | `lastName` | string | | Фамилия | | `secondName` | string | | Отчество | | `phone` | multifield | | Телефон. На вход (POST/PATCH) принимает `string \| string[] \| object[]`. На выходе `phone` — строка с первичным значением, значения по типам — в полях `phoneWork`/`phoneMobile`, полный перечень с типами — в массиве `fm[]` (формат `{ id, typeId, valueType, value }`). ⚠ PATCH **только добавляет** новые записи — старые `phone` не удаляются. См. [Обновить контакт](/docs/entities/contacts/update). ⚠ UPPER-форма `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` **не принимается** — вернёт `400 INVALID_MULTIFIELD_SHAPE`. Используйте camelCase: `[{ "value": "...", "typeId": "WORK" }]`. | | `email` | multifield | | Email. На вход принимает `string \| string[] \| object[]`. На выходе `email` — строка с первичным значением, значения по типам — в полях `emailWork`/`emailHome`/`emailMailing`, полный перечень — в массиве `fm[]`. ⚠ PATCH **только добавляет** новые записи — старые `email` не удаляются. ⚠ UPPER-форма `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` **не принимается** — вернёт `400 INVALID_MULTIFIELD_SHAPE`. Используйте camelCase: `[{ "value": "...", "typeId": "WORK" }]`. | | `hasPhone` | boolean | да | Указан ли телефон | | `hasEmail` | boolean | да | Указан ли email | | `hasImol` | boolean | да | Есть ли контакт в открытой линии | | `companyId` | number | | ID компании. Поиск: `GET /v1/companies` | | `post` | string | | Должность | | `comments` | string | | Комментарий | | `typeId` | string | | Тип контакта. Список: `GET /v1/statuses?filter[entityId]=CONTACT_TYPE` | | `sourceId` | string | | Источник. Список: `GET /v1/statuses?filter[entityId]=SOURCE` | | `sourceDescription` | string | | Описание источника | | `assignedById` | number | | Ответственный. Список: `GET /v1/users` | | `createdBy` | number | да | Создатель. Поиск: `GET /v1/users` | | `updatedBy` | number | да | Кто изменил. Поиск: `GET /v1/users` | | `createdTime` | datetime | да | Дата создания | | `updatedTime` | datetime | да | Дата изменения | | `opened` | boolean | | Доступен для всех | | `export` | boolean | | Разрешён экспорт | | `leadId` | number | | ID лида-источника | | `honorific` | string | | Обращение. Список: `GET /v1/statuses?filter[entityId]=HONORIFIC` | **Пользовательские поля** (`ufCrm_*`) также возвращаются в ответах и принимаются при создании/обновлении. ## Доступные include Эндпоинт `GET /v1/contacts/fields` возвращает список доступных include: `company`, `requisite`. Пример использования: [Получить contacts](/docs/entities/contacts/get#связанные-данные). Подробнее об include: [Связанные данные](/docs/includes). ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true }, "name": { "type": "string", "readonly": false }, "assignedById": { "type": "number", "readonly": false } }, "batch": ["create", "update", "delete"] } } ``` Показаны 3 из множества полей. Полный список в таблице выше. ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать контакт](/docs/entities/contacts/create) - [Пользовательские поля](/docs/userfields) - [Entity API](/docs/entity-api) - [Лимиты и оптимизация](/docs/optimization) --- # Contacts: Get ## Получить контакт `GET /v1/contacts/:id` Возвращает контакт по ID со всеми полями. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID контакта | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/contacts/71" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/contacts/71" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/contacts/71', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Контакт:', data.name, data.lastName) console.log('Получено:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/contacts/71', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` Подробнее об include: [Связанные данные](/docs/includes). ## Поля ответа Объект контакта со всеми полями — см. [Поля контакта](/docs/entities/contacts/fields). ## Связанные данные (include) Получить связанные сущности вместе с контактом — параметр `include` в GET-запросе: ``` GET /v1/contacts/71?include=company ``` Доступные include: `company`, `requisite`. Результат в поле `_included`. ## Пример ответа ```json { "success": true, "data": { "id": 71, "name": "Иван", "lastName": "Петров", "companyId": 1, "assignedById": 1, "sourceId": "WEB", "typeId": "CLIENT", "phone": "+70000000001", "phoneWork": "+70000000001", "email": "info@example.com", "emailWork": "info@example.com", "emailHome": "home@example.com", "hasPhone": true, "hasEmail": true, "fm": [ { "id": 41, "typeId": "PHONE", "valueType": "WORK", "value": "+70000000001" }, { "id": 43, "typeId": "EMAIL", "valueType": "WORK", "value": "info@example.com" }, { "id": 45, "typeId": "EMAIL", "valueType": "HOME", "value": "home@example.com" } ], "createdTime": "2020-05-08T10:48:20+03:00", "updatedTime": "2025-08-22T13:01:31+03:00" } } ``` Телефон и почта в ответе — строки с первичным значением, значения по типам — в полях `phoneWork`, `phoneMobile`, `emailWork`, `emailHome`. Полный перечень с типами — в массиве `fm[]` (`{ id, typeId, valueType, value }`, где `id` — идентификатор записи). Наличие проверяйте по `hasPhone`/`hasEmail`: при отсутствии телефона `phone` приходит пустой строкой. Отдельную запись `fm[]` по её `id` через API не изменить и не удалить — PATCH добавляет новые записи. ## Пример ответа при ошибке 404 — контакт не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Контакт не найден | | 403 | `ACCESS_DENIED` | Нет доступа к контакту | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Работа с файлами в полях CRM](/docs/recipes/crm-files) - [Обновить контакт](/docs/entities/contacts/update) - [Поля контакта](/docs/entities/contacts/fields) - [Компании](/docs/entities/companies) - [Лимиты и оптимизация](/docs/optimization) --- # Contacts: List ## Список контактов `GET /v1/contacts` Возвращает список контактов с поддержкой фильтрации, сортировки и авто-пагинации. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` авто-пагинация | | `offset` | number | `0` | Пропустить N записей. При `offset > 0` рекомендуется `limit ≤ 500`. Для обхода всей коллекции дешевле курсор — `order[id]=asc` и `filter[>id]` из `meta.nextAfterId` | | `select` | string | — | Выборка полей: `?select=id,name,lastName,phone` | | `order` | object | — | Сортировка: `?order[lastName]=asc` | | `filter` | object | — | Фильтрация по полям `GET /v1/contacts/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[companyId]=15` | | `withTotal` | string | — | Нужно ли количество: `true` или `false`. `false` — не заказывать подсчёт. Это единственный способ гарантированно убрать `meta.total` из ответа. Без параметра — настройка ключа, затем платформенное умолчание, и тогда на короткой странице точное количество приходит и без заказа. [Листание и количество](/docs/entity-api#листание-и-количество-записей) | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/contacts?limit=10&filter[companyId]=15&select=id,name,lastName,phone" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/contacts?limit=10&filter[companyId]=15&select=id,name,lastName,phone" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/contacts?limit=10&filter[companyId]=15&select=id,name,lastName,phone', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} контактов`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/contacts?limit=10&filter[companyId]=15&select=id,name,lastName,phone', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив контактов (поля — см. [Поля](/docs/entities/contacts/fields)) | | `meta.total` | number | Общее количество записей. Необязательное поле: если количество не заказывалось, его в ответе нет | | `meta.hasMore` | boolean | Есть ещё записи | | `meta.nextAfterId` | string | Идентификатор последней отданной записи. Приходит при сортировке строго по `id` по возрастанию, пока `hasMore` равен `true`. Передайте его обратно как `filter[>id]` — это дешёвая замена растущему `offset` | URL карточки любого контакта из массива `data` — его `id`: ``` https://.bitrix24.ru/crm/contact/details// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 17, "name": "Иван", "lastName": "Петров", "phone": "74955553546", "email": "ivan@company.ru", "companyId": 1, "assignedById": 1, "sourceId": "EMAIL", "typeId": "CLIENT" } ], "meta": { "total": 1167, "hasMore": true } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Фильтр по телефону подходит не для всякого поиска.** Значение без оператора сравнивается со всей сохранённой строкой: контакт с номером `+7 (999) 123-45-67` найдётся по этой же строке и не найдётся по `79991234567`, потому что плюс, пробелы, скобки и дефисы — часть значения. Вдобавок фильтр видит только первый номер записи: если записаны рабочий и мобильный, по мобильному он вернёт пустой список. Чтобы найти контакт по номеру телефона в любом написании и по любому из его номеров, используйте [Поиск дубликатов](/docs/duplicates). **Авто-пагинация:** при `limit > 50` Вайбкод автоматически запрашивает несколько страниц. **Когда использовать поиск.** Для составных условий подходит `POST /v1/contacts/search` — параметры передаются в теле запроса. См. [Поиск контактов](/docs/entities/contacts/search). ## Смотрите также - [Поиск контактов](/docs/entities/contacts/search) - [Создать контакт](/docs/entities/contacts/create) - [Поиск дубликатов](/docs/duplicates) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Contacts: Search ## Поиск контактов `POST /v1/contacts/search` Поиск контактов по условиям в теле запроса. Принимает те же фильтры, что и список контактов, и рассчитан на составные условия и большие выборки. ## Поля запроса (body) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям `GET /v1/contacts/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "companyId": 15 }` | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки» | | `order` | object | — | Сортировка: `{ "lastName": "asc" }` | | `select` | string[] | — | Выборка полей: `["id", "name", "lastName", "phone"]` | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/contacts/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "companyId": 15 }, "limit": 10, "order": { "lastName": "asc" } }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/contacts/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "companyId": 15 }, "limit": 10, "order": { "lastName": "asc" } }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/contacts/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { companyId: 15 }, limit: 10, order: { lastName: 'asc' }, }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/contacts/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { companyId: 15 }, limit: 10, order: { lastName: 'asc' }, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив контактов (поля — см. [Поля](/docs/entities/contacts/fields)) | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли следующая страница | | `meta.nextAfterId` | string | Идентификатор последней отданной записи. Приходит при сортировке строго по `id` по возрастанию, пока `hasMore` равен `true`. Передайте его обратно в фильтр `>id` — это дешёвая замена растущему `offset` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. URL карточки любого контакта из массива `data` — его `id`: ``` https://.bitrix24.ru/crm/contact/details// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 71, "name": "Иван", "lastName": "Петров", "phone": "74955553546", "companyId": 15, "assignedById": 1, "typeId": "CLIENT" } ] } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Фильтр по телефону подходит не для всякого поиска.** Значение без оператора сравнивается со всей сохранённой строкой: контакт с номером `+7 (999) 123-45-67` найдётся по этой же строке и не найдётся по `79991234567`, потому что плюс, пробелы, скобки и дефисы — часть значения. Вдобавок фильтр видит только первый номер записи: если записаны рабочий и мобильный, по мобильному он вернёт пустой список. Чтобы найти контакт по номеру телефона в любом написании и по любому из его номеров, используйте [Поиск дубликатов](/docs/duplicates). Оператор `$contains` при этом работает — он ищет кусок текста внутри значения, это рабочий способ для почты: `{ "email": { "$contains": "@example.com" } }`. ## Смотрите также - [Список контактов](/docs/entities/contacts/list) - [Поиск дубликатов](/docs/duplicates) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Contacts: Update ## Обновить контакт `PATCH /v1/contacts/:id` Обновляет поля существующего контакта. Передайте только изменяемые поля. Полный список в [справочнике полей](/docs/entities/contacts/fields), включая пользовательские (`ufCrm_*`). > ⚠ **Важно про `email` / `phone` (multifield):** При обновлении Битрикс24 **только добавляет** новые multifield-записи. PATCH `{"email": "new@y.com"}` к контакту, у которого уже есть email, **не заменит** старый — у контакта станет два email. Это особенность Битрикс24, не Вайбкод. Чтобы заменить или удалить email/phone — отредактируйте контакт через интерфейс Битрикс24. ## Часто обновляемые поля | Параметр | Тип | Описание | |----------|-----|---------| | `phone` | string \| string[] \| object[] | Телефон. Принимает три формы: строка `"+7..."`, массив строк `["+7...", "+7..."]`, или массив объектов `[{ "value": "+7...", "typeId": "WORK" }, …]`. `typeId`: `WORK \| HOME \| MOBILE \| OTHER` (по умолчанию `WORK`). ⚠ UPPER-форма `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` **не принимается** — вернёт `400 INVALID_MULTIFIELD_SHAPE`. Используйте camelCase: `[{ "value": "...", "typeId": "WORK" }]` | | `email` | string \| string[] \| object[] | Email. Принимает три формы: строка `"a@b.com"`, массив строк `["a@b.com", "b@c.com"]`, или массив объектов `[{ "value": "a@b.com", "typeId": "WORK" }, …]`. `typeId`: `WORK \| HOME \| MAILING \| OTHER` (по умолчанию `WORK`). ⚠ UPPER-форма `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` **не принимается** — вернёт `400 INVALID_MULTIFIELD_SHAPE`. Используйте camelCase: `[{ "value": "...", "typeId": "WORK" }]` | | `companyId` | number | ID компании. Поиск: `GET /v1/companies` | | `assignedById` | number | Ответственный. Список: `GET /v1/users` | | `post` | string | Должность | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/contacts/71" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "phone": "+79169876543", "post": "Директор" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/contacts/71" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "phone": "+79169876543", "post": "Директор" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/contacts/71', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ phone: '+79169876543', post: 'Директор', }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/contacts/71', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ phone: '+79169876543', post: 'Директор', }), }) const { success, data } = await res.json() ``` ### Альтернативная форма — массив объектов с явным `typeId` Если нужно указать несколько значений или явный тип (`HOME`, `MOBILE`): ```json { "phone": [ { "value": "+79161234567", "typeId": "WORK" }, { "value": "+79161112233", "typeId": "MOBILE" } ], "email": [ { "value": "work@company.ru", "typeId": "WORK" }, { "value": "personal@me.ru", "typeId": "HOME" } ] } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | object | Обновлённый объект контакта со всеми полями — см. [Поля](/docs/entities/contacts/fields) | Обновлённый объект контакта — см. [Поля контакта](/docs/entities/contacts/fields). ## Пример ответа ```json { "success": true, "data": { "id": 71, "name": "Иван", "lastName": "Петров", "companyId": 15, "assignedById": 1, "createdTime": "2020-05-08T10:48:20+03:00", "updatedTime": "2026-04-15T12:00:00+03:00" } } ``` ## Пример ответа при ошибке 404 — контакт не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Контакт не найден | | 403 | `ACCESS_DENIED` | Нет доступа | | 400 | `INVALID_REQUEST` | Некорректные поля | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Работа с файлами в полях CRM](/docs/recipes/crm-files) - [Получить контакт](/docs/entities/contacts/get) - [Поля контакта](/docs/entities/contacts/fields) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Crm Card Config: Force Common ## Общая раскладка для всех сотрудников `POST /v1/crm/card-config/:entityTypeId/force-common` Удаляет личные раскладки карточки у всех сотрудников и оставляет только общую раскладку выбранной области. После вызова все сотрудники видят единый макет карточки. Метод не принимает `scope` и `userId` — по своей роли он действует на всех сразу. ## Параметр пути | Параметр | Тип | Описание | |----------|-----|---------| | `entityTypeId` | number | Тип CRM-объекта:
`1` — лид
`2` — сделка
`3` — контакт
`4` — компания
`7` — предложение
`31` — счёт
смарт-процесс — числовой ID типа из [`GET /v1/smart-processes`](/docs/entities/smart-processes), поле `entityTypeId` | ## Поля запроса (body) Тело может быть пустым или `{}`. Уточнения области передаются по необходимости. | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `dealCategoryId` | number | нет | Воронка сделок, только для сделок (`entityTypeId=2`). Источник: [`GET /v1/categories/2`](/docs/entities/categories) | | `categoryId` | number | нет | Воронка смарт-процесса, только для смарт-процессов. Источник: [`GET /v1/categories/:entityTypeId`](/docs/entities/categories) | | `leadCustomerType` | number | нет | Тип лида, только для лидов (`entityTypeId=1`): `1` — простой, `2` — повторный | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/crm/card-config/2/force-common" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "dealCategoryId": 9 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/crm/card-config/2/force-common" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "dealCategoryId": 9 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/crm/card-config/2/force-common', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ dealCategoryId: 9 }), }) const { success, data } = await res.json() console.log('Общая раскладка применена ко всем:', data.forced) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/crm/card-config/2/force-common', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ dealCategoryId: 9 }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Результат операции | | `data.entityTypeId` | number | Тип объекта из пути | | `data.forced` | boolean | Всегда `true` при успехе | ## Пример ответа ```json { "success": true, "data": { "entityTypeId": 2, "forced": true } } ``` ## Пример ответа при ошибке 400 — недопустимое значение `dealCategoryId`: ```json { "success": false, "error": { "code": "INVALID_DEAL_CATEGORY_ID", "message": "dealCategoryId must be a positive integer." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_ENTITY_TYPE_ID` | `entityTypeId` в пути не является положительным целым числом | | 400 | `INVALID_DEAL_CATEGORY_ID` | `dealCategoryId` не является положительным целым числом | | 400 | `INVALID_CATEGORY_ID` | `categoryId` не является положительным целым числом | | 400 | `INVALID_LEAD_CUSTOMER_TYPE` | `leadCustomerType` не равен `1` или `2` | | 502 | `CRM_CARD_CONFIG_FORCE_COMMON_FAILED` | Битрикс24 не подтвердил операцию — например, недостаточно прав или целевая область недоступна | | 422 | `BITRIX_ERROR` | Битрикс24 не распознал тип объекта. Сообщение — в `error.message` | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ приложения в режиме «только чтение» — запись заблокирована | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Метод удаляет личные раскладки всех сотрудников.** Личные настройки карточки, сделанные сотрудниками для выбранной области, пропадают, и все переходят на общую раскладку. Действие рассчитано на первоначальное развёртывание единого макета карточки на портале. **`scope` и `userId` не принимаются.** Метод по своей роли работает на всех сотрудников. Чтобы записать общую раскладку без удаления личных, используйте [`PUT`](./set.md) со `scope: "C"`. ## Смотрите также - [Установить раскладку](/docs/entities/crm-card-config/set) - [Получить раскладку](/docs/entities/crm-card-config/get) - [Сбросить раскладку](/docs/entities/crm-card-config/reset) --- # Crm Card Config: Get ## Получить раскладку карточки `GET /v1/crm/card-config/:entityTypeId` Возвращает текущую раскладку секций и полей карточки для указанного типа CRM-объекта и области. Отдаёт массив секций либо `null`, если явной конфигурации ещё не было. ## Параметр пути | Параметр | Тип | Описание | |----------|-----|---------| | `entityTypeId` | number | Тип CRM-объекта:
`1` — лид
`2` — сделка
`3` — контакт
`4` — компания
`7` — предложение
`31` — счёт
смарт-процесс — числовой ID типа из [`GET /v1/smart-processes`](/docs/entities/smart-processes), поле `entityTypeId` | ## Параметры запроса | Параметр | Тип | Описание | |----------|-----|---------| | `scope` | string | Область раскладки: `P` — личная (по умолчанию), `C` — общая | | `userId` | number | Сотрудник, чью личную раскладку читать. По умолчанию — владелец API-ключа. Имеет смысл только при `scope=P`. Источник: [`GET /v1/users`](/docs/entities/users) | | `dealCategoryId` | number | Воронка сделок, только для сделок (`entityTypeId=2`). Источник: [`GET /v1/categories/2`](/docs/entities/categories) | | `categoryId` | number | Воронка смарт-процесса, только для смарт-процессов. Источник: [`GET /v1/categories/:entityTypeId`](/docs/entities/categories) | | `leadCustomerType` | number | Тип лида, только для лидов (`entityTypeId=1`): `1` — простой, `2` — повторный | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/crm/card-config/2?scope=C&dealCategoryId=9" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/crm/card-config/2?scope=C&dealCategoryId=9" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/crm/card-config/2?scope=C&dealCategoryId=9', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() if (data === null) { console.log('Явной раскладки нет — используется раскладка по умолчанию') } else { console.log('Секций в раскладке:', data.length) } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/crm/card-config/2?scope=C&dealCategoryId=9', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array \| null | Массив секций раскладки. `null` — явной конфигурации ещё не было | | `data[].name` | string | Внутреннее имя секции | | `data[].title` | string | Отображаемое название секции | | `data[].type` | string | Всегда `section` | | `data[].elements` | array | Поля секции в порядке отображения | | `data[].elements[].name` | string | Имя поля CRM в формате Битрикс24 | | `data[].elements[].optionFlags` | string | Флаг поля: `"0"` — обычное, `"1"` — поле клиента | | `data[].elements[].options` | object | Параметры конкретного поля, если заданы | ## Пример ответа Раскладка задана явно: ```json { "success": true, "data": [ { "name": "main", "title": "О сделке", "type": "section", "elements": [ { "name": "TITLE", "optionFlags": "0" }, { "name": "STAGE_ID", "optionFlags": "0" }, { "name": "OPPORTUNITY_WITH_CURRENCY", "optionFlags": "0" } ] } ] } ``` Явной конфигурации для области ещё не было: ```json { "success": true, "data": null } ``` ## Пример ответа при ошибке 400 — недопустимое значение `scope`: ```json { "success": false, "error": { "code": "INVALID_SCOPE", "message": "scope must be \"P\" (personal) or \"C\" (common)." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_ENTITY_TYPE_ID` | `entityTypeId` в пути не является положительным целым числом | | 400 | `INVALID_SCOPE` | `scope` не равен `P` или `C` | | 400 | `INVALID_USER_ID` | `userId` не является положительным целым числом | | 400 | `INVALID_DEAL_CATEGORY_ID` | `dealCategoryId` не является положительным целым числом | | 400 | `INVALID_CATEGORY_ID` | `categoryId` не является положительным целым числом | | 400 | `INVALID_LEAD_CUSTOMER_TYPE` | `leadCustomerType` не равен `1` или `2` | | 422 | `BITRIX_ERROR` | Битрикс24 не распознал тип объекта — например, для несуществующего `entityTypeId`. Сообщение — в `error.message` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`data: null` отличается от пустой раскладки.** `null` означает, что для указанной области ещё не было явной конфигурации, и карточка рисуется встроенной раскладкой по умолчанию. Пустой массив `[]` означает явно сохранённую пустую раскладку. Ветку `data === null` в коде стоит обрабатывать отдельно. **В ответе `optionFlags` приходит строкой.** Для ранее сохранённых раскладок значение флага возвращается как строка `"0"` или `"1"`. При записи через [`PUT`](./set.md) флаг передаётся числом. ## Смотрите также - [Установить раскладку](/docs/entities/crm-card-config/set) - [Сбросить раскладку](/docs/entities/crm-card-config/reset) - [Смарт-процессы](/docs/entities/smart-processes) - [Воронки](/docs/entities/categories) - [Пользовательские поля](/docs/userfields) --- # Crm Card Config: Reset ## Сбросить раскладку карточки `DELETE /v1/crm/card-config/:entityTypeId` Удаляет явную раскладку выбранной области. После сброса карточка возвращается к встроенной раскладке по умолчанию, а [`GET`](./get.md) для этой области возвращает `data: null`. ## Параметр пути | Параметр | Тип | Описание | |----------|-----|---------| | `entityTypeId` | number | Тип CRM-объекта:
`1` — лид
`2` — сделка
`3` — контакт
`4` — компания
`7` — предложение
`31` — счёт
смарт-процесс — числовой ID типа из [`GET /v1/smart-processes`](/docs/entities/smart-processes), поле `entityTypeId` | ## Параметры запроса или тела Принимаются в строке запроса или в теле. При совпадении значение из тела имеет приоритет. | Параметр | Тип | Описание | |----------|-----|---------| | `scope` | string | Область раскладки: `P` — личная (по умолчанию), `C` — общая | | `userId` | number | Сотрудник, чью личную раскладку сбросить. По умолчанию — владелец API-ключа. Имеет смысл только при `scope=P`. Источник: [`GET /v1/users`](/docs/entities/users) | | `dealCategoryId` | number | Воронка сделок, только для сделок (`entityTypeId=2`). Источник: [`GET /v1/categories/2`](/docs/entities/categories) | | `categoryId` | number | Воронка смарт-процесса, только для смарт-процессов. Источник: [`GET /v1/categories/:entityTypeId`](/docs/entities/categories) | | `leadCustomerType` | number | Тип лида, только для лидов (`entityTypeId=1`): `1` — простой, `2` — повторный | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/crm/card-config/2?scope=C&dealCategoryId=9" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/crm/card-config/2?scope=C&dealCategoryId=9" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/crm/card-config/2?scope=C&dealCategoryId=9', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() console.log('Раскладка сброшена:', data.reset) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/crm/card-config/2?scope=C&dealCategoryId=9', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Результат сброса | | `data.entityTypeId` | number | Тип объекта из пути | | `data.scope` | string | Область, которая сброшена: `P` или `C` | | `data.reset` | boolean | Всегда `true` при успехе | ## Пример ответа ```json { "success": true, "data": { "entityTypeId": 2, "scope": "C", "reset": true } } ``` ## Пример ответа при ошибке 400 — недопустимое значение `scope`: ```json { "success": false, "error": { "code": "INVALID_SCOPE", "message": "scope must be \"P\" (personal) or \"C\" (common)." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_ENTITY_TYPE_ID` | `entityTypeId` в пути не является положительным целым числом | | 400 | `INVALID_SCOPE` | `scope` не равен `P` или `C` | | 400 | `INVALID_USER_ID` | `userId` не является положительным целым числом | | 400 | `INVALID_DEAL_CATEGORY_ID` | `dealCategoryId` не является положительным целым числом | | 400 | `INVALID_CATEGORY_ID` | `categoryId` не является положительным целым числом | | 400 | `INVALID_LEAD_CUSTOMER_TYPE` | `leadCustomerType` не равен `1` или `2` | | 502 | `CRM_CARD_CONFIG_RESET_FAILED` | Битрикс24 не подтвердил сброс — например, недостаточно прав или целевая область недоступна | | 422 | `BITRIX_ERROR` | Битрикс24 не распознал тип объекта. Сообщение — в `error.message` | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ приложения в режиме «только чтение» — запись заблокирована | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Сброс несуществующей раскладки проходит успешно.** Если явной конфигурации для области не было, метод всё равно возвращает `reset: true`. Отдельной проверки «была ли раскладка» не требуется. **После сброса `GET` возвращает `null`.** Область снова показывает встроенную раскладку по умолчанию, а [`GET`](./get.md) для неё отдаёт `data: null`. ## Смотрите также - [Получить раскладку](/docs/entities/crm-card-config/get) - [Установить раскладку](/docs/entities/crm-card-config/set) - [Общая раскладка для всех](/docs/entities/crm-card-config/force-common) --- # Crm Card Config: Set ## Установить раскладку карточки `PUT /v1/crm/card-config/:entityTypeId` Записывает раскладку секций и полей карточки для указанной области. Полностью заменяет прежнюю раскладку этой области. Тело содержит массив секций `data` — каждая секция описывает блок карточки и его поля. ## Параметр пути | Параметр | Тип | Описание | |----------|-----|---------| | `entityTypeId` | number | Тип CRM-объекта:
`1` — лид
`2` — сделка
`3` — контакт
`4` — компания
`7` — предложение
`31` — счёт
смарт-процесс — числовой ID типа из [`GET /v1/smart-processes`](/docs/entities/smart-processes), поле `entityTypeId` | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `data` | array | да | Массив секций раскладки в порядке отображения | | `data[].name` | string | да | Внутреннее имя секции | | `data[].title` | string | да | Отображаемое название секции | | `data[].type` | string | да | Всегда `section` | | `data[].elements` | array | да | Поля секции в порядке отображения | | `data[].elements[].name` | string | да | Имя поля CRM в формате Битрикс24: `TITLE`, `NAME`, `PHONE`, `UF_CRM_1234567890` для пользовательских полей. Источник для пользовательских полей: [`GET /v1/userfields/:entity`](/docs/userfields) | | `data[].elements[].optionFlags` | number | нет | Флаг поля: `0` — обычное, `1` — поле клиента | | `data[].elements[].options` | object | нет | Параметры конкретного поля, например `defaultCountry` для `PHONE` или `defaultAddressType` для `ADDRESS` | | `scope` | string | нет | Область раскладки: `P` — личная (по умолчанию), `C` — общая | | `userId` | number | нет | Сотрудник, чью личную раскладку записать. По умолчанию — владелец API-ключа. Имеет смысл только при `scope=P`. Источник: [`GET /v1/users`](/docs/entities/users) | | `dealCategoryId` | number | нет | Воронка сделок, только для сделок (`entityTypeId=2`). Источник: [`GET /v1/categories/2`](/docs/entities/categories) | | `categoryId` | number | нет | Воронка смарт-процесса, только для смарт-процессов. Источник: [`GET /v1/categories/:entityTypeId`](/docs/entities/categories) | | `leadCustomerType` | number | нет | Тип лида, только для лидов (`entityTypeId=1`): `1` — простой, `2` — повторный | ## Примеры ### curl — личный ключ ```bash curl -X PUT "https://vibecode.bitrix24.tech/v1/crm/card-config/3" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "scope": "C", "data": [ { "name": "section_1", "title": "Личные данные", "type": "section", "elements": [ { "name": "NAME", "optionFlags": 1 }, { "name": "LAST_NAME", "optionFlags": 1 } ] } ] }' ``` ### curl — OAuth-приложение ```bash curl -X PUT "https://vibecode.bitrix24.tech/v1/crm/card-config/3" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "scope": "C", "data": [ { "name": "section_1", "title": "Личные данные", "type": "section", "elements": [ { "name": "NAME", "optionFlags": 1 }, { "name": "LAST_NAME", "optionFlags": 1 } ] } ] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/crm/card-config/3', { method: 'PUT', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ scope: 'C', data: [ { name: 'section_1', title: 'Личные данные', type: 'section', elements: [ { name: 'NAME', optionFlags: 1 }, { name: 'LAST_NAME', optionFlags: 1 }, ], }, ], }), }) const { success, data } = await res.json() console.log('Раскладка обновлена:', data.updated) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/crm/card-config/3', { method: 'PUT', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ scope: 'C', data: [ { name: 'section_1', title: 'Личные данные', type: 'section', elements: [ { name: 'NAME', optionFlags: 1 }, { name: 'LAST_NAME', optionFlags: 1 }, ], }, ], }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Результат записи | | `data.entityTypeId` | number | Тип объекта из пути | | `data.scope` | string | Область, в которую записана раскладка: `P` или `C` | | `data.updated` | boolean | Всегда `true` при успехе | ## Пример ответа ```json { "success": true, "data": { "entityTypeId": 3, "scope": "C", "updated": true } } ``` ## Пример ответа при ошибке 400 — тело без `data`: ```json { "success": false, "error": { "code": "INVALID_DATA", "message": "data must be a non-empty array of section objects. Each section: { name, title, type: \"section\", elements: [...] }." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_ENTITY_TYPE_ID` | `entityTypeId` в пути не является положительным целым числом | | 400 | `INVALID_DATA` | `data` отсутствует, не является массивом или является пустым массивом | | 400 | `INVALID_SCOPE` | `scope` не равен `P` или `C` | | 400 | `INVALID_USER_ID` | `userId` не является положительным целым числом | | 400 | `INVALID_DEAL_CATEGORY_ID` | `dealCategoryId` не является положительным целым числом | | 400 | `INVALID_CATEGORY_ID` | `categoryId` не является положительным целым числом | | 400 | `INVALID_LEAD_CUSTOMER_TYPE` | `leadCustomerType` не равен `1` или `2` | | 502 | `CRM_CARD_CONFIG_SET_FAILED` | Битрикс24 не подтвердил запись — например, недостаточно прав или целевая область недоступна | | 422 | `BITRIX_ERROR` | Битрикс24 отклонил тело — например, секция без `name` или `title`, элемент без `name`. Сообщение — в `error.message` | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ приложения в режиме «только чтение» — запись заблокирована | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Запись полностью заменяет раскладку области.** `PUT` перезаписывает всю раскладку выбранной области целиком, а не отдельные секции. Чтобы изменить часть карточки, прочитайте текущую раскладку через [`GET`](./get.md), измените массив и запишите его обратно. **Флаг `optionFlags` в теле передаётся числом.** При записи используется число (`0` или `1`). В ответе [`GET`](./get.md) для сохранённой раскладки тот же флаг возвращается строкой. ## Смотрите также - [Получить раскладку](/docs/entities/crm-card-config/get) - [Сбросить раскладку](/docs/entities/crm-card-config/reset) - [Общая раскладка для всех](/docs/entities/crm-card-config/force-common) - [Пользовательские поля](/docs/userfields) --- # Currencies: Aggregate ## Агрегация валют `POST /v1/currencies/aggregate` Подсчёт числа валют и числовые агрегации по курсам обмена и другим числовым полям справочника. Поддерживает функцию `count` и числовые функции `sum`, `avg`, `min`, `max` по полям `amount`, `amountCnt`, `sort`, `decimals`. Группировка `groupBy` для валют недоступна — у справочника нет полей, разрешённых для группировки, поэтому любой `groupBy` возвращает `400 INVALID_PARAMS`. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций. Подсчёт — `{ "field": "*", "function": "count" }`. Числовые функции — `{ "field": "<поле>", "function": "sum" \| "avg" \| "min" \| "max" }` по полям `amount`, `amountCnt`, `sort`, `decimals`. Без параметра возвращается только `count` | | `groupBy` | string \| array | нет | Не поддерживается для валют — возвращает `400 INVALID_PARAMS`. У справочника нет полей, разрешённых для группировки | | `filter` | object | нет | Не поддерживается для валют — любой ключ возвращает `400 UNSUPPORTED_FILTER` | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/currencies/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "amount", "function": "sum" }, { "field": "amount", "function": "avg" } ] }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/currencies/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "amount", "function": "sum" }, { "field": "amount", "function": "avg" } ] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/currencies/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [ { field: 'amount', function: 'sum' }, { field: 'amount', function: 'avg' }, ], }), }) const { success, data } = await res.json() console.log('Сумма курсов:', data.aggregates.amount.sum) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/currencies/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [ { field: 'amount', function: 'sum' }, { field: 'amount', function: 'avg' }, ], }), }) const { success, data } = await res.json() ``` ## Другие сценарии Общее количество валют в портале — самый быстрый запрос, без выгрузки записей: ```json {} ``` Минимальный и максимальный курс обмена: ```json { "aggregate": [{ "field": "amount", "function": "min" }, { "field": "amount", "function": "max" }] } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Количество валют, соответствующих запросу | | `data.aggregates` | object | Результаты числовых функций, сгруппированные по имени поля: `data.aggregates.amount.sum` и так далее. Пустой объект, если массив `aggregate` не передан | | `data.meta.totalRecords` | number | Общее количество валют | | `data.meta.recordsProcessed` | number | Сколько записей обработано для числовых функций. `0` для запроса только с `count` | | `data.meta.truncated` | boolean | `true`, если под запрос попало более 5000 записей и агрегация посчитана по первым 5000 | ## Пример ответа ```json { "success": true, "data": { "count": 7, "aggregates": { "amount": { "sum": 59, "avg": 8.428571428571429 } }, "meta": { "totalRecords": 7, "recordsProcessed": 7, "truncated": false } } } ``` Без массива `aggregate` поле `data.aggregates` — пустой объект, а `data.meta.recordsProcessed` равен `0`. ## Пример ответа при ошибке 400 — поле недоступно для агрегации: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "Field 'nope' not found. Available numeric fields: amount, amountCnt, sort, decimals." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Неизвестное поле в `aggregate` — сообщение перечисляет доступные числовые поля | | 400 | `INVALID_PARAMS` | Нечисловое поле в `sum`, `avg`, `min`, `max` — сообщение называет тип поля | | 400 | `INVALID_PARAMS` | Неизвестная функция агрегации — поддерживаются `count`, `sum`, `avg`, `min`, `max` | | 400 | `INVALID_PARAMS` | Передан `groupBy` — для валют группировка недоступна | | 400 | `UNSUPPORTED_FILTER` | Передан `filter` — валюты не фильтруются на стороне сервера | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | Не передан API-ключ | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`count` не выгружает записи, числовые функции — выгружают.** `count` считается одним запросом на любом объёме, поэтому `data.meta.recordsProcessed` равен `0`. Функции `sum`, `avg`, `min`, `max` выгружают записи и считают на стороне Вайбкод, поэтому `data.meta.recordsProcessed` равен числу обработанных валют. Справочник валют содержит единицы записей, поэтому предел в 5000 записей и `data.meta.truncated` для него не срабатывают. ## Смотрите также - [Валюты](/docs/entities/currencies) - [Список валют](/docs/entities/currencies/list) - [Поиск валют](/docs/entities/currencies/search) --- # Currencies: Create ## Создать валюту `POST /v1/currencies` Создаёт новую валюту в CRM. Код валюты задаётся в поле `id` (трёхбуквенный код ISO 4217). ## Параметры тела запроса | Параметр | Тип | Обязат. | Описание | |----------|-----|:-------:|---------| | `id` | string | да | Код валюты (RUB, USD, EUR) | | `amount` | number | да | Курс обмена относительно базовой валюты | | `amountCnt` | number | да | Номинал — для большинства валют равен 1, для JPY 100 | | `sort` | number | | Порядок сортировки | | `fullName` | string | | Название валюты. Если не передать, в названии остаётся код валюты | | `formatString` | string | да | Шаблон отображения, например `# ₽`. Символ `#` — место для суммы | | `decimals` | number | | Число знаков после запятой | | `decPoint` | string | | Десятичный разделитель | | `thousandsSep` | string | | Разделитель тысяч | > **Локализуемые поля можно передавать плоско.** `fullName`, `formatString`, `decimals`, `decPoint`, `thousandsSep` в Битрикс24 хранятся в структуре локализации по языкам. API сам упаковывает их в локализацию **вашего** языка (языка API-ключа), так что плоская запись теперь сохраняется и читается обратно. Сырой объект `LANG` в теле передавать **нельзя** — поле только для чтения, запрос вернётся `400 READONLY_FIELD`. Задание разных значений сразу для нескольких языков через API пока не поддерживается. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/currencies" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"id": "CNY", "amount": 12.7, "amountCnt": 1, "sort": 300, "fullName": "Китайский юань", "formatString": "# ¥"}' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/currencies" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"id": "CNY", "amount": 12.7, "amountCnt": 1, "sort": 300, "fullName": "Китайский юань", "formatString": "# ¥"}' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/currencies', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ id: 'CNY', amount: 12.7, amountCnt: 1, sort: 300, fullName: 'Китайский юань', formatString: '# ¥' }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/currencies', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ id: 'CNY', amount: 12.7, amountCnt: 1, sort: 300, fullName: 'Китайский юань', formatString: '# ¥' }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | string | Код валюты (RUB, USD, EUR) | | `amountCnt` | number | Количество единиц для курса | | `amount` | number | Курс обмена | | `sort` | number | Сортировка | | `base` | boolean | Базовая валюта | | `fullName` | string | Название (руб., $) | | `lid` | string | Идентификатор сайта, к которому привязана валюта | | `formatString` | string | Формат отображения | | `decPoint` | string | Разделитель дробной части | | `thousandsSep` | string | Разделитель тысяч | | `decimals` | number | Знаков после запятой | | `dateUpdate` | datetime | Дата последнего изменения | | `lang` | object | Настройки отображения по языкам — формат, название, разделители, с ключом-идентификатором языка. Заполняется из плоских полей запроса для языка вашего API-ключа | ## Пример ответа Успешный запрос возвращает полный объект созданной валюты со статусом `201`. ```json { "success": true, "data": { "id": "CNY", "fullName": "Китайский юань", "amount": 12.7, "amountCnt": 1, "base": false, "sort": 300, "lid": "ru", "formatString": "# ¥", "decimals": 2, "decPoint": ".", "thousandsSep": " ", "dateUpdate": "2024-11-12T07:20:08.000Z", "lang": { "ru": { "FORMAT_STRING": "# ¥", "FULL_NAME": "Китайский юань", "DEC_POINT": ".", "THOUSANDS_SEP": " ", "DECIMALS": "2", "THOUSANDS_VARIANT": "S", "HIDE_ZERO": "N" } } } } ``` ## Пример ответа при ошибке 422 — валюта с таким `id` уже заведена: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Валюта с таким идентификатором уже существует
" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `READONLY_FIELD` | В теле передано поле только для чтения, например `LANG` или `dateUpdate`. Имя поля указано в `message` | | 422 | `BITRIX_ERROR` | Не передан `formatString` — сообщение `Не заполнено поле "Формат" для языка ru` | | 422 | `BITRIX_ERROR` | Валюта с таким `id` уже существует | | 422 | `BITRIX_ERROR` | `id` не из трёх латинских букв — сообщение `Идентификатор валюты должен состоять из 3-х символов латинского алфавита` | | 422 | `BITRIX_ERROR` | `amount` равен нулю — сообщение `Неверный курс по умолчанию` | | 422 | `BITRIX_ERROR` | Прочие отказы валидации Битрикс24 — конкретная причина в `message` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | Не передан API-ключ | Полный список ошибок — [Ошибки](/docs/errors). ## Смотрите также - [Список валют](/docs/entities/currencies/list) - [Описание полей](/docs/entities/currencies/fields) - [Валюты](/docs/entities/currencies) --- # Currencies: Delete ## Удалить валюту `DELETE /v1/currencies/:id` Удаляет валюту из CRM по коду. Базовую валюту портала удалить нельзя. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | string | да | Код валюты (например `CNY`, `USD`) | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/currencies/CNY" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/currencies/CNY" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/currencies/CNY', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) if (res.status === 204) { console.log('Валюта удалена') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/currencies/CNY', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 422 — попытка удалить базовую валюту: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Нельзя удалить базовую валюту." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Невозможно удалить (базовая валюта или валюта не найдена) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | Не передан API-ключ | Полный список ошибок — [Ошибки](/docs/errors). ## Смотрите также - [Список валют](/docs/entities/currencies/list) - [Валюты](/docs/entities/currencies) --- # Currencies: Fields ## Поля валюты `GET /v1/currencies/fields` Возвращает описание всех полей сущности с типами и атрибутами. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/currencies/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/currencies/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/currencies/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/currencies/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | RO | Описание | |------|-----|:--:|---------| | `id` | string | | Код валюты (RUB, USD, EUR). Задаётся при создании валюты | | `amount` | number | | Курс обмена | | `amountCnt` | number | | Количество единиц для курса | | `base` | boolean | | Базовая валюта | | `sort` | number | | Сортировка | | `fullName` | string | | Название (руб., $) | | `formatString` | string | | Формат отображения | | `decPoint` | string | | Разделитель дробной части | | `thousandsSep` | string | | Разделитель тысяч | | `decimals` | number | | Знаков после запятой | | `lid` | string | да | Идентификатор сайта, к которому привязана валюта | | `dateUpdate` | datetime | да | Дата последнего изменения | | `lang` | object | да | Настройки отображения по языкам — формат, название, разделители, с ключом-идентификатором языка. Приходит в ответах `POST /v1/currencies` и `GET /v1/currencies/:id`. В списке `GET /v1/currencies` не возвращается | ## Пример ответа `GET /v1/currencies/fields` возвращает описания полей под ключом `data.fields` (имена — camelCase, как в ответах API), где каждое поле — `{ type, readonly, label, description }`. Значения `label`/`description` приходят на русском языке. Плюс `data.batch` со списком доступных batch-операций. ```json { "success": true, "data": { "fields": { "id": { "type": "string", "readonly": false, "label": "Код валюты", "description": "Код валюты по ISO 4217 (RUB, USD, EUR). Задаётся при создании." }, "amount": { "type": "number", "readonly": false, "label": "Курс обмена", "description": "Курс обмена относительно базовой валюты." }, "amountCnt": { "type": "number", "readonly": false, "label": "Номинал", "description": "Количество единиц валюты, для которых указан курс." }, "base": { "type": "boolean", "readonly": false, "label": "Базовая валюта", "description": "Является ли валюта базовой для портала." }, "sort": { "type": "number", "readonly": false, "label": "Сортировка", "description": "Порядок сортировки в списке валют." }, "fullName": { "type": "string", "readonly": false, "label": "Название", "description": "Отображаемое название валюты." }, "formatString": { "type": "string", "readonly": false, "label": "Строка формата вывода", "description": "Шаблон вывода сумм в этой валюте (# — место для числа)." }, "decimals": { "type": "number", "readonly": false, "label": "Количество десятичных знаков", "description": "Сколько знаков показывать после запятой." }, "decPoint": { "type": "string", "readonly": false, "label": "Десятичный разделитель", "description": "Символ, используемый как разделитель дробной части." }, "thousandsSep": { "type": "string", "readonly": false, "label": "Разделитель тысяч", "description": "Символ, используемый как разделитель тысяч." }, "lid": { "type": "string", "readonly": true, "label": "Сайт", "description": "Идентификатор сайта, к которому привязана валюта." }, "dateUpdate": { "type": "datetime", "readonly": true, "label": "Дата изменения", "description": "Дата последнего изменения валюты." }, "lang": { "type": "object", "readonly": true, "label": "Привязка к языку", "description": "Настройки отображения по языкам (формат, название, разделители), с ключом-идентификатором языка. Возвращается только в GET /:id." } }, "batch": ["create", "update", "delete"] } } ``` Описание `lang` в этом ответе говорит, что поле приходит только в `GET /v1/currencies/:id`. Это известное расхождение: `lang` приходит и в ответе `POST /v1/currencies`. Описание в схеме будет исправлено, таблица выше отражает фактическое поведение. ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | Не передан API-ключ | Полный список ошибок — [Ошибки](/docs/errors). ## Смотрите также - [Валюты](/docs/entities/currencies) - [Список валют](/docs/entities/currencies/list) --- # Currencies: Get ## Получить валюту `GET /v1/currencies/:id` Возвращает валюту по коду (RUB, USD, EUR). ## Параметры пути | Параметр | Тип | Описание | |----------|-----|---------| | `id` | string | Код валюты (RUB, USD, EUR) | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/currencies/USD" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/currencies/USD" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/currencies/USD', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/currencies/USD', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | string | Код валюты (RUB, USD, EUR) | | `amountCnt` | number | Количество единиц для курса | | `amount` | number | Курс обмена | | `sort` | number | Сортировка | | `base` | boolean | Базовая валюта | | `fullName` | string | Название (руб., $) | | `lid` | string | Идентификатор сайта, к которому привязана валюта | | `formatString` | string | Формат отображения | | `decPoint` | string | Разделитель дробной части | | `thousandsSep` | string | Разделитель тысяч | | `decimals` | number | Знаков после запятой | | `dateUpdate` | datetime | Дата последнего изменения | ## Пример ответа ```json { "success": true, "data": { "id": "USD", "fullName": "Доллар США", "amount": 92.5, "amountCnt": 1, "base": false, "sort": 200, "lid": "ru", "formatString": "$#", "decimals": 2, "decPoint": ".", "thousandsSep": ",", "dateUpdate": "2024-11-12T07:20:08.000Z" } } ``` ## Пример ответа при ошибке ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Валюта не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | Не передан API-ключ | Полный список ошибок — [Ошибки](/docs/errors). ## Смотрите также - [Список валют](/docs/entities/currencies/list) - [Обновить валюту](/docs/entities/currencies/update) - [Валюты](/docs/entities/currencies) --- # Currencies: List ## Список валют `GET /v1/currencies` Возвращает список валют портала с курсами обмена. В справочнике единицы записей. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей | | `offset` | number | `0` | Пропустить N записей | | `select` | string | — | Выборка полей: `?select=id,fullName,amount` | | `order` | object | — | Сортировка: `?order[sort]=asc` | | `filter` | object | — | Не поддерживается для валют. Любой ключ возвращает `400 UNSUPPORTED_FILTER`. Получите весь справочник и отфильтруйте записи на стороне клиента | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/currencies?select=id,fullName,amount,base" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/currencies?select=id,fullName,amount,base" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/currencies?select=id,fullName,amount,base', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data, meta } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/currencies?select=id,fullName,amount,base', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data[].id` | string | Код валюты (RUB, USD, EUR) | | `data[].amountCnt` | number | Количество единиц для курса | | `data[].amount` | number | Курс обмена | | `data[].sort` | number | Сортировка | | `data[].base` | boolean | Базовая валюта | | `data[].fullName` | string | Название (руб., $) | | `data[].LID` | string | Язык | | `data[].formatString` | string | Формат отображения | | `data[].decPoint` | string | Разделитель дробной части | | `data[].thousandsSep` | string | Разделитель тысяч | | `data[].decimals` | number | Знаков после запятой | ## Пример ответа ```json { "success": true, "data": [ { "id": "RUB", "fullName": "Российский рубль", "amount": 1, "amountCnt": 1, "base": true, "sort": 100, "formatString": "# руб.", "decimals": 2, "decPoint": ".", "thousandsSep": " " }, { "id": "USD", "fullName": "Доллар США", "amount": 92.5, "amountCnt": 1, "base": false, "sort": 200 } ], "meta": { "total": 3, "hasMore": false } } ``` ## Пример ответа при ошибке 400 — фильтрация не поддерживается: ```json { "success": false, "error": { "code": "UNSUPPORTED_FILTER", "message": "UNSUPPORTED_FILTER: 'currencies' does not support server-side filtering. Its Bitrix24 method (crm.currency.list) silently ignores every filter key and returns the full list — retrieve all records and filter client-side." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSUPPORTED_FILTER` | Передан любой ключ в `filter`. Валюты не фильтруются на стороне сервера — получите весь справочник и отфильтруйте записи на стороне клиента | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | Не передан API-ключ | Полный список ошибок — [Ошибки](/docs/errors). ## Смотрите также - [Валюты](/docs/entities/currencies) - [Создать валюту](/docs/entities/currencies/create) - [Поиск валют](/docs/entities/currencies/search) - [Агрегация валют](/docs/entities/currencies/aggregate) - [Batch](/docs/batch) --- # Currencies: Search ## Поиск валют `POST /v1/currencies/search` Возвращает валюты портала в теле POST-запроса — с выборкой полей, сортировкой и постраничным ограничением. Фильтрация на стороне сервера для валют не поддерживается: любой ключ в `filter` возвращает `400 UNSUPPORTED_FILTER`. Чтобы отобрать нужные валюты, получите весь справочник и отфильтруйте записи на стороне клиента. Валют на портале единицы, поэтому запрос возвращает тот же справочник, что и [список валют](/docs/entities/currencies/list) — отличается только передачей параметров в теле запроса вместо строки запроса. ## Поля запроса (body) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `select` | string[] | — | Выборка полей: `["id", "fullName", "amount"]` | | `order` | object | — | Сортировка: `{ "sort": "asc" }` | | `limit` | number | `50` | Количество записей | | `offset` | number | `0` | Пропустить N записей от начала выборки | | `filter` | object | — | Не поддерживается для валют. Любой ключ возвращает `400 UNSUPPORTED_FILTER`. Получите весь справочник и отфильтруйте записи на стороне клиента | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/currencies/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "select": ["id", "fullName", "amount", "base"], "order": { "sort": "asc" }, "limit": 3 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/currencies/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "select": ["id", "fullName", "amount", "base"], "order": { "sort": "asc" }, "limit": 3 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/currencies/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ select: ['id', 'fullName', 'amount', 'base'], order: { sort: 'asc' }, limit: 3, }), }) const { success, data, meta } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/currencies/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ select: ['id', 'fullName', 'amount', 'base'], order: { sort: 'asc' }, limit: 3, }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив валют (поля — см. [Поля](/docs/entities/currencies/fields)) | | `meta.total` | number | Сколько валют в справочнике | | `meta.hasMore` | boolean | Есть ли следующая страница | | `meta.durationMs` | number | Длительность запроса в миллисекундах | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа ```json { "success": true, "data": [ { "id": "RUB", "fullName": "руб.", "amount": 1, "base": true }, { "id": "THB", "fullName": "Бат", "amount": 5, "base": false }, { "id": "USD", "fullName": "Доллар США", "amount": 1, "base": false } ], "meta": { "total": 7, "hasMore": true, "durationMs": 148 } } ``` ## Пример ответа при ошибке 400 — фильтрация не поддерживается: ```json { "success": false, "error": { "code": "UNSUPPORTED_FILTER", "message": "UNSUPPORTED_FILTER: 'currencies' does not support server-side filtering. Its Bitrix24 method (crm.currency.list) silently ignores every filter key and returns the full list — retrieve all records and filter client-side." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSUPPORTED_FILTER` | Передан любой ключ в `filter`. Валюты не фильтруются на стороне сервера — получите весь справочник и отфильтруйте записи на стороне клиента | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | Не передан API-ключ | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Валюты](/docs/entities/currencies) - [Список валют](/docs/entities/currencies/list) - [Агрегация валют](/docs/entities/currencies/aggregate) - [Batch](/docs/batch) --- # Currencies: Update ## Обновить валюту `PATCH /v1/currencies/:id` Обновляет поля валюты по коду. Используйте для обновления курса обмена. ## Параметры пути | Параметр | Тип | Описание | |----------|-----|---------| | `id` | string | Код валюты (RUB, USD, EUR) | ## Параметры тела запроса | Параметр | Тип | Описание | |----------|-----|---------| | `amount` | number | Курс обмена | | `amountCnt` | number | Количество единиц для курса | | `sort` | number | Порядок сортировки | | `fullName` | string | Название валюты | | `formatString` | string | Шаблон отображения, например `# ₽` | | `decimals` | number | Число знаков после запятой | | `decPoint` | string | Десятичный разделитель | | `thousandsSep` | string | Разделитель тысяч | > **Локализуемые поля можно передавать плоско.** `fullName`, `formatString`, `decimals`, `decPoint`, `thousandsSep` API упаковывает в локализацию **вашего** языка (языка API-ключа), поэтому плоское обновление сохраняется и читается обратно. Сырой объект `LANG` в теле передавать **нельзя** — поле только для чтения, вернётся `400 READONLY_FIELD`. Задание разных значений сразу для нескольких языков через API пока не поддерживается. ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/currencies/USD" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"amount": 94.2}' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/currencies/USD" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"amount": 94.2}' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/currencies/USD', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ amount: 94.2 }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/currencies/USD', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ amount: 94.2 }), }) const { success, data } = await res.json() ``` ## Поля ответа После записи возвращается полный объект валюты. | Поле | Тип | Описание | |------|-----|---------| | `id` | string | Код валюты (RUB, USD, EUR) | | `amountCnt` | number | Количество единиц для курса | | `amount` | number | Курс обмена | | `sort` | number | Сортировка | | `base` | boolean | Базовая валюта | | `fullName` | string | Название (руб., $) | | `lid` | string | Идентификатор сайта, к которому привязана валюта | | `formatString` | string | Формат отображения | | `decPoint` | string | Разделитель дробной части | | `thousandsSep` | string | Разделитель тысяч | | `decimals` | number | Знаков после запятой | | `dateUpdate` | datetime | Дата последнего изменения | ## Пример ответа ```json { "success": true, "data": { "id": "USD", "fullName": "Доллар США", "amount": 94.2, "amountCnt": 1, "base": false, "sort": 200, "lid": "ru", "formatString": "$#", "decimals": 2, "decPoint": ".", "thousandsSep": ",", "dateUpdate": "2024-11-12T07:20:08.000Z" } } ``` ## Пример ответа при ошибке ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Currency is not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Валюта не найдена | | 400 | `READONLY_FIELD` | В теле передано поле только для чтения, например `LANG` или `dateUpdate`. Имя поля указано в `message` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | Не передан API-ключ | Полный список ошибок — [Ошибки](/docs/errors). ## Смотрите также - [Получить валюту](/docs/entities/currencies/get) - [Описание полей](/docs/entities/currencies/fields) - [Валюты](/docs/entities/currencies) --- # Deal Categories: Aggregate ## Агрегация воронок `POST /v1/deal-categories/aggregate` Подсчёт количества воронок и числовые агрегаты по фильтру. Без тела запроса возвращает общее количество воронок одним вызовом, без выгрузки записей. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций. Каждый элемент: `{ "field": "sort", "function": "sum" }`. Функции: `count`, `sum`, `avg`, `min`, `max`. Для `count` поле — `"*"`. Без массива возвращается только `count` | | `filter` | object | нет | Точное равенство и `$in` по `id`, `name`, `sort`. Фильтр по `isLocked` или `createdAt` даёт `400 UNSUPPORTED_FILTER`. [Синтаксис фильтрации](/docs/filtering) | Числовые функции (`sum`/`avg`/`min`/`max`) применимы к числовым полям воронки — `sort`. Группировка (`groupBy`) недоступна: у воронок нет категориальных полей для группировки, запрос с `groupBy` возвращает `400 INVALID_PARAMS`. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/deal-categories/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{}' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/deal-categories/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{}' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deal-categories/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({}), }) const { success, data } = await res.json() console.log('Всего воронок:', data.count) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deal-categories/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({}), }) const { success, data } = await res.json() ``` ## Другие сценарии Подсчёт записей — `count` с полем `"*"`, самый быстрый запрос без выгрузки записей. Без массива `aggregate` результат тот же: ```json { "aggregate": [{ "field": "*", "function": "count" }] } ``` Сумма поля `sort` по всем воронкам: ```json { "aggregate": [{ "field": "sort", "function": "sum" }] } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Общее количество воронок под фильтр | | `data.aggregates` | object | Результаты числовых агрегаций по полям. Пустой объект, если массив `aggregate` не передан | | `data.meta.totalRecords` | number | Общее количество воронок под фильтр | | `data.meta.recordsProcessed` | number | Сколько записей обработано: `0` для чистого `count`, число записей при числовых функциях | | `data.meta.truncated` | boolean | `true`, если под фильтр попало больше 5000 записей | ## Пример ответа Запрос количества (тело `{}`): ```json { "success": true, "data": { "count": 6, "aggregates": {}, "meta": { "totalRecords": 6, "recordsProcessed": 0, "truncated": false } } } ``` Сумма поля `sort` (тело `{ "aggregate": [{ "field": "sort", "function": "sum" }] }`): ```json { "success": true, "data": { "count": 6, "aggregates": { "sort": { "sum": 2410 } }, "meta": { "totalRecords": 6, "recordsProcessed": 6, "truncated": false } } } ``` ## Пример ответа при ошибке 400 — передан `groupBy` (у воронок нет полей для группировки): ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "groupBy field 'isLocked' is not aggregatable on this entity. Available: ." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Передан `groupBy` или числовая функция по нечисловому полю | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список воронок](/docs/entities/deal-categories/list) - [Поиск воронок](/docs/entities/deal-categories/search) - [Синтаксис фильтрации](/docs/filtering) --- # Deal Categories: Create ## Создать воронку `POST /v1/deal-categories` Создаёт новую воронку сделок. После создания добавьте стадии через [справочники](/docs/entities/statuses) с `entityId = DEAL_STAGE_{id}`. ## Параметры тела запроса | Параметр | Тип | Обязат. | Описание | |----------|-----|:-------:|---------| | `name` | string | да | Название воронки | | `sort` | number | | Порядок сортировки | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/deal-categories" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "Корпоративные продажи", "sort": 200}' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/deal-categories" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name": "Корпоративные продажи", "sort": 200}' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deal-categories', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Корпоративные продажи', sort: 200 }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deal-categories', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Корпоративные продажи', sort: 200 }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID воронки | | `name` | string | Название | | `sort` | number | Сортировка | | `isLocked` | boolean | Заблокирована ли воронка — недоступна на текущем тарифе | | `createdAt` | datetime | Дата создания | ## Пример ответа ```json { "success": true, "data": { "id": 5, "createdAt": "2026-06-01T10:00:00.000Z", "name": "Оптовые продажи", "sort": 200, "isLocked": false } } ``` ## Пример ответа при ошибке ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "NAME is required" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `BITRIX_ERROR` | Ошибка Битрикс24 | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | Не передан API-ключ | Полный список ошибок — [Ошибки](/docs/errors). ## Смотрите также - [Справочники CRM](/docs/entities/statuses) - [Описание полей](/docs/entities/deal-categories/fields) - [Воронки сделок](/docs/entities/deal-categories) --- # Deal Categories: Delete ## Удалить воронку `DELETE /v1/deal-categories/:id` Удаляет воронку сделок по ID. Основную воронку (ID 0) удалить нельзя. При удалении все сделки переносятся в основную воронку. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID воронки | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/deal-categories/3" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/deal-categories/3" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deal-categories/3', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) if (res.status === 204) { console.log('Воронка удалена') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deal-categories/3', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — воронка не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Not found." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Воронка не найдена | | 422 | `BITRIX_ERROR` | ID некорректен или попытка удалить основную воронку (ID 0) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | Не передан API-ключ | Полный список ошибок — [Ошибки](/docs/errors). ## Смотрите также - [Список воронок](/docs/entities/deal-categories/list) - [Сделки](/docs/entities/deals) - [Воронки сделок](/docs/entities/deal-categories) --- # Deal Categories: Fields ## Поля воронки `GET /v1/deal-categories/fields` Возвращает описание всех полей воронки с типами и атрибутами. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/deal-categories/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/deal-categories/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deal-categories/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deal-categories/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа Объект `data` содержит карту `fields` и список `batch` с операциями, доступными в массовом режиме. Каждое поле карты описано типом `type`, признаком `readonly`, подписью `label` и описанием `description`. | Поле | Тип | RO | Описание | |------|-----|:--:|---------| | `id` | number | да | ID воронки | | `name` | string | | Название | | `sort` | number | | Сортировка | | `isLocked` | boolean | да | Заблокирована ли воронка — недоступна на текущем тарифе | | `createdAt` | datetime | да | Дата создания | ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "ID", "description": "Уникальный идентификатор воронки (категории) сделок." }, "name": { "type": "string", "readonly": false, "label": "Название", "description": "Отображаемое название воронки." }, "sort": { "type": "number", "readonly": false, "label": "Сортировка", "description": "Порядок сортировки среди воронок." }, "isLocked": { "type": "boolean", "readonly": true, "label": "Заблокирована", "description": "Заблокирована ли воронка (недоступна на текущем тарифе)." }, "createdAt": { "type": "datetime", "readonly": true, "label": "Дата создания", "description": "Когда воронка была создана." } }, "batch": ["create", "update", "delete"] } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | Не передан API-ключ | Полный список ошибок — [Ошибки](/docs/errors). ## Смотрите также - [Воронки сделок](/docs/entities/deal-categories) - [Список воронок](/docs/entities/deal-categories/list) - [Сделки](/docs/entities/deals) --- # Deal Categories: Get ## Получить воронку `GET /v1/deal-categories/:id` Возвращает воронку сделок по ID. ## Параметры пути | Параметр | Тип | Описание | |----------|-----|---------| | `id` | number | ID воронки. Список — `GET /v1/deal-categories` | Основная воронка с id `0` через этот эндпоинт недоступна — для неё используйте `/v1/categories/2/0`. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/deal-categories/3" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/deal-categories/3" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deal-categories/3', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deal-categories/3', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID воронки | | `name` | string | Название | | `sort` | number | Сортировка | | `isLocked` | boolean | Заблокирована ли воронка — недоступна на текущем тарифе | | `createdAt` | datetime | Дата создания | ## Пример ответа ```json { "success": true, "data": { "id": 3, "name": "Корпоративные продажи", "sort": 200, "isLocked": false, "createdAt": "2025-06-01T14:00:00.000Z" } } ``` ## Пример ответа при ошибке ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Воронка не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | Не передан API-ключ | Полный список ошибок — [Ошибки](/docs/errors). ## Смотрите также - [Список воронок](/docs/entities/deal-categories/list) - [Обновить воронку](/docs/entities/deal-categories/update) - [Воронки сделок](/docs/entities/deal-categories) --- # Deal Categories: List ## Список воронок `GET /v1/deal-categories` Возвращает список воронок сделок портала с поддержкой сортировки и пагинации. Основная воронка с id `0` в список не входит — она доступна через `/v1/categories/2`. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей | | `offset` | number | `0` | Пропустить N записей | | `select` | string | — | Выборка полей: `?select=id,name,sort` | | `order` | object | — | Сортировка: `?order[sort]=asc` | | `filter` | object | — | Только точное равенство и `$in` (IN-множество) по полям `id`, `name`, `sort`. Операторы (`>`, `>=`, `<`, `<=`, `!`, `%`, `$ne`, `$contains`, `$nin`) и фильтрация по `isLocked` / `createdAt` не поддерживаются — вернётся `400 UNSUPPORTED_FILTER`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[name]=Newest` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/deal-categories?order[sort]=asc" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/deal-categories?order[sort]=asc" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deal-categories?order[sort]=asc', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data, meta } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deal-categories?order[sort]=asc', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data[].id` | number | ID воронки | | `data[].name` | string | Название | | `data[].sort` | number | Сортировка | | `data[].isLocked` | boolean | Заблокирована ли воронка — недоступна на текущем тарифе | | `data[].createdAt` | datetime | Дата создания | ## Пример ответа ```json { "success": true, "data": [ { "id": 1, "name": "Продажи", "sort": 100, "isLocked": false, "createdAt": "2025-01-15T10:30:00.000Z" }, { "id": 3, "name": "Корпоративные продажи", "sort": 200, "isLocked": false, "createdAt": "2025-06-01T14:00:00.000Z" } ], "meta": { "total": 2, "hasMore": false } } ``` ## Пример ответа при ошибке ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSUPPORTED_FILTER` | Оператор или неподдерживаемое поле в фильтре. Фильтруйте точным равенством или `$in` по `id`, `name`, `sort` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | Не передан API-ключ | Полный список ошибок — [Ошибки](/docs/errors). ## Известные особенности **Только точное равенство в фильтре.** Фильтр применяется точным равенством (и `$in`-множеством) по `id`, `name`, `sort`. Операторы (`>`, `<`, `!`, `%`), `$ne`/`$contains`/`$nin` и фильтрация по `isLocked` / `createdAt` дают `400 UNSUPPORTED_FILTER` — так вы сразу видите, что фильтр не применился, а не получаете весь список без фильтра. `isLocked` в Битрикс24 — переключатель видимости выборки, а не поле для равенства: значение `Y` возвращает все воронки, `N` — все кроме заблокированных. В ответе это поле приходит булевым. Сортировка `order` по `sort` при этом работает. ## Смотрите также - [Воронки сделок](/docs/entities/deal-categories) - [Создать воронку](/docs/entities/deal-categories/create) - [Сделки](/docs/entities/deals) - [Batch](/docs/batch) --- # Deal Categories: Search ## Поиск воронок `POST /v1/deal-categories/search` Поиск воронок сделок с фильтрами через тело запроса — единый интерфейс с остальными сущностями. Для простых выборок по одному-двум полям подойдёт и [`GET /v1/deal-categories`](/docs/entities/deal-categories/list) с query-фильтром. ## Поля запроса (body) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Только точное равенство и `$in` (IN-множество) по полям `id`, `name`, `sort`. Операторы (`>`, `>=`, `<`, `<=`, `!`, `%`, `$ne`, `$contains`, `$nin`) и фильтрация по `isLocked` / `createdAt` не поддерживаются — вернётся `400 UNSUPPORTED_FILTER`.
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "id": { "$in": [1, 11] } }` | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей | | `order` | object | — | Сортировка: `{ "sort": "asc" }` | | `select` | string[] | — | Выборка полей: `["id", "name", "sort"]` | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/deal-categories/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "id": { "$in": [1, 11] } }, "order": { "sort": "asc" }, "select": ["id", "name", "sort"], "limit": 3 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/deal-categories/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "id": { "$in": [1, 11] } }, "order": { "sort": "asc" }, "select": ["id", "name", "sort"], "limit": 3 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deal-categories/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { id: { $in: [1, 11] } }, order: { sort: 'asc' }, select: ['id', 'name', 'sort'], limit: 3, }), }) const { success, data, meta } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deal-categories/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { id: { $in: [1, 11] } }, order: { sort: 'asc' }, select: ['id', 'name', 'sort'], limit: 3, }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив воронок (поля — см. [Поля](/docs/entities/deal-categories/fields)) | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа В запросе передан `select`, поэтому в ответе только выбранные поля. ```json { "success": true, "data": [ { "id": 1, "name": "Newest", "sort": 100 }, { "id": 11, "name": "English", "sort": 200 } ], "meta": { "total": 2, "hasMore": false, "durationMs": 167 } } ``` ## Пример ответа при ошибке 400 — неподдерживаемое поле в фильтре (`isLocked` — переключатель видимости, не поле для равенства): ```json { "success": false, "error": { "code": "UNSUPPORTED_FILTER", "message": "UNSUPPORTED_FILTER: 'isLocked' is not filterable on 'deal-categories'. Its Bitrix24 method (crm.dealcategory.list) filters by exact match only. Filterable: id, name, sort." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSUPPORTED_FILTER` | Оператор или неподдерживаемое поле в фильтре. Фильтруйте точным равенством или `$in` по `id`, `name`, `sort` | | 400 | `INVALID_PARAMS` | Нарушена валидация полей запроса | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список воронок](/docs/entities/deal-categories/list) - [Агрегация воронок](/docs/entities/deal-categories/aggregate) - [Синтаксис фильтрации](/docs/filtering) - [Сделки](/docs/entities/deals) --- # Deal Categories: Update ## Обновить воронку `PATCH /v1/deal-categories/:id` Обновляет поля воронки сделок по ID. ## Параметры пути | Параметр | Тип | Описание | |----------|-----|---------| | `id` | number | ID воронки | ## Параметры тела запроса | Параметр | Тип | Описание | |----------|-----|---------| | `name` | string | Название воронки | | `sort` | number | Порядок сортировки | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/deal-categories/3" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "Корпоративные продажи B2B"}' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/deal-categories/3" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name": "Корпоративные продажи B2B"}' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deal-categories/3', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Корпоративные продажи B2B' }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deal-categories/3', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Корпоративные продажи B2B' }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | object | Полный объект воронки после обновления | ## Пример ответа ```json { "success": true, "data": { "id": 5, "createdAt": "2026-06-01T10:00:00.000Z", "name": "Оптовые продажи", "sort": 200, "isLocked": false } } ``` ## Пример ответа при ошибке ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Not found." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Воронка не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | Не передан API-ключ | Полный список ошибок — [Ошибки](/docs/errors). ## Смотрите также - [Получить воронку](/docs/entities/deal-categories/get) - [Описание полей](/docs/entities/deal-categories/fields) - [Воронки сделок](/docs/entities/deal-categories) --- # Deals: Aggregate ## Агрегация сделок `POST /v1/deals/aggregate` Подсчёт количества, сумма, среднее, минимум и максимум по сделкам с фильтрацией и группировкой. **Стандартные поля:** - `amount` — сумма сделки (числовое агрегирование имеет смысл) - `stageId` — стадия (для `groupBy`) - `categoryId` — воронка (для `groupBy`) - `assignedById` — ответственный (для `groupBy`) - `sourceId` — источник (для `groupBy`) **Пользовательские поля (UF):** поля типов `integer`, `double`, `money` — для числовых функций, поля любого типа — для `groupBy`. Полный список UF-полей конкретного портала приходит в тексте ошибки `INVALID_PARAMS`, если передать несуществующее имя. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций. Каждый элемент: `{ "field": "amount", "function": "sum" }`. Функции: `count`, `sum`, `avg`, `min`, `max`. Для `count` поле — `"*"`. Без массива — только `count` | | `filter` | object | нет | Фильтрация по полям `GET /v1/deals/fields`. [Синтаксис фильтрации](/docs/filtering) | | `groupBy` | string \| string[] | нет | Поле или массив полей для группировки (максимум 5). Допустимые значения — из списка выше | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/deals/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "amount", "function": "sum" }, { "field": "amount", "function": "avg" } ], "filter": { "categoryId": 0 }, "groupBy": "stageId" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/deals/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "amount", "function": "sum" }, { "field": "amount", "function": "avg" } ], "filter": { "categoryId": 0 }, "groupBy": "stageId" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [ { field: 'amount', function: 'sum' }, { field: 'amount', function: 'avg' }, ], filter: { categoryId: 0 }, groupBy: 'stageId', }), }) const { success, data } = await res.json() console.log('Всего сделок в воронке:', data.count) console.log('По стадиям:', data.groups) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [ { field: 'amount', function: 'sum' }, { field: 'amount', function: 'avg' }, ], filter: { categoryId: 0 }, groupBy: 'stageId', }), }) const { success, data } = await res.json() ``` > Для группировки по нескольким полям передайте массив: `"groupBy": ["stageId", "sourceId"]` (максимум 5). ## Другие сценарии Подсчёт записей — `count` с полем `"*"`, самый быстрый запрос без выгрузки записей. Без массива `aggregate` результат тот же: ```json { "aggregate": [{ "field": "*", "function": "count" }] } ``` Работа с пользовательскими полями (UF) — `sum` по UF + группировка по другому UF. Имя поля берётся из схемы [`GET /v1/deals/fields`](/docs/entities/deals/fields), на другое написание приходит `400 INVALID_PARAMS` со списком доступных полей: ```json { "aggregate": [{ "field": "ufCrmBudget", "function": "sum" }], "groupBy": "ufCrmPriority" } ``` Сводка по воронке — один запрос с группировкой по стадии и суммой даёт разбивку, из которой на стороне приложения считается конверсия в выигранные: ```json { "aggregate": [{ "field": "amount", "function": "sum" }], "filter": { "categoryId": 0 }, "groupBy": "stageId" } ``` В ответе `data.count` — всего сделок в воронке, `data.groups` — разбивка по стадиям с суммой и количеством. Идентификаторы стадий зависят от воронки — получить их можно из [Поля](/docs/entities/deals/fields). Конверсия считается из групп без отдельного запроса: ```javascript const total = data.count const won = data.groups.find(g => g.stageId === 'WON')?.count ?? 0 const conversion = total ? Math.round((won / total) * 100) : 0 console.log(`Сделок в воронке: ${total}, выиграно: ${won}, конверсия: ${conversion}%`) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Общее количество записей под фильтр | | `data.aggregates` | object | Результаты агрегаций: `{ "amount": { "sum": 100000, "avg": 2439 } }` | | `data.groups` | array | Группы (только при `groupBy`). Каждый элемент: поля группировки + `count` + `aggregates` | | `data.meta.totalRecords` | number | Общее количество записей под фильтр | | `data.meta.recordsProcessed` | number | Сколько записей обработано для числовых агрегаций (максимум 5000) | | `data.meta.truncated` | boolean | `true`, если под фильтр попало больше 5000 записей | ## Пример ответа Ответ на основной запрос (агрегации + `groupBy: "stageId"`): ```json { "success": true, "data": { "count": 41, "aggregates": { "amount": { "sum": 100000, "avg": 2439 } }, "groups": [ { "stageId": "NEW", "count": 25, "aggregates": { "amount": { "sum": 60000 } } }, { "stageId": "WON", "count": 16, "aggregates": { "amount": { "sum": 40000 } } } ], "meta": { "totalRecords": 41, "recordsProcessed": 41, "truncated": false } } } ``` Без `groupBy` поле `data.groups` в ответе отсутствует. ## Пример ответа при ошибке 400 — неверное имя функции, несуществующее поле или `groupBy` по неаггрегируемому полю: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "Field 'foo' not found. Available numeric fields: amount, stageId, categoryId, assignedById, sourceId" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Некорректное имя функции, несуществующее поле, нечисловое поле в `sum`/`avg`/`min`/`max`, `groupBy` по неаггрегируемому полю или больше 5 полей в `groupBy` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`count` и числовые функции — в чём разница.** `count` без `groupBy` считается одним вызовом в Битрикс24 на любом объёме данных. Функции `sum`/`avg`/`min`/`max` подгружают записи постранично (максимум 5000) и считают на стороне Вайбкод — если под фильтр попадает больше 5000 записей, `meta.truncated` будет `true`, агрегация выполнится по первым 5000. Для точных счётчиков на больших выборках используйте `count` или сужайте фильтр. Потолок общий для всех сущностей — [Агрегация POST — потолок 5000 записей](/docs/entity-api#агрегация-post-потолок-5000-записей). **Крупная воронка: два режима, включаются администратором платформы по аккаунтам.** Оба выключены по умолчанию. Пока они выключены, поведение ровно такое, как описано выше. - **Отказ вместо усечения.** Запрос, которому для ответа нужны строки (числовые функции и/или `groupBy`), при `total > 5000` отвечает `422 AGGREGATION_LIMIT_EXCEEDED` и не выгружает ни одной записи. Раньше он всё равно выгружал первые 5000 — на крупной воронке эта выгрузка не успевала и запрос обрывался по таймауту. В тексте ошибки перечислено, что делать дальше. - **Счётчики по стадиям без чтения строк.** `groupBy: ["stageId"]` или `["stageSemanticId"]` со скалярным `categoryId` в фильтре отвечает на воронке любого размера: количество по каждой стадии берётся отдельным дешёвым подсчётом на стороне Битрикс24. Признак такого ответа — `meta.aggregatePath: "fanout"`, `meta.recordsProcessed: 0`, `meta.truncated: false`. Числовые функции по стадиям остаются доступны, пока суммарный размер групп укладывается в 5000. **`meta.stageCountDelta`** приходит только в ответе со счётчиками по стадиям: разница между общим количеством и суммой по стадиям. Ноль означает, что разбиение полное. Ненулевое значение означает, что записи изменились между подсчётами. Ответ по-прежнему достоверен. `count` всегда равен общему количеству, а не сумме групп. **Money-поля.** UF-поля типа `money` хранятся в формате `"сумма|валюта"` (`"1500|RUB"`) — агрегат извлекает числовую часть автоматически, складывать можно без парсинга. **Фильтрация по UF работает.** В `filter` можно передавать любые поля — стандартные и пользовательские, любого типа. Например, `{ "filter": { "ufCrm_1234": "value" } }` вернёт количество сделок с этим значением UF. ## Смотрите также - [Список сделок](/docs/entities/deals/list) - [Поиск сделок](/docs/entities/deals/search) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Deals: Contacts # Контакты сделки Управление связями сделки с контактами (many-to-many). Поле `contactIds` в самой сделке доступно только для чтения — `PATCH /v1/deals/:id` его не меняет. Чтобы привязать, заменить или отвязать контакты, используйте эндпоинты ниже. Прочитать список контактов вместе со сделкой можно через `GET /v1/deals/:id?include=contact` (см. «Включение связанных сущностей»). Требуется scope `crm`. ## Поля связи | Поле | Тип | Описание | |----------|-----|---------| | `contactId` | number | ID контакта. Каталог: `GET /v1/contacts` | | `isPrimary` | boolean | Основной контакт сделки. Если ни один не помечен, основным станет первый | | `sort` | number | Порядок сортировки | | `roleId` | number | ID роли контакта (если используется) | ## Получить контакты сделки `GET /v1/deals/:id/contacts` Возвращает массив привязанных контактов. ```bash curl "https://vibecode.bitrix24.tech/v1/deals/741/contacts" \ -H "X-Api-Key: YOUR_API_KEY" ``` Ответ: ```json { "success": true, "data": [ { "contactId": 9, "sort": 10, "isPrimary": true, "roleId": 0 }, { "contactId": 17, "sort": 20, "isPrimary": false, "roleId": 0 } ] } ``` ## Добавить один контакт `POST /v1/deals/:id/contacts` Привязывает один контакт к сделке, не затрагивая уже привязанные. | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `contactId` | number | да | ID контакта | | `isPrimary` | boolean | нет | Сделать основным | | `sort` | number | нет | Порядок сортировки | ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/deals/741/contacts" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "contactId": 9, "isPrimary": true, "sort": 10 }' ``` Возвращает обновлённый список контактов сделки (как в `GET`). ## Заменить весь список контактов `PUT /v1/deals/:id/contacts` Полностью заменяет список контактов сделки. Контакты, не вошедшие в `items`, отвязываются. Передайте `"items": []`, чтобы отвязать все. | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `items` | array | да | Массив контактов (пустой массив отвязывает все) | | `items[].contactId` | number | да | ID контакта | | `items[].isPrimary` | boolean | нет | Основной контакт | | `items[].sort` | number | нет | Порядок сортировки | ```bash curl -X PUT "https://vibecode.bitrix24.tech/v1/deals/741/contacts" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "items": [ { "contactId": 16530, "isPrimary": true, "sort": 10 }, { "contactId": 16532, "isPrimary": false, "sort": 20 } ] }' ``` Возвращает обновлённый список контактов сделки (как в `GET`). ## Удалить один контакт `DELETE /v1/deals/:id/contacts/:contactId` Отвязывает один контакт. Если удаляется основной, основным становится первый из оставшихся. ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/deals/741/contacts/16530" \ -H "X-Api-Key: YOUR_API_KEY" ``` Возвращает `204 No Content`. ## Ошибки | Код | Когда | |-----|-------| | `INVALID_PARAMS` | В `PUT` поле `items` не массив, либо элемент без `contactId` | | `SCOPE_DENIED` | У ключа нет scope `crm` | | `WRITE_BLOCKED_READONLY_KEY` | Ключ в режиме READONLY — записи (`POST`/`PUT`/`DELETE`) запрещены | --- # Deals: Create ## Создать сделку `POST /v1/deals` Создаёт новую сделку в CRM. ## Поля запроса (body) | Параметр | Тип | Описание | |----------|-----|---------| | `title` | string | Название сделки | | `amount` | number | Сумма | | `currency` | string | Валюта. Список: `GET /v1/currencies` | | `stageId` | string | Стадия воронки. Стандартные: `NEW`, `PREPARATION`, `PREPAYMENT_INVOICE`, `EXECUTING`, `FINAL_INVOICE`, `WON`, `LOSE`. Портал может иметь свои — список: `GET /v1/statuses?filter[entityId]=DEAL_STAGE` | | `categoryId` | number | ID воронки (0 = основная). Список: `GET /v1/deal-categories` | | `companyId` | number | ID компании. Поиск: `GET /v1/companies` | | `contactId` | number | ID основного контакта. Поиск: `GET /v1/contacts` | | `assignedById` | number | ID ответственного. Список сотрудников: `GET /v1/users` | | `sourceId` | string | Источник. Список: `GET /v1/statuses?filter[entityId]=SOURCE` | | `sourceDescription` | string | Описание источника | | `comments` | string | Комментарий | | `opened` | boolean | Доступна для всех | | `closedAt` | datetime | Дата закрытия | | `probability` | number | Вероятность успеха (%) | | `observers` | number[] | Массив ID наблюдателей. Список сотрудников: `GET /v1/users` | Полный список полей: [GET /v1/deals/fields](/docs/entities/deals/fields). Пользовательские поля (`ufCrm_*`) также принимаются. ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/deals \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Поставка оборудования", "amount": 50000, "currency": "RUB", "stageId": "NEW", "categoryId": 0, "assignedById": 1 }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/deals \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Поставка оборудования", "amount": 50000, "currency": "RUB", "stageId": "NEW", "categoryId": 0, "assignedById": 1 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Поставка оборудования', amount: 50000, currency: 'RUB', stageId: 'NEW', categoryId: 0, assignedById: 1, }), }) const { success, data } = await res.json() console.log('Deal ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Поставка оборудования', amount: 50000, currency: 'RUB', stageId: 'NEW', categoryId: 0, assignedById: 1, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID созданной сделки | | `title` | string | Название | | `amount` | number | Сумма | | `currency` | string | Валюта | | `stageId` | string | Стадия | | `categoryId` | number | ID воронки | | `assignedById` | number | Ответственный | | `createdBy` | number | Создатель | | `createdAt` | datetime | Дата создания | | `updatedAt` | datetime | Дата изменения | | `entityTypeId` | number | Тип сущности (2 = сделки) | Ответ содержит все поля сделки, включая пользовательские (`ufCrm_*`). Выше показаны основные. URL карточки сделки в Битрикс24 строится из `id`: ``` https://.bitrix24.ru/crm/deal/details// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": { "id": 7689, "title": "Поставка оборудования", "amount": 50000, "currency": "RUB", "stageId": "NEW", "categoryId": 0, "assignedById": 1, "createdBy": 1, "createdAt": "2026-04-14T08:43:59.000Z", "updatedAt": "2026-04-14T08:43:59.000Z", "companyId": 0, "contactId": 0, "opened": true, "closed": false, "typeId": "SALE", "observers": [], "contactIds": [], "entityTypeId": 2 } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 400 | `INVALID_REQUEST` | Некорректные поля | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Работа с файлами в полях CRM](/docs/recipes/crm-files) - [Список сделок](/docs/entities/deals/list) - [Поля сделки](/docs/entities/deals/fields) - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Deals: Delete ## Удалить сделку `DELETE /v1/deals/:id` Удаляет сделку по ID. Восстановить удалённую сделку через API нельзя — создавайте новую при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID сделки | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/deals/7689" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/deals/7689" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/7689', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Сделка удалена') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/7689', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — сделка не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Сделка не найдена | | 403 | `ACCESS_DENIED` | Нет доступа к сделке | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список сделок](/docs/entities/deals/list) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Deals: Fields ## Поля сделки `GET /v1/deals/fields` Возвращает полный список доступных полей, включая пользовательские (`ufCrm_*`). ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/deals/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/deals/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Битрикс24 | Тип | RO | Описание | |------|----------|-----|:--:|---------| | `id` | `id` | number | да | ID сделки | | `title` | `title` | string | | Название | | `amount` | `opportunity` | number | | Сумма | | `currency` | `currencyId` | string | | Валюта. Список: `GET /v1/currencies` | | `stageId` | `stageId` | string | | Стадия воронки. Набор стадий и их идентификаторы настраиваются на стороне портала и отличаются между воронками. Актуальный список — `GET /v1/statuses?filter[entityId]=DEAL_STAGE` для основной воронки, `GET /v1/statuses?filter[entityId]=DEAL_STAGE_{N}` для воронки с `categoryId={N}` (значение `categoryId` берётся из `GET /v1/deal-categories`) | | `categoryId` | `categoryId` | number | | ID воронки (0 = основная). Список: `GET /v1/deal-categories` | | `stageSemanticId` | `stageSemanticId` | string | да | Смысловая категория текущей стадии: `P` — в работе, `S` — успех, `F` — провал | | `companyId` | `companyId` | number | | ID компании. Поиск: `GET /v1/companies` | | `contactId` | `contactId` | number | | ID основного контакта. Поиск: `GET /v1/contacts` | | `contactIds` | `contactIds` | number[] | да | Все привязанные контакты. Поиск: `GET /v1/contacts` | | `assignedById` | `assignedById` | number | | Ответственный. Список: `GET /v1/users` | | `createdBy` | `createdBy` | number | да | Создатель. Поиск: `GET /v1/users` | | `updatedBy` | `updatedBy` | number | да | Кто изменил. Поиск: `GET /v1/users` | | `createdAt` | `createdTime` | datetime | да | Дата создания | | `updatedAt` | `updatedTime` | datetime | да | Дата изменения | | `closedAt` | `closedate` | datetime | | Дата закрытия | | `closed` | `closed` | boolean | да | Закрыта ли сделка | | `sourceId` | `sourceId` | string | | Источник. Список: `GET /v1/statuses?filter[entityId]=SOURCE` | | `sourceDescription` | `sourceDescription` | string | | Описание источника | | `probability` | `probability` | number | | Вероятность успеха (%) | | `opened` | `opened` | boolean | | Доступна для всех | | `comments` | `comments` | string | | Комментарий | | `observers` | `observers` | number[] | | Наблюдатели. Список: `GET /v1/users` | | `typeId` | `typeId` | string | | Тип записи. Список: `GET /v1/statuses?filter[entityId]=DEAL_TYPE` | | `isReturning` | `isReturnCustomer` | boolean | | Повторная сделка | **Пользовательские поля** (`ufCrm_*`) также возвращаются в ответах и принимаются при создании/обновлении. ## Доступные include Эндпоинт `GET /v1/deals/fields` возвращает список доступных include: `contact`, `company`, `quote`. Пример использования: [Получить deals](/docs/entities/deals/get#связанные-данные). Подробнее об include: [Связанные данные](/docs/includes). ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "ID сделки", "description": "Уникальный числовой идентификатор сделки." }, "title": { "type": "string", "readonly": false, "label": "Название", "description": "Название сделки." }, "assignedById": { "type": "number", "readonly": false, "label": "Ответственный", "description": "ID ответственного пользователя. Список: GET /v1/users." }, "stageSemanticId": { "type": "string", "readonly": true, "label": "Семантика стадии", "description": "Смысловая категория текущей стадии — коды расшифрованы в enum.", "enum": [{ "value": "P", "label": "In progress", "labelRu": "В работе" }, { "value": "S", "label": "Success", "labelRu": "Успех" }, { "value": "F", "label": "Failure", "labelRu": "Провал" }] } }, "batch": ["create", "update", "delete"] } } ``` Показаны 3 из множества полей. Полный список в таблице выше. ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать сделку](/docs/entities/deals/create) - [Пользовательские поля](/docs/userfields) - [Entity API](/docs/entity-api) - [Лимиты и оптимизация](/docs/optimization) --- # Deals: Get ## Получить сделку `GET /v1/deals/:id` Возвращает сделку по ID со всеми полями, включая пользовательские (`ufCrm_*`). ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID сделки | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/deals/741" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/deals/741" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/741', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Сделка:', data.title, '—', data.amount, data.currency) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/741', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` Подробнее об include: [Связанные данные](/docs/includes). ## Поля ответа Объект сделки со всеми полями — см. [Поля сделки](/docs/entities/deals/fields). ## Связанные данные Получить связанные сущности вместе со сделкой — параметр `include` в GET-запросе: ``` GET /v1/deals/741?include=contact,company ``` Доступные include: `contact`, `company`, `quote`. Результат в поле `_included`: ```json { "success": true, "data": { "id": 741, "title": "Поставка оборудования", "_included": { "contacts": [{ "id": 71, "name": "Иван Петров", ... }], "company": { "id": 15, "title": "ООО Ромашка", ... } } } } ``` ## Пример ответа ```json { "success": true, "data": { "id": 741, "title": "Поставка оборудования", "amount": 50000, "currency": "RUB", "stageId": "EXECUTING", "categoryId": 0, "assignedById": 29, "createdBy": 1, "createdAt": "2020-09-25T13:08:24.000Z", "updatedAt": "2025-08-22T13:01:31.000Z", "contactId": 71, "companyId": 0, "opened": true, "observers": [], "contactIds": [], "entityTypeId": 2 } } ``` Ответ содержит все поля сделки, включая пользовательские (`ufCrm_*`). Выше показаны основные. ## Пример ответа при ошибке 404 — сделка не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Сделка с таким ID не найдена | | 403 | `ACCESS_DENIED` | Нет доступа к сделке | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Работа с файлами в полях CRM](/docs/recipes/crm-files) - [Поля сделки](/docs/entities/deals/fields) - [Обновить сделку](/docs/entities/deals/update) - [Список сделок](/docs/entities/deals/list) - [Лимиты и оптимизация](/docs/optimization) --- # Deals: List ## Список сделок `GET /v1/deals` Возвращает список сделок с поддержкой фильтрации, сортировки и авто-пагинации. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` ответ собирается из нескольких последовательных чтений по 50 записей | | `offset` | number | `0` | Пропустить N записей. При `offset > 0` рекомендуется `limit ≤ 500`. Для обхода всей коллекции дешевле курсор — `order[id]=asc` и `filter[>id]` из `meta.nextAfterId` | | `select` | string | — | Выборка полей: `?select=id,title,amount` | | `order` | object | — | Сортировка: `?order[createdAt]=desc` | | `filter` | object | — | Фильтрация по полям `GET /v1/deals/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[stageId]=NEW` | | `withTotal` | string | — | Нужно ли количество: `true` или `false`. `false` — не заказывать подсчёт. Это единственный способ гарантированно убрать `meta.total` из ответа. Без параметра — настройка ключа, затем платформенное умолчание, и тогда на короткой странице точное количество приходит и без заказа. [Листание и количество](/docs/entity-api#листание-и-количество-записей) | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/deals?limit=10&order[amount]=desc&filter[stageId]=NEW" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/deals?limit=10&order[amount]=desc&filter[stageId]=NEW" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals?limit=10&order[amount]=desc&filter[stageId]=NEW', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} сделок`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals?limit=10&order[amount]=desc&filter[stageId]=NEW', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив сделок (каждая содержит все поля — см. [Поля](/docs/entities/deals/fields)) | | `meta.total` | number | Общее количество записей, соответствующих фильтру. Необязательное поле: если количество не заказывалось, его в ответе нет | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.nextAfterId` | string | Идентификатор последней отданной записи. Приходит при сортировке строго по `id` по возрастанию, пока `hasMore` равен `true`. Передайте его обратно как `filter[>id]` — это дешёвая замена растущему `offset` | URL карточки любой сделки из массива `data` — её `id`: ``` https://.bitrix24.ru/crm/deal/details// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 741, "title": "Поставка оборудования", "amount": 50000, "currency": "RUB", "stageId": "NEW", "categoryId": 0, "assignedById": 1, "createdAt": "2026-04-14T08:43:59.000Z", "contactId": 71, "companyId": 0, "opened": true } ], "meta": { "total": 156, "hasMore": true } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет в схеме сделки. Сообщение содержит список доступных полей | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Авто-пагинация:** `limit > 50` выполняется несколькими последовательными чтениями по 50 записей, а ответ приходит одним массивом. Время ответа растёт вместе с `limit` — [Клиентский таймаут](/docs/optimization#клиентский-таймаут). **Ограничение `offset`:** при `offset ≥ 2500` ответ может прийти с `INTERNAL_ERROR`. Держите `limit ≤ 500` на больших смещениях, а всю коллекцию обходите курсором `filter[>id]` — он не зависит от глубины. **Когда использовать поиск.** Сложные фильтры с множеством условий передаются в теле запроса, а не в строке запроса. Поиск дополнительно разбивает широкий диапазон дат на окна — [Поиск с разбиением по датам](/docs/optimization#поиск-с-разбиением-по-датам). См. [Поиск сделок](/docs/entities/deals/search). ## Смотрите также - [Поиск сделок](/docs/entities/deals/search) - [Создать сделку](/docs/entities/deals/create) - [Синтаксис фильтрации](/docs/filtering) - [Обзор API](/docs/entity-api) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Deals: Products Add > Поле, которого нет среди записываемых, больше не отбрасывается молча — запрос отклоняется с `400 INVALID_PARAMS`, и в тексте ошибки перечислены записываемые имена. Поля только для чтения, которые приходят в ответах товарных позиций (`priceAccount`, `ownerId`, `storeId` и другие) по-прежнему принимаются и игнорируются, поэтому объект, прочитанный через GET, можно отправить обратно без чистки. ## Добавить товар в сделку `POST /v1/deals/:id/products` Добавляет одну товарную позицию в сделку. В отличие от `PUT /v1/deals/:id/products`, не заменяет существующие позиции. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID сделки | | `productId` | number | нет | ID товара из каталога. Если задан без `productName`, имя подставляется из каталога. Каталог: `GET /v1/products` | | `productName` | string | нет | Название товарной позиции — для произвольной строки без товара из каталога. Укажите хотя бы одно из `productId` / `productName`. | | `price` | number | нет | Цена за единицу | | `quantity` | number | нет | Количество | | `discount` | number | нет | Сумма скидки | | `taxRate` | number | нет | Ставка налога (%) | | `taxIncluded` | boolean | нет | Налог включён в цену | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/deals/741/products" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "productId": 1, "price": 25000, "quantity": 2 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/deals/741/products" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "productId": 1, "price": 25000, "quantity": 2 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/741/products', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ productId: 1, price: 25000, quantity: 2 }), }) const { success, data } = await res.json() console.log('ID строки:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/741/products', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ productId: 1, price: 25000, quantity: 2 }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | object | Созданная товарная строка целиком, HTTP-статус `201`. Состав полей — [Поля товаров](/docs/entities/deals/products-fields) | ## Пример ответа Показаны основные поля. Полный список — [Поля товаров](/docs/entities/deals/products-fields). ```json { "success": true, "data": { "id": 1465, "productId": 1, "productName": "Серверное оборудование", "price": 25000, "quantity": 2, "discount": 0, "discountTypeId": 2, "taxIncluded": false } } ``` ## Пример ответа при ошибке 404 — сделка не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Тело содержит имя, которого нет среди записываемых полей — см. [Поля товаров](/docs/entities/deals/products-fields) | | 404 | `ENTITY_NOT_FOUND` | Сделка не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Товарные позиции](/docs/entities/deals/products-get) - [Установить товары](/docs/entities/deals/products-set) - [Удалить товар](/docs/entities/deals/products-delete) - [Товары каталога](/docs/entities/products) --- # Deals: Products Delete ## Удалить товар из сделки `DELETE /v1/deals/:id/products/:rowId` Удаляет одну товарную позицию из сделки по ID строки. Восстановить удалённую позицию через API нельзя — добавляйте новую при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID сделки | | `rowId` (path) | number | да | ID товарной строки (из ответа add или list) | `rowId` — это ID товарной строки, а не `productId` из каталога товаров. ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/deals/741/products/1465" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/deals/741/products/1465" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/741/products/1465', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Товар удалён из сделки') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/741/products/1465', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — сделка не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Сделка или товарная строка не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Товарные позиции](/docs/entities/deals/products-get) - [Добавить товар](/docs/entities/deals/products-add) - [Установить товары](/docs/entities/deals/products-set) - [Товары каталога](/docs/entities/products) --- # Deals: Products Fields ## Поля товаров сделки `GET /v1/deals/:id/products/fields` Возвращает описание полей товарных позиций сделки: названия, типы, доступность для чтения и записи. > **Сумма скидки называется `discount`** — как в данных и при записи. Прежнее имя `discountSum` осталось устаревшим псевдонимом: оно по-прежнему приходит в этом справочнике и принимается при записи, поэтому код, написанный по старому списку полей, продолжает работать. В самих товарных позициях приходит только `discount` — переходите на него. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID сделки | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/deals/741/products/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/deals/741/products/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/741/products/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/741/products/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | RO | Обяз. | Описание | |------|-----|:--:|:-----:|---------| | `id` | integer | да | | ID позиции | | `productId` | integer | | да | ID товара. Каталог: `GET /v1/products` | | `productName` | string | | | Название товара | | `price` | double | | | Цена | | `quantity` | double | | | Количество | | `discount` | double | | | Сумма скидки | | `discountSum` | double | | | Устаревший псевдоним `discount` — принимается при записи, в товарных позициях не приходит | | `discountRate` | double | | | Величина скидки (%) | | `discountTypeId` | integer | | | Тип скидки | | `taxRate` | double | | | Налог (%) | | `taxIncluded` | char | | | Налог включён в цену (`Y`/`N`) | | `priceExclusive` | double | да | | Цена без налога со скидкой | | `priceNetto` | double | да | | Цена нетто | | `priceBrutto` | double | да | | Цена брутто | | `measureCode` | integer | | | Код единицы измерения | | `measureName` | string | да | | Единица измерения | | `customized` | char | да | | Изменён (`Y`/`N`) | | `sort` | integer | | | Сортировка | | `type` | integer | да | | Тип | | `storeId` | integer | да | | ID склада | | `ownerId` | integer | да | | ID владельца (сделки) | | `ownerType` | string | да | | Тип владельца | | `priceAccount` | double | да | | Цена в валюте отчёта | | `xmlId` | string | да | | Внешний код позиции | ## Пример ответа ```json { "success": true, "data": { "id": { "type": "integer", "isRequired": false, "isReadOnly": true, "title": "ID", "description": "Row identity. Read-only as an attribute; echo it back in PUT /products items to update a row in place instead of recreating it." }, "ownerId": { "type": "integer", "isRequired": false, "isReadOnly": true, "isImmutable": true, "title": "ID владельца" }, "ownerType": { "type": "string", "isRequired": false, "isReadOnly": true, "isImmutable": true, "title": "Тип владельца" }, "productId": { "type": "integer", "isRequired": true, "isReadOnly": false, "title": "Товар" }, "productName": { "type": "string", "isRequired": false, "isReadOnly": false, "title": "Название товара" }, "price": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Цена" }, "priceExclusive": { "type": "double", "isRequired": false, "isReadOnly": true, "title": "Цена без налога со скидкой" }, "priceNetto": { "type": "double", "isRequired": false, "isReadOnly": true, "title": "PRICE_NETTO" }, "priceBrutto": { "type": "double", "isRequired": false, "isReadOnly": true, "title": "PRICE_BRUTTO" }, "quantity": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Количество" }, "discountTypeId": { "type": "integer", "isRequired": false, "isReadOnly": false, "title": "Тип скидки" }, "discountRate": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Величина скидки" }, "discount": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Сумма скидки" }, "discountSum": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Сумма скидки", "description": "Deprecated alias of `discount`; kept so clients written against the previous field list keep working. Accepted on write, never present in row data — migrate to `discount`." }, "taxRate": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Налог" }, "taxIncluded": { "type": "char", "isRequired": false, "isReadOnly": false, "title": "Налог включен в цену" }, "customized": { "type": "char", "isRequired": false, "isReadOnly": true, "title": "Изменен" }, "measureCode": { "type": "integer", "isRequired": false, "isReadOnly": false, "title": "Код единицы измерения" }, "measureName": { "type": "string", "isRequired": false, "isReadOnly": true, "title": "Единица измерения" }, "sort": { "type": "integer", "isRequired": false, "isReadOnly": false, "title": "Сортировка" }, "type": { "type": "integer", "isRequired": false, "isReadOnly": true, "title": "TYPE" }, "storeId": { "type": "integer", "isRequired": false, "isReadOnly": true, "title": "STORE_ID" }, "priceAccount": { "type": "double", "isRequired": false, "isReadOnly": true }, "xmlId": { "type": "string", "isRequired": false, "isReadOnly": true } } } ``` ## Пример ответа при ошибке 404 — сделка не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Сделка не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Товарные позиции](/docs/entities/deals/products-get) - [Добавить товар](/docs/entities/deals/products-add) - [Установить товары](/docs/entities/deals/products-set) - [Поля сделки](/docs/entities/deals/fields) --- # Deals: Products Get ## Товарные позиции сделки `GET /v1/deals/:id/products` Возвращает список товарных позиций, привязанных к сделке. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID сделки | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/deals/741/products" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/deals/741/products" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/741/products', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Товаров:', data.length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/741/products', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив товарных позиций | | `data[].productId` | number | ID товара. Каталог: `GET /v1/products` | | `data[].productName` | string | Название товара | | `data[].price` | number | Цена за единицу | | `data[].quantity` | number | Количество | | `data[].discount` | number | Сумма скидки | | `data[].taxRate` | number/null | Ставка налога (%) | | `data[].taxIncluded` | boolean | Налог включён в цену | Показаны основные поля. Полный список (23 поля, включая priceAccount, measureCode и др.): [Поля товаров](/docs/entities/deals/products-fields). ## Пример ответа ```json { "success": true, "data": [ { "productId": 1, "productName": "Серверное оборудование", "price": 1000, "quantity": 2, "discount": 0, "taxRate": null, "taxIncluded": false } ] } ``` ## Пример ответа при ошибке 404 — сделка не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Сделка не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Установить товары](/docs/entities/deals/products-set) - [Получить сделку](/docs/entities/deals/get) - [Товары каталога](/docs/entities/products) - [Лимиты и оптимизация](/docs/optimization) --- # Deals: Products Get Single ## Получить товар из сделки `GET /v1/deals/:id/products/:rowId` Возвращает одну товарную позицию сделки по ID строки. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID сделки | | `rowId` (path) | number | да | ID товарной строки (из ответа add или list) | `rowId` — это ID товарной строки, а не `productId` из каталога товаров. ## Примеры ### curl — личный ключ ```bash curl -X GET "https://vibecode.bitrix24.tech/v1/deals/741/products/1471" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X GET "https://vibecode.bitrix24.tech/v1/deals/741/products/1471" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/741/products/1471', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Цена:', data.price) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/741/products/1471', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.id` | number | ID товарной строки | | `data.productId` | number | ID товара из каталога | | `data.productName` | string | Название товара | | `data.price` | number | Цена за единицу | | `data.quantity` | number | Количество | | `data.discount` | number | Сумма скидки | | `data.discountRate` | number | Процент скидки | | `data.discountTypeId` | number | Тип скидки (1 — сумма, 2 — процент) | | `data.taxRate` | number \| null | Ставка налога (%) | | `data.taxIncluded` | boolean | Налог включён в цену | | `data.priceExclusive` | number | Цена без скидки | | `data.priceNetto` | number | Цена нетто | | `data.priceBrutto` | number | Цена брутто | | `data.priceAccount` | number | Цена в валюте учёта | | `data.measureCode` | number | Код единицы измерения | | `data.measureName` | string | Название единицы измерения | | `data.sort` | number | Сортировка | | `data.ownerId` | number | ID сущности-владельца, которой принадлежит позиция | | `data.ownerType` | string | Код типа владельца (`D` у сделок, `T` у смарт-процессов) | | `data.storeId` | number \| null | ID склада; `null`, если складской учёт выключен | ## Пример ответа ```json { "success": true, "data": { "id": 1471, "productId": 1, "productName": "День добрый!", "price": 5000, "priceAccount": 5000, "priceExclusive": 5000, "priceNetto": 5000, "priceBrutto": 5000, "quantity": 3, "discountTypeId": 2, "discountRate": 0, "discount": 0, "taxRate": null, "taxIncluded": false, "customized": "Y", "measureCode": 796, "measureName": "шт", "sort": 0, "ownerId": 741, "ownerType": "D", "storeId": 3, "xmlId": "sale_basket_995", "type": 1 } } ``` ## Пример ответа при ошибке 404 — сделка или товарная строка не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Сделка или товарная строка не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Товарные позиции](/docs/entities/deals/products-get) - [Обновить товар](/docs/entities/deals/products-update) - [Добавить товар](/docs/entities/deals/products-add) - [Удалить товар](/docs/entities/deals/products-delete) - [Товары каталога](/docs/entities/products) --- # Deals: Products Set > Поле, которого нет среди записываемых, больше не отбрасывается молча — запрос отклоняется с `400 INVALID_PARAMS`, и в тексте ошибки перечислены записываемые имена. Поля только для чтения, которые приходят в ответах товарных позиций (`priceAccount`, `ownerId`, `storeId` и другие) по-прежнему принимаются и игнорируются, поэтому объект, прочитанный через GET, можно отправить обратно без чистки. > Сохраняйте `id` у элемента, чтобы обновить существующую строку на месте: без него строка будет создана заново с новым идентификатором. ## Установить товары сделки `PUT /v1/deals/:id/products` Устанавливает товарные позиции сделки. Полностью заменяет текущий список — передайте все нужные позиции. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `items` | array | да | Массив товарных позиций | | `items[].productId` | number | да | ID товара. Каталог: `GET /v1/products` | | `items[].price` | number | да | Цена за единицу | | `items[].quantity` | number | да | Количество | | `items[].discount` | number | нет | Сумма скидки | | `items[].taxRate` | number | нет | Ставка налога (%) | | `items[].taxIncluded` | boolean | нет | Налог включён в цену | ## Примеры ### curl — личный ключ ```bash curl -X PUT "https://vibecode.bitrix24.tech/v1/deals/741/products" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "items": [ { "productId": 1, "price": 25000, "quantity": 2 }, { "productId": 5, "price": 5000, "quantity": 1, "discount": 500 } ] }' ``` ### curl — OAuth-приложение ```bash curl -X PUT "https://vibecode.bitrix24.tech/v1/deals/741/products" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "items": [ { "productId": 1, "price": 25000, "quantity": 2 }, { "productId": 5, "price": 5000, "quantity": 1, "discount": 500 } ] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/741/products', { method: 'PUT', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ items: [ { productId: 1, price: 25000, quantity: 2 }, { productId: 5, price: 5000, quantity: 1, discount: 500 }, ], }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/741/products', { method: 'PUT', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ items: [ { productId: 1, price: 25000, quantity: 2 }, { productId: 5, price: 5000, quantity: 1, discount: 500 }, ], }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив установленных позиций с полями productId, productName, price, quantity, discount, taxRate, taxIncluded | Массив установленных позиций с полями `productId`, `productName`, `price`, `quantity`, `discount`, `taxRate`, `taxIncluded`. ## Пример ответа ```json { "success": true, "data": [ { "productId": 1, "productName": "Серверное оборудование", "price": 25000, "quantity": 2, "discount": 0, "taxRate": null, "taxIncluded": false }, { "productId": 5, "productName": "Установка и настройка", "price": 5000, "quantity": 1, "discount": 500, "taxRate": null, "taxIncluded": false } ] } ``` ## Пример ответа при ошибке 400 — неверный формат: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "items must be an array" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Тело содержит имя, которого нет среди записываемых полей — см. [Поля товаров](/docs/entities/deals/products-fields) | | 400 | `INVALID_PARAMS` | `items` не является массивом | | 404 | `ENTITY_NOT_FOUND` | Сделка не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Полная замена:** PUT заменяет весь список товаров. Чтобы добавить позицию — сначала получите текущие (`GET`), добавьте новую в массив, отправьте всё (`PUT`). ## Смотрите также - [Товарные позиции](/docs/entities/deals/products-get) - [Получить сделку](/docs/entities/deals/get) - [Товары каталога](/docs/entities/products) - [Лимиты и оптимизация](/docs/optimization) --- # Deals: Products Update > Поле, которого нет среди записываемых, больше не отбрасывается молча — запрос отклоняется с `400 INVALID_PARAMS`, и в тексте ошибки перечислены записываемые имена. Поля только для чтения, которые приходят в ответах товарных позиций (`priceAccount`, `ownerId`, `storeId` и другие) по-прежнему принимаются и игнорируются, поэтому объект, прочитанный через GET, можно отправить обратно без чистки. ## Обновить товар сделки `PATCH /v1/deals/:id/products/:rowId` Обновляет товарную позицию сделки. Передайте только изменяемые поля. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID сделки | | `rowId` (path) | number | да | ID товарной позиции (из ответа list или add, не productId из каталога) | ## Поля запроса (body) | Параметр | Тип | Описание | |----------|-----|---------| | `price` | number | Цена за единицу | | `quantity` | number | Количество | | `productId` | number | ID товара. Каталог: `GET /v1/products` | | `discount` | number | Сумма скидки | | `taxRate` | number | Ставка налога (%) | | `taxIncluded` | boolean | Налог включён в цену | | `sort` | number | Сортировка | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/deals/741/products/1471" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "price": 9999, "quantity": 10 }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/deals/741/products/1471" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "price": 9999, "quantity": 10 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/741/products/1471', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ price: 9999, quantity: 10 }), }) const { success, data } = await res.json() console.log('Обновлено:', data.price, 'x', data.quantity) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/741/products/1471', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ price: 9999, quantity: 10 }), }) const { success, data } = await res.json() ``` ## Поля ответа Обновлённый объект товарной позиции: `id`, `productId`, `productName`, `price`, `quantity`, `discount`, `taxRate`, `taxIncluded`. ## Пример ответа ```json { "success": true, "data": { "id": 1471, "productId": 1, "productName": "Серверное оборудование", "price": 9999, "quantity": 10, "discount": 0, "taxRate": null, "taxIncluded": false } } ``` ## Пример ответа при ошибке 404 — позиция не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Тело содержит имя, которого нет среди записываемых полей — см. [Поля товаров](/docs/entities/deals/products-fields) | | 404 | `ENTITY_NOT_FOUND` | Позиция не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить товар](/docs/entities/deals/products-get-single) - [Получить товары](/docs/entities/deals/products-get) - [Добавить товар](/docs/entities/deals/products-add) - [Лимиты и оптимизация](/docs/optimization) --- # Deals: Search ## Поиск сделок `POST /v1/deals/search` Поиск сделок с фильтрами и авто-пагинацией. Аналогичен `GET /v1/deals` с фильтрами, но через POST — удобнее для сложных запросов с большим количеством условий. ## Поля запроса (body) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям `GET /v1/deals/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[stageId]=NEW` | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки» | | `order` | object | — | Сортировка: `{ "createdAt": "desc" }` | | `select` | string[] | — | Выборка полей: `["id", "title", "amount"]` | | `autoWindow` | boolean | `true` | Разбивать выборку по недельным окнам при фильтре по диапазону дат шире 14 дней. `false` отключает разбиение | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/deals/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "stageId": "NEW" }, "limit": 10, "order": { "amount": "desc" } }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/deals/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "stageId": "NEW" }, "limit": 10, "order": { "amount": "desc" } }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { stageId: 'NEW' }, limit: 10, order: { amount: 'desc' }, }), }) const { success, data } = await res.json() console.log('Найдено:', data.length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { stageId: 'NEW' }, limit: 10, order: { amount: 'desc' }, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив сделок (все поля — см. [Поля](/docs/entities/deals/fields)) | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.nextAfterId` | string | Идентификатор последней отданной записи. Приходит при сортировке строго по `id` по возрастанию, пока `hasMore` равен `true`. Передайте его обратно в фильтр `>id` — это дешёвая замена растущему `offset` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временны́м окнам | | `meta.windowCount` | number | Число окон. Приходит при `autoWindowed: true` | | `meta.batchWaves` | number | Число волн параллельных запросов. Приходит при `autoWindowed: true` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. URL карточки любой сделки из массива `data` — её `id`: ``` https://.bitrix24.ru/crm/deal/details// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 3865, "title": "Шаблончик", "amount": 0, "currency": "RUB", "stageId": "NEW", "categoryId": 0, "assignedById": 29, "createdAt": "2021-01-13T13:52:44.000Z" } ], "meta": { "total": 1915, "hasMore": true, "durationMs": 690 } } ``` С фильтром по диапазону дат шире 14 дней в `meta` дополнительно приходят `autoWindowed`, `windowCount` и `batchWaves`: ```json { "success": true, "data": [ /* ... */ ], "meta": { "total": 618, "hasMore": true, "autoWindowed": true, "windowCount": 78, "batchWaves": 2, "durationMs": 2742 } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет в схеме сделки. Сообщение содержит список доступных полей | | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Разбиение по временны́м окнам.** Фильтр по диапазону дат шире 14 дней автоматически разбивается на недельные окна, которые выполняются параллельными волнами — так выборка обходит потолок в 5000 записей на один вызов. В `meta` тогда приходят `autoWindowed: true`, число окон `windowCount` и число волн `batchWaves`. Отключает разбиение параметр `autoWindow: false`. При активном разбиении `offset` больше нуля отклоняется с `UNSTABLE_OFFSET_PAGINATION`. **Отчёты по закрытым сделкам фильтруются по `closedAt`.** Дата закрытия сделки — поле `closedAt` (ISO 8601 с учётом часового пояса портала), заполняется при переходе сделки в финальную стадию. Имя поля именно `closedAt` — не `closedDate`. Для отчёта «выиграно/проиграно за период» отбирайте по диапазону `closedAt`: ```json { "filter": { "closedAt": { "$gte": "2026-01-01", "$lte": "2026-01-31T23:59:59" } } } ``` Чтобы разделить выигранные и проигранные, добавьте к фильтру стадию (`stageId`). Идентификаторы финальных стадий воронки — `GET /v1/statuses?filter[entityId]=DEAL_STAGE`. ## Смотрите также - [Список сделок](/docs/entities/deals/list) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Deals: Update ## Обновить сделку `PATCH /v1/deals/:id` Обновляет поля существующей сделки. Передайте только изменяемые поля. Полный список в [справочнике полей](/docs/entities/deals/fields), включая пользовательские (`ufCrm_*`). ## Часто обновляемые поля | Параметр | Тип | Описание | |----------|-----|---------| | `stageId` | string | Стадия воронки. Список: `GET /v1/statuses?filter[entityId]=DEAL_STAGE` | | `amount` | number | Сумма сделки | | `assignedById` | number | Ответственный. Список: `GET /v1/users` | | `title` | string | Название | | `closedAt` | datetime | Дата закрытия | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/deals/741" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "stageId": "WON", "amount": 75000 }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/deals/741" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "stageId": "WON", "amount": 75000 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/741', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ stageId: 'WON', amount: 75000, }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/deals/741', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ stageId: 'WON', amount: 75000, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | object | Обновлённый объект сделки со всеми полями — см. [Поля](/docs/entities/deals/fields) | Обновлённый объект сделки со всеми полями — см. [Поля сделки](/docs/entities/deals/fields). ## Пример ответа ```json { "success": true, "data": { "id": 741, "title": "Поставка оборудования", "amount": 75000, "currency": "RUB", "stageId": "WON", "categoryId": 0, "assignedById": 1, "updatedAt": "2026-04-14T09:15:00.000Z", "entityTypeId": 2 } } ``` ## Пример ответа при ошибке 404 — сделка не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Сделка не найдена | | 403 | `ACCESS_DENIED` | Нет доступа к сделке | | 400 | `INVALID_REQUEST` | Некорректные поля | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Работа с файлами в полях CRM](/docs/recipes/crm-files) - [Получить сделку](/docs/entities/deals/get) - [Поля сделки](/docs/entities/deals/fields) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Departments: Create ## Создать отдел `POST /v1/departments` Создаёт новый отдел в дереве организационной структуры портала. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `name` | string | да | Название отдела | | `parentId` | number | да | ID родительского отдела. Список родителей: [`GET /v1/departments`](./list.md). Для отдела верхнего уровня используйте `parentId: 1` | | `headId` | number | | ID руководителя отдела. Источник: [`GET /v1/users`](/docs/entities/users) | | `sort` | number | | Порядок отдела среди соседей (меньшее значение — выше в списке). По умолчанию `500` | Создать второй отдел верхнего уровня (без `parentId` или с `parentId: 0`) нельзя — портал поддерживает только один корневой отдел. > **`headId` не проверяется на существование.** Bitrix24 не валидирует пользователя в `headId`: несуществующий `userId` будет принят и сохранён как руководитель отдела (висячая ссылка), запрос вернёт `201`. Валидируется только `parentId` (несуществующий родитель → `422 BITRIX_ERROR`). Перед назначением убедитесь, что пользователь существует — [`GET /v1/users`](/docs/entities/users). ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/departments" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Коммерческий отдел", "parentId": 1, "headId": 99, "sort": 500 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/departments" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Коммерческий отдел", "parentId": 1, "headId": 99, "sort": 500 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/departments', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Коммерческий отдел', parentId: 1, headId: 99, sort: 500, }), }) const { success, data } = await res.json() console.log('Department ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/departments', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Коммерческий отдел', parentId: 1, headId: 99, sort: 500, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID созданного отдела | | `name` | string | Название | | `parentId` | number | ID родительского отдела | | `headId` | number | ID руководителя (если указан при создании) | | `sort` | number | Порядок сортировки | ## Пример ответа ```json { "success": true, "data": { "id": 189, "name": "Коммерческий отдел", "sort": 500, "parentId": 1, "headId": 99 } } ``` ## Пример ответа при ошибке 422 — не указано обязательное поле `name` (при корректном `parentId`): ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Не введено название раздела." } } ``` Порядок валидации: сначала проверяется корректность `parentId` (для пустого тела или отсутствующего `parentId` сработает ошибка единственного корневого отдела), и только затем — обязательность `name`. ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Не указан `name`, либо попытка создать второй корневой отдел, либо `parentId` ссылается на несуществующий отдел. `headId` НЕ проверяется (несуществующий пользователь принимается) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `department` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список отделов](/docs/entities/departments/list) - [Поля отдела](/docs/entities/departments/fields) - [Сотрудники](/docs/entities/users) - [Batch](/docs/batch) --- # Departments: Delete ## Удалить отдел `DELETE /v1/departments/:id` Удаляет отдел по ID. **Удаление не блокируется** наличием дочерних отделов или закреплённых сотрудников: Bitrix24 удаляет отдел и автоматически переподвешивает его прямые дочерние отделы на родителя удаляемого отдела, переназначая им `sort` (их собственные поддеревья перемещаются вверх вместе с ними). Чтобы контролировать итоговую структуру, перенесите дочерние отделы и сотрудников вручную **до** удаления. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID отдела | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/departments/189" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/departments/189" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/departments/189', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Отдел удалён') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/departments/189', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — отдел не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Department not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Отдел не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `department` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Удаление отдела с детьми не запрещено и молча перестраивает дерево.** При `DELETE` отдела, у которого есть дочерние отделы, Bitrix24 удаляет его (`204`) и переподвешивает прямые дочерние отделы на родителя удалённого отдела, переназначая им `sort`; их собственные поддеревья перемещаются вверх вместе с ними. Закреплённые сотрудники также не препятствуют удалению. Чтобы контролировать итоговую структуру, **до** удаления перенесите дочерние отделы через [`PATCH /v1/departments/:id`](./update.md) (новый `parentId`) и переназначьте сотрудников через [`PATCH /v1/users/:id`](/docs/entities/users) с новым `departmentId` (массив ID отделов). ## Смотрите также - [Список отделов](/docs/entities/departments/list) - [Обновить отдел](/docs/entities/departments/update) - [Сотрудники](/docs/entities/users) - [Batch](/docs/batch) --- # Departments: Fields ## Поля отдела `GET /v1/departments/fields` Возвращает справочник полей отдела с типами и признаком «только для чтения», а также список операций, доступных в [`POST /v1/batch`](/docs/batch). ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/departments/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/departments/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/departments/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data.fields).length) console.log('Доступные batch-операции:', data.batch) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/departments/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | RO | Описание | |------|-----|:--:|---------| | `id` | number | да | Идентификатор отдела | | `name` | string | | Название отдела | | `parentId` | number | | ID родительского отдела. Для отдела верхнего уровня указывается `1` (виртуальный корень дерева). Источник: [`GET /v1/departments`](./list.md) | | `headId` | number | | ID руководителя отдела. Источник: [`GET /v1/users`](/docs/entities/users) | | `sort` | number | | Порядок отдела среди соседей (целое число, по возрастанию) | ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "ID", "description": "Уникальный идентификатор отдела." }, "name": { "type": "string", "readonly": false, "label": "Название", "description": "Название отдела, отображаемое в структуре компании." }, "parentId": { "type": "number", "readonly": false, "label": "Родительский отдел", "description": "ID родительского отдела в иерархии; для отдела верхнего уровня указывается 1 — виртуальный корень дерева." }, "headId": { "type": "number", "readonly": false, "label": "Руководитель", "description": "ID пользователя, назначенного руководителем отдела." }, "sort": { "type": "number", "readonly": false, "label": "Сортировка", "description": "Порядок отдела среди соседних по уровню; по умолчанию 500." } }, "batch": ["create", "update", "delete"] } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'department' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `department` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать отдел](/docs/entities/departments/create) - [Обновить отдел](/docs/entities/departments/update) - [Список отделов](/docs/entities/departments/list) - [Batch](/docs/batch) - [Entity API](/docs/entity-api) --- # Departments: Get ## Получить отдел `GET /v1/departments/:id` Возвращает один отдел по идентификатору со всеми полями. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID отдела | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/departments/47" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/departments/47" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/departments/47', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Отдел:', data.name, '— руководитель ID', data.headId) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/departments/47', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа Объект отдела со всеми полями — см. [Поля отдела](/docs/entities/departments/fields). ## Пример ответа ```json { "success": true, "data": { "id": 47, "name": "Коммерческий отдел", "sort": 500, "parentId": 1, "headId": 99 } } ``` ## Пример ответа при ошибке 404 — отдел не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "department 9999 not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Отдел с таким ID не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `department` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Поля отдела](/docs/entities/departments/fields) - [Обновить отдел](/docs/entities/departments/update) - [Список отделов](/docs/entities/departments/list) - [Сотрудники](/docs/entities/users) --- # Departments: List ## Список отделов `GET /v1/departments` Возвращает список отделов портала с поддержкой фильтрации и выборки полей. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` запрос автоматически собирается из нескольких страниц на стороне сервера | | `select` | string | — | Выборка полей: `?select=id,name`. Возвращаются только перечисленные поля | | `filter` | object | — | Только точное равенство и `$in` (IN-множество) по полям `id`, `name`, `parentId`, `headId`. Операторы (`>`, `>=`, `<`, `<=`, `!`, `%`, `$ne`, `$contains`, `$nin`) и другие поля не поддерживаются — вернётся `400 UNSUPPORTED_FILTER`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[parentId]=1` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/departments?filter[parentId]=1" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/departments?filter[parentId]=1" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/departments?filter[parentId]=1', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} отделов`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/departments?filter[parentId]=1', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив отделов (см. [Поля отдела](/docs/entities/departments/fields)) | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | ## Пример ответа ```json { "success": true, "data": [ { "id": 47, "name": "Коммерческий отдел", "sort": 500, "parentId": 1, "headId": 99 }, { "id": 107, "name": "Отдел разработки", "sort": 600, "parentId": 1, "headId": 1 } ], "meta": { "total": 2, "hasMore": false } } ``` ## Пример ответа при ошибке 400 — оператор или неподдерживаемое поле в фильтре: ```json { "success": false, "error": { "code": "UNSUPPORTED_FILTER", "message": "UNSUPPORTED_FILTER: 'sort' is not filterable on 'departments'. Its Bitrix24 method (department.get) filters by exact match only. Filterable: id, name, parentId, headId." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSUPPORTED_FILTER` | Оператор или неподдерживаемое поле в фильтре. Фильтруйте точным равенством или `$in` по `id`, `name`, `parentId`, `headId` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `department` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Сортировка не поддерживается; `offset` работает построчно.** Параметр `order` / `sort` отклоняется с ошибкой `400 INVALID_SORT_FIELD` — метод Битрикс24 `department.get` не принимает порядок сортировки; для упорядочивания отсортируйте выборку на стороне клиента. Параметр `offset` считается по записям: `offset=7` начинает выборку с 8-го департамента. Битрикс24 отдаёт результат страницами по 50, поэтому Vibe запрашивает страницу, покрывающую нужную позицию, и отбрасывает лишнее начало. При `limit > 50` Vibe сам собирает нужные страницы (см. параметр `limit` выше), поэтому весь список департаментов загружается одним запросом без ручной постраничной навигации. **Когда использовать search вместо list:** для составных условий по нескольким полям удобнее [`POST /v1/departments/search`](./search.md) — параметры передаются в теле запроса. ## Смотрите также - [Поиск отделов](/docs/entities/departments/search) - [Получить отдел](/docs/entities/departments/get) - [Создать отдел](/docs/entities/departments/create) - [Синтаксис фильтрации](/docs/filtering) - [Entity API](/docs/entity-api) - [Batch](/docs/batch) --- # Departments: Search ## Поиск отделов `POST /v1/departments/search` Поиск отделов с фильтрами. Аналог `GET /v1/departments` с фильтрами, но через POST — удобнее для составных запросов из нескольких условий. ## Поля запроса (body) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Только точное равенство и `$in` (IN-множество) по полям `id`, `name`, `parentId`, `headId`. Операторы (`>`, `>=`, `<`, `<=`, `!`, `%`, `$ne`, `$contains`, `$nin`) и другие поля не поддерживаются — вернётся `400 UNSUPPORTED_FILTER`.
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "parentId": 1 }` | | `limit` | number | `50` | Количество записей (до 5000) | | `select` | string[] | — | Выборка полей: `["id", "name"]` | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/departments/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "parentId": 1 }, "limit": 10 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/departments/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "parentId": 1 }, "limit": 10 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/departments/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { parentId: 1 }, limit: 10, }), }) const { success, data, meta } = await res.json() console.log('Найдено:', meta.total) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/departments/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { parentId: 1 }, limit: 10, }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив отделов (см. [Поля отдела](/docs/entities/departments/fields)) | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа ```json { "success": true, "data": [ { "id": 47, "name": "Коммерческий отдел", "sort": 500, "parentId": 1, "headId": 99 }, { "id": 107, "name": "Отдел разработки", "sort": 600, "parentId": 1, "headId": 1 } ], "meta": { "total": 2, "hasMore": false, "durationMs": 252 } } ``` ## Пример ответа при ошибке 400 — оператор или неподдерживаемое поле в фильтре: ```json { "success": false, "error": { "code": "UNSUPPORTED_FILTER", "message": "UNSUPPORTED_FILTER: operators are not supported on 'departments' (near 'id'). Its Bitrix24 method (department.get) filters by exact match only — operators are silently ignored by Bitrix24. Use exact match (field: value) or $in (field: {$in: [...]}) on: id, name, parentId, headId." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSUPPORTED_FILTER` | Оператор или неподдерживаемое поле в фильтре. Фильтруйте точным равенством или `$in` по `id`, `name`, `parentId`, `headId` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `department` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Параметр `order` не применяется; `offset` применяется построчно.** Поле `order` в теле запроса принимается без ошибки, но порядок результата не меняется — метод Битрикс24 `department.get` не принимает сортировку. Поле `offset` считается по записям: `offset=7` вернёт выборку начиная с 8-го департамента. Порядок при этом задаёт Битрикс24, поэтому для устойчивой постраничной обработки запрашивайте всю выборку фильтра и сортируйте на стороне клиента. ## Смотрите также - [Список отделов](/docs/entities/departments/list) - [Поля отдела](/docs/entities/departments/fields) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) --- # Departments: Update ## Обновить отдел `PATCH /v1/departments/:id` Обновляет поля существующего отдела. Передайте только изменяемые поля. ## Поля запроса (body) | Параметр | Тип | Описание | |----------|-----|---------| | `name` | string | Название отдела | | `parentId` | number | ID нового родительского отдела — для перемещения отдела в дереве. Должен ссылаться на существующий отдел. Список: [`GET /v1/departments`](./list.md) | | `headId` | number | Новый руководитель. Источник: [`GET /v1/users`](/docs/entities/users) | | `sort` | number | Порядок среди отделов того же уровня | Полный список полей — [Поля отдела](/docs/entities/departments/fields). > **`headId` не проверяется на существование.** Bitrix24 не валидирует пользователя в `headId`: несуществующий `userId` будет принят и сохранён (висячая ссылка), запрос вернёт `200`. Валидируется только `parentId` (несуществующий родитель → `422 BITRIX_ERROR`). Перед назначением убедитесь, что пользователь существует — [`GET /v1/users`](/docs/entities/users). ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/departments/47" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Коммерческий отдел Запад", "headId": 101 }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/departments/47" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Коммерческий отдел Запад", "headId": 101 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/departments/47', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Коммерческий отдел Запад', headId: 101, }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/departments/47', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Коммерческий отдел Запад', headId: 101, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | object | Обновлённый объект отдела со всеми полями — см. [Поля](/docs/entities/departments/fields) | ## Пример ответа ```json { "success": true, "data": { "id": 47, "name": "Коммерческий отдел Запад", "sort": 500, "parentId": 1, "headId": 101 } } ``` ## Пример ответа при ошибке 404 — отдел не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "department 9999 not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Отдел не найден | | 422 | `BITRIX_ERROR` | `parentId` ссылается на несуществующий отдел. `headId` НЕ проверяется (несуществующий пользователь принимается) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `department` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить отдел](/docs/entities/departments/get) - [Поля отдела](/docs/entities/departments/fields) - [Batch](/docs/batch) --- # Doc Templates: Aggregate ## Агрегация шаблонов документов `POST /v1/doc-templates/aggregate` Подсчёт количества и числовые агрегации (сумма, среднее, минимум, максимум) по шаблонам документов с фильтрацией и группировкой. **Стандартные поля:** - `sort` — индекс сортировки, единственное числовое поле, для которого `sum`/`avg`/`min`/`max` имеют смысл - `numeratorId` — нумератор, число, работает в числовых функциях и в `groupBy` - `fileId` — файл шаблона на Диске, число, работает в числовых функциях и в `groupBy` - `region` — регион шаблона, строка, только для `groupBy` - `moduleId` — модуль-владелец, строка, только для `groupBy` - `active` — активность, строка, только для `groupBy` Функции `sum`/`avg`/`min`/`max` принимают только числовые поля — `sort`, `numeratorId`, `fileId`. Для строкового поля в числовой функции возвращается `400 INVALID_PARAMS`. Группировать `groupBy` можно по любому полю из списка выше. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций. Каждый элемент: `{ "field": "sort", "function": "sum" }`. Функции: `count`, `sum`, `avg`, `min`, `max`. Для `count` поле — `"*"`. Без массива — только `count` | | `filter` | object | нет | Фильтрация по полям `GET /v1/doc-templates/fields`. [Синтаксис фильтрации](/docs/filtering) | | `groupBy` | string \| string[] | нет | Поле или массив полей для группировки (максимум 5). Допустимые значения — из списка выше | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/doc-templates/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "sort", "function": "sum" }, { "field": "sort", "function": "avg" } ], "groupBy": "region" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/doc-templates/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "sort", "function": "sum" }, { "field": "sort", "function": "avg" } ], "groupBy": "region" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/doc-templates/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [ { field: 'sort', function: 'sum' }, { field: 'sort', function: 'avg' }, ], groupBy: 'region', }), }) const { success, data } = await res.json() console.log('Всего шаблонов:', data.count) console.log('По регионам:', data.groups) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/doc-templates/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [ { field: 'sort', function: 'sum' }, { field: 'sort', function: 'avg' }, ], groupBy: 'region', }), }) const { success, data } = await res.json() ``` > Для группировки по нескольким полям передайте массив: `"groupBy": ["region", "active"]` (максимум 5). ## Другие сценарии Подсчёт записей — `count` с полем `"*"`, самый быстрый запрос без выгрузки шаблонов. Без массива `aggregate` результат тот же: ```json { "aggregate": [{ "field": "*", "function": "count" }] } ``` Разбивка по двум полям сразу — сколько шаблонов в каждом сочетании региона и активности: ```json { "groupBy": ["region", "active"] } ``` Количество шаблонов одного региона — `count` с фильтром, записи не выгружаются: ```json { "filter": { "region": "ru" } } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Общее количество шаблонов под фильтр | | `data.aggregates` | object | Результаты числовых агрегаций: `{ "sort": { "sum": 1650, "avg": 275 } }`. Пустой объект, если массив `aggregate` не передан | | `data.groups` | array | Группы, только при `groupBy`. Каждый элемент: поля группировки + `count` + `aggregates` | | `data.meta.totalRecords` | number | Общее количество записей под фильтр | | `data.meta.recordsProcessed` | number | Сколько записей обработано для числовых агрегаций. При запросе без числовых функций равно `0` — записи не выгружаются | | `data.meta.truncated` | boolean | `true`, если под фильтр попало больше 5000 записей | | `data.meta.groupTotal` | number | Количество групп, только при `groupBy` | | `data.meta.groupsTruncated` | boolean | `true`, если групп оказалось больше предела выдачи. Только при `groupBy` | ## Пример ответа Ответ на основной запрос (`sum` и `avg` по `sort` с `groupBy: "region"`): ```json { "success": true, "data": { "count": 6, "aggregates": { "sort": { "sum": 1650, "avg": 275 } }, "groups": [ { "region": "ru", "count": 3, "aggregates": { "sort": { "sum": 600, "avg": 200 } } }, { "region": "by", "count": 2, "aggregates": { "sort": { "sum": 900, "avg": 450 } } }, { "region": "kz", "count": 1, "aggregates": { "sort": { "sum": 150, "avg": 150 } } } ], "meta": { "totalRecords": 6, "recordsProcessed": 6, "truncated": false, "groupTotal": 3, "groupsTruncated": false } } } ``` Без `groupBy` поля `data.groups`, `data.meta.groupTotal` и `data.meta.groupsTruncated` в ответе отсутствуют. ## Пример ответа при ошибке 400 — несуществующее поле. Сообщение перечисляет доступные поля: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "Field 'bogus' not found. Available numeric fields: sort, numeratorId, fileId, region, moduleId, active." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Некорректное имя функции или несуществующее поле — сообщение перечисляет доступные поля | | 400 | `INVALID_PARAMS` | Строковое поле (`region`, `moduleId`, `active`) в `sum`/`avg`/`min`/`max` — сообщение называет тип поля | | 400 | `INVALID_PARAMS` | `groupBy` по полю вне списка, зарезервированное слово (`count`, `aggregates`, `meta`, `groups`) или больше 5 полей в `groupBy` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `documentgenerator` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`count` vs числовые функции.** `count` считается одним вызовом в Битрикс24 на любом объёме данных, записи при этом не выгружаются и `meta.recordsProcessed` равно `0`. Функции `sum`/`avg`/`min`/`max` подгружают записи постранично (максимум 5000) и считают на стороне Вайбкод — если под фильтр попадает больше 5000 записей, `meta.truncated` будет `true`, агрегация выполнится по первым 5000. Для точных счётчиков на больших выборках используйте `count` или сужайте фильтр. **Числовое агрегирование — по одному полю.** Осмысленную сумму или среднее даёт только `sort`. Поля `numeratorId` и `fileId` тоже числовые и принимаются в `sum`/`avg`/`min`/`max`, но это идентификаторы — их агрегируют для группировки, а не для подсчёта суммы. Остальные поля строковые и работают только в `groupBy`. ## Смотрите также - [Список шаблонов](/docs/entities/doc-templates/list) - [Поиск шаблонов](/docs/entities/doc-templates/search) - [Поля шаблона](/docs/entities/doc-templates/fields) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Doc Templates: Create ## Создать шаблон `POST /v1/doc-templates` Создаёт шаблон документа из файла `.docx`. Файл передаётся одним из двух способов: - `file` — содержимое `.docx` в виде строки base64. - `fileId` — идентификатор файла, заранее загруженного на Диск. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `name` | string | да | Название шаблона | | `numeratorId` | number | да | Идентификатор нумератора | | `region` | string | да | Регион, например `ru` | | `file` | string | * | Содержимое файла `.docx` в виде строки base64. Альтернатива полю `fileId` | | `fileId` | number | * | Идентификатор файла на Диске. Источник: загрузка через `POST /v1/files/upload`. Альтернатива полю `file` | | `code` | string | нет | Символьный код шаблона | | `active` | string | нет | Активность шаблона: `"Y"` или `"N"` | | `withStamps` | string | нет | Использовать печати и подписи: `"Y"` или `"N"` | | `sort` | number | нет | Индекс сортировки | | `users` | array | нет | Идентификаторы сотрудников, которым доступен шаблон | \* Поля `file` и `fileId` взаимоисключающие: передаётся одно из двух. Чтобы получить `fileId`, загрузите файл `.docx` через `POST /v1/files/upload` — значение `id` из ответа используйте как `fileId`. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/doc-templates" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Шаблон договора", "numeratorId": 1, "region": "ru", "fileId": 9175 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/doc-templates" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Шаблон договора", "numeratorId": 1, "region": "ru", "fileId": 9175 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/doc-templates', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Шаблон договора', numeratorId: 1, region: 'ru', fileId: 9175, }), }) const { success, data } = await res.json() console.log('ID шаблона:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/doc-templates', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Шаблон договора', numeratorId: 1, region: 'ru', fileId: 9175, }), }) const { success, data } = await res.json() ``` Альтернатива — передать содержимое файла `.docx` напрямую в поле `file` (base64): ```json { "name": "Шаблон договора", "numeratorId": 1, "region": "ru", "file": "" } ``` ## Поля ответа Возвращается полный объект созданного шаблона. Статус ответа — `201`. | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор созданного шаблона | | `name` | string | Название шаблона | | `region` | string | Регион | | `code` | string | Символьный код шаблона | | `active` | string | Активность: `"Y"` или `"N"` | | `moduleId` | string | Идентификатор модуля-источника шаблона | | `numeratorId` | number | Идентификатор нумератора | | `withStamps` | string | Использование печатей и подписей: `"Y"` или `"N"` | | `providers` | object | Сопоставление поставщиков данных шаблона | | `users` | object | Сопоставление идентификаторов пользователей, которым доступен шаблон | | `isDeleted` | boolean | Помечен ли шаблон удалённым | | `sort` | number | Индекс сортировки | | `createTime` | string | Дата создания (ISO 8601) | | `updateTime` | string | Дата последнего изменения (ISO 8601) | | `download` | string | Адрес скачивания собранного документа из шаблона | | `downloadMachine` | string | Адрес скачивания с токеном для программного доступа | ## Пример ответа ```json { "success": true, "data": { "id": 209, "name": "Шаблон договора", "region": "ru", "code": null, "download": "/bitrix/services/main/ajax.php?action=documentgenerator.api.template.download&SITE_ID=s1&id=209", "active": "Y", "moduleId": "rest", "numeratorId": 1, "withStamps": "N", "providers": { "bitrix\\documentgenerator\\dataprovider\\rest": "bitrix\\documentgenerator\\dataprovider\\rest" }, "users": { "U1": "U1" }, "isDeleted": false, "sort": 500, "createTime": "2026-05-12T09:03:38.000Z", "updateTime": "2026-05-12T09:03:38.000Z", "downloadMachine": "https:///rest/1//documentgenerator.api.template.download/?token=" } } ``` ## Пример ответа при ошибке 400 — не передан файл: ```json { "success": false, "error": { "code": "MISSING_FILE_OR_FILE_ID", "message": "POST /v1/doc-templates requires either \"file\" (base64-encoded .docx content) or \"fileId\" (Disk file ID). Neither was provided." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_FILE_OR_FILE_ID` | Не передан ни `file`, ни `fileId` | | 400 | `CONFLICTING_FILE_FIELDS` | Переданы и `file`, и `fileId` | | 400 | `MISSING_REQUIRED_FIELD` | Отсутствует `name`, `numeratorId` или `region` | | 400 | `INVALID_PARAMS` | `name`/`region` не строка либо `numeratorId` не положительное целое | | 415 | `UNSUPPORTED_MEDIA_TYPE` | Запрос отправлен с `multipart/form-data` | | 413 | `PAYLOAD_TOO_LARGE` | Тело запроса в формате `multipart/form-data` содержит данные | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `documentgenerator` | | 401 | `TOKEN_MISSING` | У ключа нет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить шаблон](/docs/entities/doc-templates/get) - [Обновить шаблон](/docs/entities/doc-templates/update) - [Список шаблонов](/docs/entities/doc-templates/list) --- # Doc Templates: Delete ## Удалить шаблон `DELETE /v1/doc-templates/:id` Удаляет шаблон документа по идентификатору. Восстановить удалённый шаблон через API нельзя — при необходимости создайте новый. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор шаблона | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/doc-templates/209" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/doc-templates/209" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/doc-templates/209', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Шаблон удалён') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/doc-templates/209', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Шаблон удалён') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом. Признак успеха — код ответа, не содержимое. ## Пример ответа ```http HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — шаблон не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Шаблон не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Шаблона с указанным `id` нет (в том числе повторное удаление) | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `documentgenerator` | | 401 | `TOKEN_MISSING` | У ключа нет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить шаблон](/docs/entities/doc-templates/get) - [Список шаблонов](/docs/entities/doc-templates/list) - [Создать шаблон](/docs/entities/doc-templates/create) --- # Doc Templates: Fields ## Поля шаблона `GET /v1/doc-templates/fields` Возвращает полную схему полей шаблона документа: имя поля, тип, признак «только для чтения» и обязательность при создании. Поля помечены ★ — обязательны в теле запроса при создании шаблона. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/doc-templates/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/doc-templates/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/doc-templates/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Всего полей:', Object.keys(data.fields).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/doc-templates/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Битрикс24 | Тип | RO | Описание | |------|----------|-----|:--:|---------| | `id` | `id` | number | да | ID шаблона | | `name` | `name` | string | | ★ Название шаблона | | `numeratorId` | `numeratorId` | number | | ★ ID нумератора, который присваивает документам порядковые номера | | `region` | `region` | string | | ★ Код региона шаблона, например `ru` или `by` | | `code` | `code` | string \| null | | Системный код шаблона для привязки в коде приложения. `null`, если код не задан | | `moduleId` | `moduleId` | string | | Идентификатор модуля-владельца шаблона | | `active` | `active` | string | | Доступность шаблона: `Y` — включён, `N` — выключен | | `bodyType` | `bodyType` | string | | Формат тела документа, например `DOCX` | | `withStamps` | `withStamps` | string | | Печать факсимиле и штампов: `Y` — добавляются, `N` — нет | | `sort` | `sort` | number | | Порядок шаблона в списке: чем меньше значение, тем выше | | `users` | `users` | array | | Идентификаторы сотрудников, которым доступен шаблон. Список: `GET /v1/users` | | `fileId` | `fileId` | number | | ID файла на Диске. Загрузка через `POST /v1/files/upload` | | `file` | `file` | string | | Содержимое .docx в base64, принимается при создании | | `createdBy` | `createdBy` | number | да | Идентификатор создавшего сотрудника | | `updatedBy` | `updatedBy` | number \| null | да | Идентификатор изменившего сотрудника. `null`, если шаблон не изменялся | | `isDeleted` | `isDeleted` | boolean | да | Шаблон помечен как удалённый | | `createTime` | `createTime` | datetime | да | Дата создания | | `updateTime` | `updateTime` | datetime | да | Дата изменения | | `download` | `download` | string | да | Ссылка для скачивания исходного файла шаблона | | `downloadMachine` | `downloadMachine` | string | да | Ссылка для скачивания файла по машинному доступу без авторизации в браузере | | `providers` | `providers` | object | да | Перечень доступных поставщиков хранилищ с их настройками | | `isDefault` | `isDefault` | string | да | Признак того, что шаблон используется по умолчанию | | `productsTableVariant` | `productsTableVariant` | string | да | Вариант оформления таблицы товаров в генерируемом документе | ★ — поля `name`, `numeratorId`, `region` обязательны в теле запроса при создании шаблона. ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "ID шаблона", "description": "Уникальный идентификатор шаблона документа." }, "name": { "type": "string", "readonly": false, "required": true, "label": "Название шаблона", "description": "Название шаблона документа, отображаемое пользователю." }, "numeratorId": { "type": "number", "readonly": false, "required": true, "label": "ID нумератора", "description": "Идентификатор нумератора, присваивающего документам порядковые номера." }, "region": { "type": "string", "readonly": false, "required": true, "label": "Регион шаблона", "description": "Код региона шаблона, например ru или by." }, "code": { "type": "string", "readonly": false, "label": "Системный код", "description": "Системный код шаблона для привязки к нему в коде приложения." }, "moduleId": { "type": "string", "readonly": false, "label": "ID модуля-владельца", "description": "Идентификатор модуля Битрикс24, которому принадлежит шаблон." }, "active": { "type": "string", "readonly": false, "label": "Активность", "description": "Признак доступности шаблона: включён или выключен." }, "bodyType": { "type": "string", "readonly": false, "label": "Формат тела", "description": "Формат содержимого генерируемого документа, например DOCX." }, "withStamps": { "type": "string", "readonly": false, "label": "Печать штампов", "description": "Признак добавления факсимиле и штампов при генерации документа." }, "sort": { "type": "number", "readonly": false, "label": "Сортировка", "description": "Значение для сортировки шаблона в списке: чем меньше, тем выше." }, "users": { "type": "array", "readonly": false, "label": "Доступные сотрудники", "description": "Список идентификаторов сотрудников, которым доступен шаблон." }, "fileId": { "type": "number", "readonly": false, "label": "ID файла на Диске", "description": "Идентификатор файла шаблона, загруженного на Диск." }, "file": { "type": "string", "readonly": false, "label": "Содержимое файла", "description": "Содержимое файла шаблона в формате .docx, закодированное в base64." }, "createdBy": { "type": "number", "readonly": true, "label": "Создал сотрудник", "description": "Идентификатор сотрудника, создавшего шаблон." }, "updatedBy": { "type": "number", "readonly": true, "label": "Изменил сотрудник", "description": "Идентификатор сотрудника, последним изменившего шаблон." }, "isDeleted": { "type": "boolean", "readonly": true, "label": "Удалён", "description": "Признак того, что шаблон помечен как удалённый." }, "createTime": { "type": "datetime", "readonly": true, "label": "Дата создания", "description": "Дата и время создания шаблона." }, "updateTime": { "type": "datetime", "readonly": true, "label": "Дата изменения", "description": "Дата и время последнего изменения шаблона." }, "download": { "type": "string", "readonly": true, "label": "Ссылка на скачивание", "description": "Ссылка для скачивания исходного файла шаблона." }, "downloadMachine": { "type": "string", "readonly": true, "label": "Машинная ссылка", "description": "Ссылка для скачивания файла без авторизации в браузере, для программного доступа." }, "providers": { "type": "object", "readonly": true, "label": "Список поставщиков", "description": "Перечень доступных поставщиков хранилищ файла шаблона с их настройками." }, "isDefault": { "type": "string", "readonly": true, "label": "Шаблон по умолчанию", "description": "Признак того, что шаблон используется по умолчанию." }, "productsTableVariant": { "type": "string", "readonly": true, "label": "Вариант таблицы товаров", "description": "Вариант оформления таблицы товаров в генерируемом документе." } } } } ``` ## Пример ответа при ошибке 403 — у ключа нет нужного скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'documentgenerator' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключу не хватает скоупа `documentgenerator` | | 401 | `TOKEN_MISSING` | у ключа нет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать шаблон](/docs/entities/doc-templates/create) - [Список шаблонов](/docs/entities/doc-templates/list) --- # Doc Templates: Get ## Получить шаблон `GET /v1/doc-templates/:id` Возвращает один шаблон документа по идентификатору. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор шаблона | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/doc-templates/209" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/doc-templates/209" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/doc-templates/209', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Шаблон:', data.name) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/doc-templates/209', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект шаблона | | `data.id` | number | Идентификатор шаблона | | `data.name` | string | Название | | `data.region` | string | Регион | | `data.code` | string \| null | Системный код шаблона | | `data.active` | string | Доступность: `Y` / `N` | | `data.moduleId` | string | Модуль-источник шаблона | | `data.numeratorId` | number | Идентификатор нумератора | | `data.withStamps` | string | Печати и подписи: `Y` / `N` | | `data.sort` | number | Порядок в списке | | `data.users` | object | Сопоставление идентификаторов сотрудников, которым доступен шаблон | | `data.providers` | object | Поставщики данных шаблона | | `data.isDeleted` | boolean | Помечен ли шаблон удалённым | | `data.createTime` | string | Дата создания (ISO 8601) | | `data.updateTime` | string | Дата изменения (ISO 8601) | | `data.download` | string | Адрес скачивания документа | | `data.downloadMachine` | string | Адрес скачивания для программного доступа | Полная схема полей шаблона — [Поля шаблона](./fields.md). ## Пример ответа ```json { "success": true, "data": { "id": 209, "name": "Шаблон договора", "region": "ru", "code": null, "download": "/bitrix/services/main/ajax.php?action=documentgenerator.api.template.download&SITE_ID=s1&id=209", "active": "Y", "moduleId": "rest", "numeratorId": 1, "withStamps": "N", "providers": { "bitrix\\documentgenerator\\dataprovider\\rest": "bitrix\\documentgenerator\\dataprovider\\rest" }, "users": { "U1": "U1" }, "isDeleted": false, "sort": 500, "createTime": "2026-05-12T09:03:38.000Z", "updateTime": "2026-05-12T09:03:38.000Z", "downloadMachine": "https:///rest/1//documentgenerator.api.template.download/?token=" } } ``` ## Пример ответа при ошибке 404 — шаблон не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Шаблон не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Шаблона с указанным `id` нет (сообщение «Шаблон не найден») | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `documentgenerator` | | 401 | `TOKEN_MISSING` | У ключа нет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список шаблонов](/docs/entities/doc-templates/list) - [Обновить шаблон](/docs/entities/doc-templates/update) - [Поля шаблона](/docs/entities/doc-templates/fields) --- # Doc Templates: List ## Список шаблонов `GET /v1/doc-templates` Возвращает список шаблонов документов портала с поддержкой фильтрации, выборки полей, сортировки и пагинации. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям шаблона. Список полей — `GET /v1/doc-templates/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[active]=Y` | | `select` | string | — | Выборка полей: `?select=id,name,region` | | `order` | object | — | Сортировка по полю: `?order[sort]=asc` | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Смещение для пагинации | Для `limit > 50` Вайбкод автоматически запрашивает несколько страниц у Битрикс24 на стороне сервера. Максимум — 5000 записей за вызов. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/doc-templates?limit=10&filter[active]=Y" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/doc-templates?limit=10&filter[active]=Y" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/doc-templates?limit=10&filter[active]=Y', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} шаблонов`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/doc-templates?limit=10&filter[active]=Y', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив шаблонов | | `data[].id` | number | Идентификатор шаблона | | `data[].name` | string | Название | | `data[].active` | string | Доступность: `Y` / `N` | | `data[].code` | string \| null | Системный код шаблона | | `data[].region` | string | Регион | | `data[].sort` | number | Порядок в списке | | `data[].createTime` | string | Дата создания (ISO 8601) | | `data[].updateTime` | string | Дата изменения (ISO 8601) | | `data[].createdBy` | number | Идентификатор создавшего сотрудника | | `data[].updatedBy` | number \| null | Идентификатор изменившего сотрудника | | `data[].moduleId` | string | Модуль-источник шаблона | | `data[].fileId` | number | Идентификатор файла на Диске | | `data[].bodyType` | string | Формат тела документа | | `data[].numeratorId` | number | Идентификатор нумератора | | `data[].withStamps` | string | Печати и подписи: `Y` / `N` | | `data[].productsTableVariant` | string | Вариант таблицы товаров в документе | | `data[].isDeleted` | boolean | Помечен ли шаблон удалённым | | `data[].isDefault` | string | Шаблон по умолчанию: `Y` / `N` | | `data[].users` | array | Идентификаторы сотрудников, которым доступен шаблон | | `data[].download` | string | Адрес скачивания документа | | `data[].downloadMachine` | string | Адрес скачивания для программного доступа | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | Полная схема полей шаблона — [Поля шаблона](./fields.md). ## Пример ответа ```json { "success": true, "data": [ { "id": 209, "active": "Y", "name": "Шаблон договора", "code": null, "region": "ru", "sort": 500, "createTime": "2026-05-12T09:03:38.000Z", "updateTime": "2026-05-12T09:03:38.000Z", "createdBy": 1, "updatedBy": null, "moduleId": "rest", "fileId": 9175, "bodyType": "Bitrix\\DocumentGenerator\\Body\\Docx", "numeratorId": 1, "withStamps": "N", "productsTableVariant": "", "isDeleted": false, "isDefault": "N", "users": ["U1"], "download": "/bitrix/services/main/ajax.php?action=documentgenerator.api.template.download&SITE_ID=s1&id=209", "downloadMachine": "https:///rest/1//documentgenerator.api.template.download/?token=" }, { "id": 211, "active": "Y", "name": "Шаблон счёта", "code": null, "region": "ru", "sort": 500, "createTime": "2026-05-12T09:04:38.000Z", "updateTime": "2026-05-12T09:04:38.000Z", "createdBy": 1, "updatedBy": null, "moduleId": "rest", "fileId": 5901, "bodyType": "Bitrix\\DocumentGenerator\\Body\\Docx", "numeratorId": 1, "withStamps": "N", "productsTableVariant": "", "isDeleted": false, "isDefault": "N", "users": ["U1"], "download": "/bitrix/services/main/ajax.php?action=documentgenerator.api.template.download&SITE_ID=s1&id=211", "downloadMachine": "https:///rest/1//documentgenerator.api.template.download/?token=" } ], "meta": { "total": 2, "hasMore": false } } ``` ## Пример ответа при ошибке 400 — фильтр по несуществующему полю. Сообщение перечисляет доступные для фильтрации поля: ```json { "success": false, "error": { "code": "UNKNOWN_FILTER_FIELD", "message": "Unknown filter field 'bogusField' for entity 'doc-templates'. Available: id, name, numeratorId, region, code, moduleId, active, bodyType, withStamps, sort, users, fileId, file, createdBy, updatedBy, isDeleted, createTime, updateTime, download, downloadMachine, providers, isDefault, productsTableVariant" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по несуществующему полю. Сообщение перечисляет доступные поля | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `documentgenerator` | | 401 | `TOKEN_MISSING` | У ключа нет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Сортировка и постраничная выборка — на стороне Вайбкод.** `order`, `offset` и `limit` применяются на стороне Вайбкод: набор вытягивается полностью, сортируется и режется по запрошенному окну. `total` и `hasMore` считаются от собранного набора. **Сортировка по несуществующему полю.** Параметр `order` по полю, которого нет, не вызывает ошибку — запрос отрабатывает со статусом `200`, а неизвестное поле сортировки пропускается. **Строковая сортировка — побайтовая.** Сортировка по строковым полям (`name`, `region`) сравнивает строки побайтово, без учёта локали и регистра, поэтому порядок кириллицы и смешанного регистра может отличаться от привычного «человеческого». Числовые (`id`, `sort`) и датовременные (`createTime`, `updateTime`) поля сортируются корректно. Пустые значения (`null`/пустая строка) всегда идут в конце. ## Смотрите также - [Получить шаблон](/docs/entities/doc-templates/get) - [Поиск шаблонов](/docs/entities/doc-templates/search) - [Поля шаблона](/docs/entities/doc-templates/fields) - [Синтаксис фильтрации](/docs/filtering) --- # Doc Templates: Search ## Поиск шаблонов `POST /v1/doc-templates/search` Возвращает шаблоны документов портала по фильтру, переданному в теле запроса. Для выборок до 5000 записей используйте `GET /v1/doc-templates` с параметрами в строке запроса. ## Поля запроса (body) | Поле | Тип | По умолч. | Описание | |------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям шаблона. Список полей — `GET /v1/doc-templates/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `{"filter": {"active": "Y"}}` | | `select` | string[] | — | Выборка полей: `["id", "name", "region"]` | | `sort` | object | — | Сортировка по полю: `{"sort": {"id": "desc"}}` | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Смещение для пагинации | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/doc-templates/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "region": "ru", "active": "Y" }, "limit": 10, "select": ["id", "name", "region", "active"] }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/doc-templates/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "region": "ru", "active": "Y" }, "limit": 10, "select": ["id", "name", "region", "active"] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/doc-templates/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { region: 'ru', active: 'Y' }, limit: 10, select: ['id', 'name', 'region', 'active'], }), }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} шаблонов`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/doc-templates/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { region: 'ru', active: 'Y' }, limit: 10, select: ['id', 'name', 'region', 'active'], }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив шаблонов | | `data[].id` | number | Идентификатор шаблона | | `data[].name` | string | Название | | `data[].active` | string | Доступность: `Y` / `N` | | `data[].code` | string \| null | Системный код шаблона | | `data[].region` | string | Регион | | `data[].sort` | number | Порядок в списке | | `data[].createTime` | string | Дата создания (ISO 8601) | | `data[].updateTime` | string | Дата изменения (ISO 8601) | | `data[].createdBy` | number | Идентификатор создавшего сотрудника | | `data[].updatedBy` | number \| null | Идентификатор изменившего сотрудника | | `data[].moduleId` | string | Модуль-источник шаблона | | `data[].fileId` | number | Идентификатор файла на Диске | | `data[].bodyType` | string | Формат тела документа | | `data[].numeratorId` | number | Идентификатор нумератора | | `data[].withStamps` | string | Печати и подписи: `Y` / `N` | | `data[].productsTableVariant` | string | Вариант таблицы товаров в документе | | `data[].isDeleted` | boolean | Помечен ли шаблон удалённым | | `data[].isDefault` | string | Шаблон по умолчанию: `Y` / `N` | | `data[].users` | array | Идентификаторы сотрудников, которым доступен шаблон | | `data[].download` | string | Адрес скачивания документа | | `data[].downloadMachine` | string | Адрес скачивания для программного доступа | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. Полная схема полей шаблона — [Поля шаблона](./fields.md). ## Пример ответа ```json { "success": true, "data": [ { "id": 209, "active": "Y", "name": "Шаблон договора", "code": null, "region": "ru", "sort": 500, "createTime": "2026-05-12T09:03:38.000Z", "updateTime": "2026-05-12T09:03:38.000Z", "createdBy": 1, "updatedBy": null, "moduleId": "rest", "fileId": 9175, "bodyType": "Bitrix\\DocumentGenerator\\Body\\Docx", "numeratorId": 1, "withStamps": "N", "productsTableVariant": "", "isDeleted": false, "isDefault": "N", "users": ["U1"], "download": "/bitrix/services/main/ajax.php?action=documentgenerator.api.template.download&SITE_ID=s1&id=209", "downloadMachine": "https:///rest/1//documentgenerator.api.template.download/?token=" }, { "id": 211, "active": "Y", "name": "Шаблон счёта", "code": null, "region": "ru", "sort": 500, "createTime": "2026-05-12T09:04:38.000Z", "updateTime": "2026-05-12T09:04:38.000Z", "createdBy": 1, "updatedBy": null, "moduleId": "rest", "fileId": 5901, "bodyType": "Bitrix\\DocumentGenerator\\Body\\Docx", "numeratorId": 1, "withStamps": "N", "productsTableVariant": "", "isDeleted": false, "isDefault": "N", "users": ["U1"], "download": "/bitrix/services/main/ajax.php?action=documentgenerator.api.template.download&SITE_ID=s1&id=211", "downloadMachine": "https:///rest/1//documentgenerator.api.template.download/?token=" } ], "meta": { "total": 2, "hasMore": false, "durationMs": 799 } } ``` ## Пример ответа при ошибке 400 — фильтр по несуществующему полю. Сообщение перечисляет доступные для фильтрации поля: ```json { "success": false, "error": { "code": "UNKNOWN_FILTER_FIELD", "message": "Unknown filter field 'bogusField' for entity 'doc-templates'. Available: id, name, numeratorId, region, code, moduleId, active, bodyType, withStamps, sort, users, fileId, file, createdBy, updatedBy, isDeleted, createTime, updateTime, download, downloadMachine, providers, isDefault, productsTableVariant" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по несуществующему полю. Сообщение перечисляет доступные поля | | 400 | `UNKNOWN_SORT_FIELD` | Сортировка по несуществующему полю в `sort`. Сообщение перечисляет доступные поля | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `documentgenerator` | | 401 | `TOKEN_MISSING` | У ключа нет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Сортировка и постраничная выборка — на стороне Вайбкод.** `sort` (`{"sort": {"поле": "asc|desc"}}`) и `offset`/`limit` применяются на стороне Вайбкод: набор вытягивается полностью, сортируется и режется по запрошенному окну. `total` и `hasMore` считаются от собранного набора. **Строковая сортировка — побайтовая.** Сортировка по строковым полям (`name`, `region`) сравнивает строки побайтово, без учёта локали и регистра. Числовые (`id`, `sort`) и датовременные (`createTime`, `updateTime`) поля сортируются корректно. Пустые значения (`null`/пустая строка) всегда идут в конце. ## Смотрите также - [Список шаблонов](/docs/entities/doc-templates/list) - [Поля шаблона](/docs/entities/doc-templates/fields) - [Синтаксис фильтрации](/docs/filtering) --- # Doc Templates: Update ## Обновить шаблон `PATCH /v1/doc-templates/:id` Частично обновляет шаблон документа. Передавайте плоско в корне JSON только те поля, которые меняете, — остальные значения сохраняются. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор шаблона | ## Поля запроса (body) | Поле | Тип | Описание | |------|-----|---------| | `name` | string | Название шаблона | | `numeratorId` | number | ID нумератора, который присваивает документам порядковые номера | | `region` | string | Код региона шаблона, например `ru` или `by` | | `code` | string | Системный код шаблона для привязки в коде приложения | | `active` | string | Доступность шаблона: `Y` — включён, `N` — выключен | | `withStamps` | string | Печать факсимиле и штампов: `Y` — добавляются, `N` — нет | | `sort` | number | Порядок шаблона в списке: чем меньше значение, тем выше | | `users` | array | Идентификаторы сотрудников, которым доступен шаблон. Список: `GET /v1/users` | Поля только для чтения (`id`, `createdBy`, `updatedBy`, `createTime`, `updateTime`, `isDeleted`, `download`, `downloadMachine`, `providers`, `isDefault`, `productsTableVariant`) в теле запроса не принимаются. ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/doc-templates/209" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Шаблон договора (ред.)" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/doc-templates/209" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Шаблон договора (ред.)" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/doc-templates/209', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Шаблон договора (ред.)', }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/doc-templates/209', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Шаблон договора (ред.)', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Обновлённый шаблон целиком | | `data.id` | number | Идентификатор шаблона | | `data.name` | string | Название | | `data.region` | string | Регион | | `data.code` | string \| null | Системный код шаблона | | `data.active` | string | Доступность: `Y` / `N` | | `data.moduleId` | string | Модуль-источник шаблона | | `data.numeratorId` | number | Идентификатор нумератора | | `data.withStamps` | string | Печати и подписи: `Y` / `N` | | `data.sort` | number | Порядок в списке | | `data.users` | object | Сопоставление идентификаторов сотрудников, которым доступен шаблон | | `data.providers` | object | Поставщики данных шаблона | | `data.isDeleted` | boolean | Помечен ли шаблон удалённым | | `data.createTime` | string | Дата создания (ISO 8601) | | `data.updateTime` | string | Дата изменения (ISO 8601) | | `data.download` | string | Адрес скачивания документа | | `data.downloadMachine` | string | Адрес скачивания для программного доступа | Полная схема полей шаблона — [Поля шаблона](./fields.md). ## Пример ответа ```json { "success": true, "data": { "id": 209, "name": "Шаблон договора (ред.)", "region": "ru", "code": null, "download": "/bitrix/services/main/ajax.php?action=documentgenerator.api.template.download&SITE_ID=s1&id=209&ts=0", "active": "Y", "moduleId": "rest", "numeratorId": 1, "withStamps": "N", "providers": { "bitrix\\documentgenerator\\dataprovider\\rest": "bitrix\\documentgenerator\\dataprovider\\rest" }, "users": { "U1": "U1" }, "isDeleted": false, "sort": 500, "createTime": "2026-05-12T09:03:38.000Z", "updateTime": "2026-05-25T10:00:11.000Z", "downloadMachine": "https:///rest/1//documentgenerator.api.template.download/?token=" } } ``` ## Пример ответа при ошибке 404 — шаблон не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Шаблон не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Шаблона с указанным `id` нет (сообщение «Шаблон не найден») | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `documentgenerator` | | 401 | `TOKEN_MISSING` | У ключа нет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить шаблон](/docs/entities/doc-templates/get) - [Создать шаблон](/docs/entities/doc-templates/create) - [Поля шаблона](/docs/entities/doc-templates/fields) --- # Documents: Create ## Создать документ `POST /v1/documents` Создаёт документ по шаблону: Битрикс24 формирует файл, подставляя в шаблон значения из провайдера данных. ## Поля запроса (body) Минимум для создания: `templateId`, `providerClassName`, `value`. | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `templateId` | number | ★ | Идентификатор шаблона, по которому формируется документ. Список шаблонов: `GET /v1/doc-templates` | | `providerClassName` | string | ★ | Класс провайдера данных — источник значений для меток шаблона. Например `Bitrix\DocumentGenerator\DataProvider\Rest` | | `value` | string | ★ | Внешний идентификатор объекта-источника, по которому провайдер подставляет значения. Например `ORDER-1024` | | `values` | object | | Значения полей-меток шаблона. Ключ — имя метки, значение — подставляемый текст. Например `{"DocumentNumber":"2026-001"}` | | `fields` | object | | Описание форматирования полей документа | | `stampsEnabled` | boolean | | Подставлять в документ печати и подписи | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/documents \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "templateId": 53, "providerClassName": "Bitrix\\DocumentGenerator\\DataProvider\\Rest", "value": "ORDER-1024", "values": { "DocumentNumber": "2026-001" } }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/documents \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "templateId": 53, "providerClassName": "Bitrix\\DocumentGenerator\\DataProvider\\Rest", "value": "ORDER-1024", "values": { "DocumentNumber": "2026-001" } }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/documents', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ templateId: 53, providerClassName: 'Bitrix\\DocumentGenerator\\DataProvider\\Rest', value: 'ORDER-1024', values: { DocumentNumber: '2026-001' }, }), }) const { success, data } = await res.json() console.log('Document ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/documents', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ templateId: 53, providerClassName: 'Bitrix\\DocumentGenerator\\DataProvider\\Rest', value: 'ORDER-1024', values: { DocumentNumber: '2026-001' }, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Созданный документ со всеми полями — см. [Поля документа](/docs/entities/documents/fields) | Поле `provider` в ответе соответствует переданному в запросе `providerClassName`. ## Пример ответа ```json { "success": true, "data": { "id": 51, "title": "Договор поставки 2026-001", "number": "2026-001", "templateId": 53, "provider": "Bitrix\\DocumentGenerator\\DataProvider\\Rest", "value": "ORDER-1024", "fileId": 241, "pdfId": 245, "imageId": 243, "createTime": "2026-03-18T17:27:48+03:00", "updateTime": "2026-03-18T17:27:48+03:00", "createdBy": 503, "updatedBy": null, "values": { "DocumentNumber": "2026-001" }, "stampsEnabled": false, "publicUrl": null, "downloadUrl": "https://example.bitrix24.ru/bitrix/services/main/ajax.php?action=documentgenerator.api.document.getfile&id=51", "pdfUrl": "https://example.bitrix24.ru/bitrix/services/main/ajax.php?action=documentgenerator.api.document.getpdf&id=51" } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'documentgenerator' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `documentgenerator` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 400 | `MISSING_REQUIRED_FIELDS` | Не передано одно из обязательных полей: `templateId`, `providerClassName` или `value` | | 404 | `ENTITY_NOT_FOUND` | Шаблон с указанным `templateId` не найден или недоступен | | 422 | `BITRIX_ERROR` | Провайдер данных не вернул объект по указанному `value` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список документов](/docs/entities/documents/list) - [Получить документ](/docs/entities/documents/get) - [Шаблоны документов](/docs/entities/doc-templates) - [Entity API](/docs/entity-api) --- # Documents: Crm List ## Документы по CRM-сущности `GET /v1/crm-documents` Возвращает документы, прикреплённые к конкретной записи CRM — сделке, контакту, компании, лиду, предложению, счёту или элементу смарт-процесса. В отличие от списка всех документов портала, отбор идёт по типу записи и её идентификатору. ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|-------|-----------|---------| | `entityTypeId` (query) | number | да | — | Тип записи CRM. Допустимые значения — в списке «Типы записей CRM» ниже | | `entityId` (query) | number | нет | — | ID записи. Без него возвращаются документы всех записей указанного типа. Где взять ID по типу — в списке «Типы записей CRM» ниже | | `select` (query) | string | нет | — | Выборка полей: `?select=id,title,number` | | `order` (query) | object | нет | — | Сортировка: `?order[updateTime]=desc`. Направление — `asc` или `desc` | | `start` (query) | number | нет | `0` | Смещение для постраничного чтения | За один вызов возвращается до 50 документов. Для следующей страницы передайте значение `meta.next` в параметр `start`. Когда документов больше нет, `meta.next` равно `null`. ### Типы записей CRM Значение `entityTypeId` и эндпоинт, откуда взять `entityId`: - `1` — лид. ID записи: `GET /v1/leads` - `2` — сделка. ID записи: `GET /v1/deals` - `3` — контакт. ID записи: `GET /v1/contacts` - `4` — компания. ID записи: `GET /v1/companies` - `7` — предложение. ID записи: `GET /v1/quotes` - `31` — счёт. ID записи: `GET /v1/invoices` - `128` и выше — элемент смарт-процесса. Значение `entityTypeId` — из `GET /v1/smart-processes`, ID записи — из `GET /v1/items/:entityTypeId` ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/crm-documents?entityTypeId=2&entityId=15&order[updateTime]=desc" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/crm-documents?entityTypeId=2&entityId=15&order[updateTime]=desc" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/crm-documents?entityTypeId=2&entityId=15&order[updateTime]=desc', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`У записи ${meta.total} документов`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/crm-documents?entityTypeId=2&entityId=15&order[updateTime]=desc', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа Идентификаторы возвращаются строками. | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив документов | | `data[].id` | string | Идентификатор документа | | `data[].title` | string | Название документа | | `data[].number` | string | Номер документа | | `data[].templateId` | string | Идентификатор шаблона. Источник — `GET /v1/doc-templates` | | `data[].entityTypeId` | string | Тип записи CRM, к которой прикреплён документ | | `data[].entityId` | string | ID записи CRM, к которой прикреплён документ | | `data[].fileId` | string | Идентификатор готового файла | | `data[].pdfId` | string | Идентификатор PDF-версии | | `data[].imageId` | string | Идентификатор изображения-превью | | `data[].downloadUrl` | string | Ссылка на скачивание файла для пользователя | | `data[].pdfUrl` | string | Ссылка на PDF для пользователя | | `data[].imageUrl` | string | Ссылка на изображение-превью для пользователя | | `data[].downloadUrlMachine` | string | Ссылка на скачивание для приложения | | `data[].pdfUrlMachine` | string | Ссылка на PDF для приложения | | `data[].imageUrlMachine` | string | Ссылка на изображение для приложения | | `data[].stampsEnabled` | boolean | Включены ли подпись и печать | | `data[].values` | object | Значения полей-меток шаблона | | `data[].createTime` | string | Дата создания в формате ISO 8601 | | `data[].updateTime` | string | Дата изменения в формате ISO 8601 | | `data[].createdBy` | string | ID создателя. Источник — `GET /v1/users` | | `data[].updatedBy` | string \| null | ID последнего редактора. Источник — `GET /v1/users` | | `meta.total` | number | Количество документов у записи | | `meta.start` | number | Смещение текущей страницы | | `meta.next` | number \| null | Смещение следующей страницы. `null`, если документов больше нет | ## Пример ответа ```json { "success": true, "data": [ { "id": "405", "title": "Счёт А161", "number": "А161", "templateId": "1", "entityTypeId": "2", "entityId": "15", "fileId": "1369", "pdfId": "1373", "imageId": "1371", "downloadUrl": "https://example.bitrix24.ru/bitrix/services/main/ajax.php?action=crm.documentgenerator.document.download&id=405", "pdfUrl": "https://example.bitrix24.ru/bitrix/services/main/ajax.php?action=crm.documentgenerator.document.getPdf&id=405", "imageUrl": "https://example.bitrix24.ru/bitrix/services/main/ajax.php?action=crm.documentgenerator.document.getImage&id=405", "downloadUrlMachine": "https://example.bitrix24.ru/rest/1/APP_TOKEN/crm.documentgenerator.document.download/?id=405", "pdfUrlMachine": "https://example.bitrix24.ru/rest/1/APP_TOKEN/crm.documentgenerator.document.getPdf/?id=405", "imageUrlMachine": "https://example.bitrix24.ru/rest/1/APP_TOKEN/crm.documentgenerator.document.getImage/?id=405", "stampsEnabled": false, "values": { "_creationMethod": "public" }, "createTime": "2026-01-18T11:10:00+03:00", "updateTime": "2026-01-18T11:10:00+03:00", "createdBy": "29", "updatedBy": null }, { "id": "406", "title": "Акт А162", "number": "А162", "templateId": "4", "entityTypeId": "2", "entityId": "15", "fileId": "1402", "pdfId": "1404", "imageId": "1403", "downloadUrl": "https://example.bitrix24.ru/bitrix/services/main/ajax.php?action=crm.documentgenerator.document.download&id=406", "pdfUrl": "https://example.bitrix24.ru/bitrix/services/main/ajax.php?action=crm.documentgenerator.document.getPdf&id=406", "imageUrl": "https://example.bitrix24.ru/bitrix/services/main/ajax.php?action=crm.documentgenerator.document.getImage&id=406", "downloadUrlMachine": "https://example.bitrix24.ru/rest/1/APP_TOKEN/crm.documentgenerator.document.download/?id=406", "pdfUrlMachine": "https://example.bitrix24.ru/rest/1/APP_TOKEN/crm.documentgenerator.document.getPdf/?id=406", "imageUrlMachine": "https://example.bitrix24.ru/rest/1/APP_TOKEN/crm.documentgenerator.document.getImage/?id=406", "stampsEnabled": false, "values": { "_creationMethod": "public" }, "createTime": "2026-01-19T09:30:00+03:00", "updateTime": "2026-01-19T09:30:00+03:00", "createdBy": "29", "updatedBy": null } ], "meta": { "total": 2, "start": 0, "next": null } } ``` ## Пример ответа при ошибке 400 — `entityTypeId` не передан или некорректен. Значение `0`, дробное или нечисловое возвращает тот же код: ```json { "success": false, "error": { "code": "MISSING_PARAMS", "message": "Query parameter `entityTypeId` (positive integer) is required. Common values: 1=LEAD, 2=DEAL, 3=CONTACT, 4=COMPANY, 7=QUOTE, 31=INVOICE, 128+ for smart processes." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_PARAMS` | Не передан `entityTypeId` или его значение не является положительным целым числом | | 400 | `INVALID_ENTITY_ID` | `entityId` передан, но не является положительным целым числом | | 400 | `INVALID_START` | `start` передан, но не является целым числом 0 или больше | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `crm` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `TOKEN_MISSING` | Ключу авторизации не сопоставлены токены — ключ OAuth-приложения вызван без пользовательской сессии | | 422 | `BITRIX_ERROR` | Модуль генератора документов не установлен на портале | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности Параметр `select` ограничивает набор полей, но ссылки на файлы `downloadUrl`, `pdfUrl`, `imageUrl` вместе с машинными вариантами, а также `stampsEnabled` и `values` возвращаются всегда, даже если их нет в выборке. ## Смотрите также - [Список документов](/docs/entities/documents/list) - [Создать документ](/docs/entities/documents/create) - [Шаблоны документов](/docs/entities/doc-templates) --- # Documents: Delete ## Удалить документ `DELETE /v1/documents/:id` Удаляет документ по идентификатору. Восстановить удалённый документ через API нельзя — создавайте новый при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор документа | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/documents/51" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/documents/51" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/documents/51', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Документ удалён') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/documents/51', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом. Признак успеха — код ответа, не содержимое. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — документ не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Документ не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Документ с таким `id` не найден | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `documentgenerator` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить документ](/docs/entities/documents/get) - [Список документов](/docs/entities/documents/list) - [Entity API](/docs/entity-api) --- # Documents: Fields ## Поля документа `GET /v1/documents/fields` Возвращает полную схему полей документа: имя поля, тип, признак «только для чтения» и обязательность при создании. Поля помечены ★ — обязательны в теле запроса при создании документа. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/documents/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/documents/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/documents/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Всего полей:', Object.keys(data.fields).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/documents/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа `data.fields` — объект, ключ которого совпадает с именем поля, а значение содержит `type` (тип поля), `readonly` (`true` — поле нельзя передать при создании и обновлении), `label` (отображаемое название) и `description` (краткое описание). Значения `label`/`description` приходят на русском языке. | Поле | Битрикс24 | Тип | RO | Описание | |------|----------|-----|:--:|---------| | `id` | `id` | number | да | Идентификатор документа | | `title` | `title` | string | | Название документа | | `number` | `number` | string | | Номер документа | | `templateId` | `templateId` | number | | ★ Идентификатор шаблона. Список: `GET /v1/doc-templates` | | `providerClassName` | `providerClassName` | string | | ★ Класс провайдера данных, например `Bitrix\DocumentGenerator\DataProvider\Rest` | | `value` | `value` | string | | ★ Внешний идентификатор объекта-источника, из которого подставляются данные | | `values` | `values` | object | | Значения полей-меток шаблона | | `fields` | `fields` | object | | Описание форматирования полей | | `createTime` | `createTime` | datetime | да | Дата создания | | `updateTime` | `updateTime` | datetime | да | Дата последнего изменения | | `fileId` | `fileId` | number | | Идентификатор файла DOCX | | `pdfId` | `pdfId` | number | | Идентификатор файла PDF | | `imageId` | `imageId` | number | | Идентификатор файла изображения | | `stampsEnabled` | `stampsEnabled` | boolean | | Включены ли печати и подписи | | `provider` | `provider` | string | да | Класс провайдера данных документа | | `downloadUrl` | `downloadUrl` | string | да | Ссылка на скачивание DOCX для пользователя | | `pdfUrl` | `pdfUrl` | string | да | Ссылка на скачивание PDF для пользователя | | `imageUrl` | `imageUrl` | string | да | Ссылка на изображение для пользователя | | `downloadUrlMachine` | `downloadUrlMachine` | string | да | Ссылка на скачивание DOCX для приложения | | `pdfUrlMachine` | `pdfUrlMachine` | string | да | Ссылка на скачивание PDF для приложения | | `imageUrlMachine` | `imageUrlMachine` | string | да | Ссылка на изображение для приложения | | `createdBy` | `createdBy` | number | да | Идентификатор создавшего пользователя. Список: `GET /v1/users` | | `updatedBy` | `updatedBy` | number \| null | да | Идентификатор изменившего пользователя. `null`, если документ не изменялся. Список: `GET /v1/users` | | `publicUrl` | `publicUrl` | string \| null | да | Публичная ссылка на документ. `null`, если публичная ссылка не сформирована | ★ — поля `templateId`, `providerClassName`, `value` обязательны в теле запроса при создании документа. ## Пример ответа Показаны 8 из 24 полей. Полный список — в таблице выше. ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "ID", "description": "Уникальный числовой идентификатор сгенерированного документа." }, "title": { "type": "string", "readonly": false, "label": "Название", "description": "Название документа." }, "number": { "type": "string", "readonly": false, "label": "Номер", "description": "Номер документа, отображаемый в печатной форме." }, "templateId": { "type": "number", "readonly": false, "required": true, "label": "Шаблон", "description": "ID шаблона, по которому создаётся документ. Список: GET /v1/doc-templates." }, "providerClassName": { "type": "string", "readonly": false, "required": true, "label": "Провайдер данных", "description": "Имя класса провайдера данных, который поставляет значения для шаблона." }, "value": { "type": "string", "readonly": false, "required": true, "label": "Идентификатор владельца", "description": "Идентификатор сущности, по которой провайдер данных строит документ (например, ID сделки)." }, "createTime": { "type": "datetime", "readonly": true, "label": "Дата создания", "description": "Дата и время создания документа." }, "publicUrl": { "type": "string", "readonly": true, "label": "Публичная ссылка", "description": "Публичная ссылка для передачи документа." } }, "batch": ["create", "update", "delete"] } } ``` Поле `batch` перечисляет операции документа, доступные в [пакетном запросе](/docs/batch). ## Пример ответа при ошибке 403 — у ключа нет нужного скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'documentgenerator' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключу не хватает скоупа `documentgenerator` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список документов](/docs/entities/documents/list) - [Создать документ](/docs/entities/documents/create) - [Справочник сущностей](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) --- # Documents: Get ## Получить документ `GET /v1/documents/:id` Возвращает документ по идентификатору со всеми полями, включая ссылки на готовый файл, PDF и изображение. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор документа | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/documents/51" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/documents/51" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/documents/51', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Документ:', data.title, '—', data.number) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/documents/51', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект документа со всеми полями — см. [Поля документа](/docs/entities/documents/fields) | ## Пример ответа ```json { "success": true, "data": { "id": 51, "title": "Договор поставки 2026-001", "number": "2026-001", "templateId": 53, "provider": "Bitrix\\DocumentGenerator\\DataProvider\\Rest", "value": "ORDER-1024", "fileId": 241, "pdfId": 245, "imageId": 243, "createTime": "2026-03-18T17:27:48+03:00", "updateTime": "2026-03-18T17:27:48+03:00", "createdBy": 503, "updatedBy": null, "values": { "DocumentNumber": "2026-001", "ClientName": "ООО «Ромашка»" }, "stampsEnabled": false, "publicUrl": "https://example.bitrix24.ru/~aBcDeF", "downloadUrl": "https://example.bitrix24.ru/bitrix/services/main/ajax.php?action=documentgenerator.api.document.getfile&id=51", "pdfUrl": "https://example.bitrix24.ru/bitrix/services/main/ajax.php?action=documentgenerator.api.document.getpdf&id=51", "imageUrl": "https://example.bitrix24.ru/bitrix/services/main/ajax.php?action=documentgenerator.api.document.getimage&id=51", "downloadUrlMachine": "https://example.bitrix24.ru/rest/documentgenerator.api.document.getfile.json?token=t0k3n", "pdfUrlMachine": "https://example.bitrix24.ru/rest/documentgenerator.api.document.getpdf.json?token=t0k3n", "imageUrlMachine": "https://example.bitrix24.ru/rest/documentgenerator.api.document.getimage.json?token=t0k3n" } } ``` ## Пример ответа при ошибке 404 — документ не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Документ не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Документ с таким `id` не найден | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `documentgenerator` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список документов](/docs/entities/documents/list) - [Обновить документ](/docs/entities/documents/update) - [Поля документа](/docs/entities/documents/fields) - [Entity API](/docs/entity-api) --- # Documents: List ## Список документов `GET /v1/documents` Возвращает список документов с поддержкой фильтрации, сортировки, выбора полей и автоматической пагинации. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` Вайбкод автоматически запрашивает несколько страниц | | `offset` | number | `0` | Пропустить N записей. При `offset > 0` рекомендуется `limit ≤ 500` | | `select` | string | — | Выборка полей: `?select=id,title,number` | | `order` | object | — | Сортировка: `?order[id]=desc` | | `filter` | object | — | Фильтрация по полям `GET /v1/documents/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[templateId]=53` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/documents?limit=10&order[id]=desc&filter[templateId]=53" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/documents?limit=10&order[id]=desc&filter[templateId]=53" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/documents?limit=10&order[id]=desc&filter[templateId]=53', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} документов`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/documents?limit=10&order[id]=desc&filter[templateId]=53', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив документов (все поля элемента — см. [Поля документа](/docs/entities/documents/fields)) | | `meta.total` | number | Количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | ## Пример ответа ```json { "success": true, "data": [ { "id": 51, "title": "Договор поставки 2026-001", "number": "2026-001", "templateId": 53, "provider": "Bitrix\\DocumentGenerator\\DataProvider\\Rest", "value": "ORDER-1024", "fileId": 241, "pdfId": 245, "imageId": 243, "createTime": "2026-03-18T17:27:48+03:00", "updateTime": "2026-03-18T17:27:48+03:00", "createdBy": 503, "updatedBy": null, "values": { "DocumentNumber": "2026-001" }, "stampsEnabled": false, "downloadUrl": "https://example.bitrix24.ru/bitrix/services/main/ajax.php?action=documentgenerator.api.document.getfile&id=51", "pdfUrl": "https://example.bitrix24.ru/bitrix/services/main/ajax.php?action=documentgenerator.api.document.getpdf&id=51", "imageUrl": "https://example.bitrix24.ru/bitrix/services/main/ajax.php?action=documentgenerator.api.document.getimage&id=51", "downloadUrlMachine": "https://example.bitrix24.ru/rest/documentgenerator.api.document.getfile.json?token=t0k3n", "pdfUrlMachine": "https://example.bitrix24.ru/rest/documentgenerator.api.document.getpdf.json?token=t0k3n", "imageUrlMachine": "https://example.bitrix24.ru/rest/documentgenerator.api.document.getimage.json?token=t0k3n" }, { "id": 52, "title": "Договор поставки 2026-002", "number": "2026-002", "templateId": 53, "provider": "Bitrix\\DocumentGenerator\\DataProvider\\Rest", "value": "ORDER-1025", "fileId": 248, "pdfId": 250, "imageId": 249, "createTime": "2026-03-19T10:12:03+03:00", "updateTime": "2026-03-19T10:12:03+03:00", "createdBy": 503, "updatedBy": null, "values": { "DocumentNumber": "2026-002" }, "stampsEnabled": false, "downloadUrl": "https://example.bitrix24.ru/bitrix/services/main/ajax.php?action=documentgenerator.api.document.getfile&id=52", "pdfUrl": "https://example.bitrix24.ru/bitrix/services/main/ajax.php?action=documentgenerator.api.document.getpdf&id=52", "imageUrl": "https://example.bitrix24.ru/bitrix/services/main/ajax.php?action=documentgenerator.api.document.getimage&id=52", "downloadUrlMachine": "https://example.bitrix24.ru/rest/documentgenerator.api.document.getfile.json?token=t0k3n", "pdfUrlMachine": "https://example.bitrix24.ru/rest/documentgenerator.api.document.getpdf.json?token=t0k3n", "imageUrlMachine": "https://example.bitrix24.ru/rest/documentgenerator.api.document.getimage.json?token=t0k3n" } ], "meta": { "total": 2, "hasMore": false } } ``` ## Пример ответа при ошибке 400 — фильтр по несуществующему полю: ```json { "success": false, "error": { "code": "UNKNOWN_FILTER_FIELD", "message": "Unknown filter field 'zzzNope' for entity 'documents'. Available: id, title, number, templateId, providerClassName, value, values, fields, createTime, updateTime, fileId, pdfId, imageId, stampsEnabled, provider, downloadUrl, pdfUrl, imageUrl, downloadUrlMachine, pdfUrlMachine, imageUrlMachine, createdBy, updatedBy, publicUrl" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет у документа. Список полей — `GET /v1/documents/fields` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `documentgenerator` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности Поле `publicUrl` доступно только в ответе `GET /v1/documents/:id`, в списке оно не приходит. При `limit > 50` Вайбкод запрашивает несколько страниц и собирает все записи в один ответ. За один вызов возвращается не более 5000 записей. При `offset ≥ 2500` для устойчивости запроса используйте `limit ≤ 500`. Для сложных фильтров с множеством условий параметры передаются в теле запроса — `POST /v1/documents/search`. Этот эндпоинт также поддерживает оконный поиск по датам для больших выборок. См. [Поиск документов](/docs/entities/documents/search). ## Смотрите также - [Поиск документов](/docs/entities/documents/search) - [Создать документ](/docs/entities/documents/create) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entity-api) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Documents: Search ## Поиск документов `POST /v1/documents/search` Возвращает документы по фильтру, переданному в теле запроса. Аналогичен `GET /v1/documents` с фильтрами, но условия отбора передаются в теле запроса — это удобнее для сложных выборок с большим количеством условий. ## Поля запроса (body) | Поле | Тип | По умолч. | Описание | |------|-----|-----------|---------| | `filter` | object | — | Отбор по полям документа.
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "filter": { "templateId": 53 } }` | | `limit` | number | `50` | Количество документов в ответе, до 5000 | | `offset` | number | `0` | Пропустить указанное число документов. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки» | | `sort` | object | — | Сортировка: `{ "id": "desc" }`. Допустимы те же поля, что и в `filter` | | `select` | string[] | — | Выборка полей: `["id", "title", "number"]`. В ответе остаются только перечисленные поля и `id` | | `autoWindow` | boolean | `true` | Разбивать выборку по недельным окнам при фильтре по диапазону дат шире 14 дней. `false` отключает разбиение | Имена полей для `filter`, `sort` и `select` — из [Полей документа](/docs/entities/documents/fields). ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/documents/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "templateId": 53 }, "limit": 10, "sort": { "id": "desc" } }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/documents/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "templateId": 53 }, "limit": 10, "sort": { "id": "desc" } }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/documents/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { templateId: 53 }, limit: 10, sort: { id: 'desc' }, }), }) const { data, meta } = await res.json() console.log('Найдено:', meta.total) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/documents/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { templateId: 53 }, limit: 10, sort: { id: 'desc' }, }), }) const { data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив документов (все поля — см. [Поля документа](/docs/entities/documents/fields)) | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временны́м окнам | | `meta.windowCount` | number | Число окон. Приходит при `autoWindowed: true` | | `meta.batchWaves` | number | Число волн параллельных запросов. Приходит при `autoWindowed: true` | ## Пример ответа ```json { "success": true, "data": [ { "id": 51, "title": "Договор поставки 2026-001", "number": "2026-001", "templateId": 53, "provider": "Bitrix\\DocumentGenerator\\DataProvider\\Rest", "value": "ORDER-1024", "createTime": "2026-03-18T17:27:48+03:00", "updateTime": "2026-03-18T17:27:48+03:00", "createdBy": 503, "updatedBy": null, "values": { "DocumentNumber": "2026-001" }, "stampsEnabled": false, "pdfUrl": "https://example.bitrix24.ru/bitrix/services/main/ajax.php?action=documentgenerator.api.document.getpdf&id=51" } ], "meta": { "total": 1, "hasMore": false, "durationMs": 42 } } ``` Когда под фильтр не попал ни один документ, `data` приходит пустым массивом, а `meta.total` равен `0`: ```json { "success": true, "data": [], "meta": { "total": 0, "hasMore": false, "durationMs": 644 } } ``` С фильтром по диапазону дат шире 14 дней в `meta` дополнительно приходят `autoWindowed`, `windowCount` и `batchWaves`: ```json { "success": true, "data": [], "meta": { "total": 0, "hasMore": false, "autoWindowed": true, "windowCount": 339, "batchWaves": 7, "durationMs": 7890 } } ``` ## Пример ответа при ошибке 400 — поле в `filter` не входит в список полей документа: ```json { "success": false, "error": { "code": "UNKNOWN_FILTER_FIELD", "message": "Unknown filter field 'notArealField' for entity 'documents'." } } ``` ## Известные особенности Имя поля в `filter` и `sort` сверяется со списком полей документа до обращения к данным. Неизвестное поле в `filter` возвращает `400 UNKNOWN_FILTER_FIELD`, неизвестное поле в `sort` — `400 UNKNOWN_SORT_FIELD`. В обоих случаях сообщение перечисляет допустимые имена полей. **Разбиение по временны́м окнам.** Фильтр по диапазону дат шире 14 дней (поля `createTime` или `updateTime`) автоматически разбивается на недельные окна, которые выполняются параллельными волнами — так выборка обходит потолок в 5000 документов на один вызов. В `meta` тогда приходят `autoWindowed: true`, число окон `windowCount` и число волн `batchWaves`. Отключает разбиение параметр `autoWindow: false`. При активном разбиении `offset` больше нуля отклоняется с `UNSTABLE_OFFSET_PAGINATION`. ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNKNOWN_FILTER_FIELD` | Поле в `filter` не входит в список полей документа | | 400 | `UNKNOWN_SORT_FIELD` | Поле в `sort` не входит в список полей документа | | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `documentgenerator` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список документов](/docs/entities/documents/list) - [Синтаксис фильтрации](/docs/filtering) - [Справочник сущностей](/docs/entity-api) - [Batch](/docs/batch) --- # Documents: Update ## Обновить документ `PATCH /v1/documents/:id` Обновляет поля существующего документа — передайте только изменяемые. Системные поля (даты, автор, ссылки на файлы) доступны только для чтения. Полный список — в [справочнике полей](/docs/entities/documents/fields). ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор документа | ## Поля запроса (body) | Параметр | Тип | Описание | |----------|-----|---------| | `title` | string | Название документа | | `number` | string | Номер документа | | `stampsEnabled` | boolean | Печати и подписи на документе | | `values` | object | Значения полей-меток шаблона | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/documents/51" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Договор поставки 2026-001 (ред.)", "stampsEnabled": true }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/documents/51" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Договор поставки 2026-001 (ред.)", "stampsEnabled": true }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/documents/51', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Договор поставки 2026-001 (ред.)', stampsEnabled: true, }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/documents/51', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Договор поставки 2026-001 (ред.)', stampsEnabled: true, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект документа со всеми полями — см. [Поля документа](/docs/entities/documents/fields) | ## Пример ответа ```json { "success": true, "data": { "id": 51, "title": "Договор поставки 2026-001 (ред.)", "number": "2026-001", "templateId": 53, "provider": "Bitrix\\DocumentGenerator\\DataProvider\\Rest", "value": "ORDER-1024", "createTime": "2026-03-18T17:27:48+03:00", "updateTime": "2026-03-20T09:14:11+03:00", "createdBy": 503, "updatedBy": 503, "values": { "DocumentNumber": "2026-001" }, "stampsEnabled": true, "publicUrl": "https://example.bitrix24.ru/~aBcDeF", "downloadUrl": "https://example.bitrix24.ru/bitrix/services/main/ajax.php?action=documentgenerator.api.document.getfile&id=51", "pdfUrl": "https://example.bitrix24.ru/bitrix/services/main/ajax.php?action=documentgenerator.api.document.getpdf&id=51" } } ``` ## Пример ответа при ошибке 404 — документ не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Документ не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Документа с указанным `id` не существует | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `documentgenerator` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить документ](/docs/entities/documents/get) - [Создать документ](/docs/entities/documents/create) - [Поля документа](/docs/entities/documents/fields) - [Entity API](/docs/entity-api) --- # Files: Copyto ## Скопировать файл `POST /v1/files/:id/copyto` Создаёт копию файла в указанной папке. Оригинал остаётся на месте, копия получает новый идентификатор. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|---------| | `id` | path | number | да | ID файла, который нужно скопировать. Получить через `GET /v1/files` | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `targetFolderId` | number | да | ID папки-назначения. Получить через `GET /v1/folders` | ## Примеры ### curl — личный ключ ```bash curl -X POST \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"targetFolderId": 649}' \ https://vibecode.bitrix24.tech/v1/files/9250/copyto ``` ### curl — OAuth-приложение ```bash curl -X POST \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"targetFolderId": 649}' \ https://vibecode.bitrix24.tech/v1/files/9250/copyto ``` ### JavaScript — личный ключ ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/files/9250/copyto', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ targetFolderId: 649 }), } ) const body = await res.json() if (!body.success) { console.error(body.error.code, body.error.message) } else { console.log('Копия создана, ID:', body.data.id) } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/files/9250/copyto', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ targetFolderId: 649 }), } ) const body = await res.json() ``` ## Поля ответа Возвращается объект созданной копии. | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | `true` при успешном копировании | | `data.id` | number | ID созданной копии (отличается от ID оригинала) | | `data.name` | string | Имя файла | | `data.code` | string \| null | Системный код файла | | `data.storageId` | number | ID хранилища | | `data.type` | string | Тип объекта — всегда `"file"` | | `data.folderId` | number | ID папки-назначения | | `data.deletedType` | number | Тип удаления: `0` — не удалён | | `data.globalContentVersion` | number | Глобальная версия содержимого | | `data.fileId` | number | Внутренний идентификатор содержимого файла | | `data.size` | number | Размер в байтах | | `data.createdBy` | number | ID пользователя, создавшего копию | | `data.updatedBy` | number | ID пользователя, обновившего копию | | `data.deletedBy` | number \| null | ID удалившего. У новой копии всегда `null` | | `data.createdAt` | string (ISO 8601) | Дата создания копии | | `data.updatedAt` | string (ISO 8601) | Дата обновления копии | | `data.deletedAt` | string \| null | Дата удаления. У новой копии всегда `null` | | `data.downloadUrl` | string | Прямой URL для скачивания файла | | `data.detailUrl` | string | URL карточки файла в Битрикс24 | ## Пример ответа ```json { "success": true, "data": { "id": 9253, "name": "doc-copy-test.txt", "code": null, "storageId": 1, "type": "file", "folderId": 649, "deletedType": 0, "globalContentVersion": 1, "fileId": 34869, "size": 4, "createdBy": 1, "updatedBy": 1, "deletedBy": null, "createdAt": "2026-05-06T09:35:13.000Z", "updatedAt": "2026-05-06T09:35:13.000Z", "deletedAt": null, "downloadUrl": "https://...", "detailUrl": "https://..." } } ``` ## Пример ответа при ошибке 400 — не передан `targetFolderId`: ```json { "success": false, "error": { "code": "MISSING_PARAMS", "message": "targetFolderId is required." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_PARAMS` | Не передан обязательный параметр `targetFolderId` | | 400 | `INVALID_PARAMS` | `targetFolderId` не является положительным целым числом | | 400 | `INVALID_ID` | `id` в path не является положительным целым числом | | 400 | `OPERATION_FAILED` | Битрикс24 вернул пустой результат — копирование не выполнено | | 401 | `TOKEN_MISSING` | Для портала не найдены токены авторизации | | 403 | `SCOPE_DENIED` | У API-ключа отсутствует скоуп `disk` | | 422 | `BITRIX_ERROR` | В папке-назначении уже существует файл с таким именем | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Копия получает новый ID.** Оригинал остаётся в исходной папке без изменений. Идентификатор копии (поле `data.id`) не совпадает с идентификатором оригинала — используйте `data.id` для дальнейшей работы с копией. - **Копирование работает между хранилищами.** В отличие от операции перемещения (`POST /v1/files/:id/moveto`), копирование допустимо даже тогда, когда исходный файл и папка-назначение принадлежат разным хранилищам. - **Конфликт имён.** Если в папке-назначении уже есть файл с таким же именем, операция завершится ошибкой `422`. Переименуйте оригинал или выберите другую папку. ## Смотрите также - [Переместить файл](./moveto.md) - [Загрузить файл](./upload.md) - [Список файлов](./list.md) - [Список папок](/docs/entities/folders) --- # Files: Delete ## Удалить файл `DELETE /v1/files/:id` Перемещает файл в корзину Битрикс24. Файл не удаляется навсегда — его можно восстановить средствами Битрикс24 вручную. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|----------| | `id` (path) | number | да | ID файла. Целое число больше нуля | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/files/3291" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/files/3291" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/files/3291', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Файл перемещён в корзину') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/files/3291', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Файл перемещён в корзину') } ``` ## Ответ При успешном перемещении в корзину возвращается HTTP-статус `204 No Content` с пустым телом. Признак успеха — код ответа, не содержимое. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — файл не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Could not find entity with id '99999999'." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 404 | `ENTITY_NOT_FOUND` | Файл с указанным ID не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `disk` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов авторизации | | 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности Операция перемещает файл в корзину Битрикс24 — мягкое удаление. Файл сохраняется в корзине и может быть восстановлен администратором портала через интерфейс Битрикс24. Безвозвратное удаление через API Вайбкод недоступно. ## Смотрите также - [Список файлов](/docs/entities/files/list) - [Получить файл](/docs/entities/files/get) - [Переименовать файл](/docs/entities/files/update) - [Загрузить файл](/docs/entities/files/upload) --- # Files: Download ## Скачать файл `GET /v1/files/:id/download` Скачивает содержимое файла через прокси платформы Вайбкод с автоматической авторизацией. В отличие от поля `downloadUrl` в ответе `GET /v1/files/:id`, этот эндпоинт добавляет авторизацию при каждом вызове — токен не нужно извлекать и подставлять вручную. Ответ — бинарный поток с заголовком `Content-Disposition`, браузеры предлагают сохранить файл автоматически. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | number | да | ID файла. Получить: `GET /v1/files` или `GET /v1/files/:id` | Тело запроса пустое. ## Примеры ### curl — личный ключ ```bash # Сохранить в файл с исходным именем из заголовка Content-Disposition curl -OJ -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/files/205/download # Указать имя файла явно curl -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/files/205/download \ -o myfile.pdf ``` ### curl — OAuth-приложение ```bash curl -OJ \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ https://vibecode.bitrix24.tech/v1/files/205/download ``` ### JavaScript — личный ключ ```javascript const fileId = 205 const res = await fetch( `https://vibecode.bitrix24.tech/v1/files/${fileId}/download`, { headers: { 'X-Api-Key': 'YOUR_API_KEY' } } ) if (!res.ok) { const body = await res.json() throw new Error(body.error?.code ?? String(res.status)) } // Сохранить blob в браузере const blob = await res.blob() const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = res.headers.get('Content-Disposition')?.match(/filename="(.+?)"/)?.[1] ?? 'file' a.click() URL.revokeObjectURL(url) ``` ### JavaScript — OAuth-приложение ```javascript const fileId = 205 const res = await fetch( `https://vibecode.bitrix24.tech/v1/files/${fileId}/download`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, } ) if (!res.ok) { const body = await res.json() throw new Error(body.error?.code ?? String(res.status)) } const blob = await res.blob() ``` ## Заголовки ответа При успехе возвращается бинарное содержимое файла (HTTP 200). Секции `## Поля ответа` нет — тело ответа не является JSON. | Заголовок | Пример значения | Описание | |-----------|-----------------|----------| | `Content-Type` | `application/pdf` | Тип содержимого. Зависит от типа файла: `text/plain`, `image/png`, `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` и т. д. | | `Content-Disposition` | `attachment; filename="report.pdf"` | Имя файла для сохранения. Браузеры используют его автоматически при скачивании | | `Content-Length` | `31232` | Размер файла в байтах. Передаётся, если известен из метаданных | ## Пример ответа при ошибке 404 — файл не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Could not find entity with id '99999999'." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный ключ | | 403 | `SCOPE_DENIED` | У ключа нет ни скоупа `disk`, ни скоупа `crm`. Достаточно любого из двух — почему, см. «Известные особенности» | | 404 | `ENTITY_NOT_FOUND` | Файла с таким `id` не существует или он недоступен ключу | | 404 | `DOWNLOAD_URL_NOT_FOUND` | У файла нет адреса для скачивания | | 502 | `DOWNLOAD_FAILED` | Битрикс24 вернул ошибку при проксировании (например, `403`) | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Достаточно скоупа `disk` или скоупа `crm`.** Обычно файл Диска скачивают ключом со скоупом `disk`. Ключ только со скоупом `crm` подходит тоже: пользовательское поле типа «Файл» в карточке CRM хранит идентификатор того же самого файла Диска, и без этого послабления такой ключ не смог бы забрать вложение собственной карточки. В машинной спецификации это объявлено полем `x-required-scope: disk` и соседним `x-alternative-scopes: ["crm"]`. Речь только о проверке скоупа на стороне Вайбкода: сам вызов Диска в Битрикс24 по-прежнему требует, чтобы доступ к Диску был у подключения портала, иначе вернётся ошибка Битрикс24. - **Авторизация добавляется автоматически.** Для ключей OAuth-приложений Вайбкод добавляет токен авторизации к запросу при каждом вызове. Для ключей типа вебхук токен уже встроен в адрес — Вайбкод использует адрес как есть. - **Поле `downloadUrl` из `GET /v1/files/:id` — временное.** Этот эндпоинт (`/download`) — стабильный способ скачивания: он каждый раз получает актуальный адрес и добавляет авторизацию. Обращение напрямую по сохранённому `downloadUrl` может завершиться ошибкой, когда токен устареет. ## Смотрите также - [Получить файл](/docs/entities/files/get) - [Список файлов](/docs/entities/files/list) - [Файлы](/docs/entities/files) --- # Files: Fields ## Поля файла `GET /v1/files/fields` Возвращает схему доступных полей сущности: типы данных и признак доступности для записи. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/files/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/files/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/files/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data.fields).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/files/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Битрикс24 | Тип | RO | Описание | |------|----------|-----|:--:|---------| | `id` | `ID` | number | да | Идентификатор объекта | | `name` | `NAME` | string | | Имя файла или папки | | `size` | `SIZE` | number | да | Размер файла в байтах. Приходит у записей-файлов | | `folderId` | `PARENT_ID` | number | | ID родительской папки. Список папок: `GET /v1/folders` | | `storageId` | `STORAGE_ID` | number | да | ID хранилища. Список: `GET /v1/storages` | | `type` | `TYPE` | string | да | Тип объекта: `"file"` или `"folder"` | | `code` | `CODE` | string | | Символьный код объекта | | `fileId` | `FILE_ID` | number | да | Внутренний ID файла. Приходит у записей-файлов | | `downloadUrl` | `DOWNLOAD_URL` | string | да | Временная ссылка для скачивания. Приходит у записей-файлов. Для программного скачивания — `GET /v1/files/:id/download` | | `detailUrl` | `DETAIL_URL` | string | да | Ссылка на объект в интерфейсе | | `contentProvider` | `CONTENT_PROVIDER` | string | да | Провайдер контента. Возвращается только у файлов из внешних провайдеров контента — у файлов на Диске Битрикс24 не возвращается | | `globalContentVersion` | `GLOBAL_CONTENT_VERSION` | number | да | Счётчик версий файла. Приходит у записей-файлов | | `deletedType` | `DELETED_TYPE` | number | да | Статус удаления: `0` — не удалён, `3` — в корзине, `4` — удалён вместе с папкой | | `realObjectId` | `REAL_OBJECT_ID` | number | да | Внутренний ID объекта | | `createdBy` | `CREATED_BY` | number | да | ID пользователя-создателя. Поиск: `GET /v1/users` | | `updatedBy` | `UPDATED_BY` | number | да | ID автора последнего изменения. Поиск: `GET /v1/users` | | `deletedBy` | `DELETED_BY` | number | да | ID пользователя, удалившего объект. Поиск: `GET /v1/users` | | `createdAt` | `CREATE_TIME` | datetime | да | Дата и время создания (ISO 8601 UTC) | | `updatedAt` | `UPDATE_TIME` | datetime | да | Дата и время последнего изменения | | `deletedAt` | `DELETE_TIME` | datetime | да | Дата и время удаления. Значение `null` — объект не удалён | Поля `name`, `folderId` и `code` доступны при создании и обновлении объекта. Через `PATCH /v1/files/:id` обновляется только поле `name`. ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "ID", "description": "Идентификатор файла или папки на Диске." }, "name": { "type": "string", "readonly": false, "label": "Имя", "description": "Имя файла или папки." }, "size": { "type": "number", "readonly": true, "label": "Размер", "description": "Размер файла в байтах; указывается только для записей-файлов." }, "folderId": { "type": "number", "readonly": false, "label": "ID папки", "description": "Идентификатор родительской папки, в которой находится объект." }, "storageId": { "type": "number", "readonly": true, "label": "ID хранилища", "description": "Идентификатор хранилища Диска, к которому относится объект." }, "type": { "type": "string", "readonly": true, "label": "Тип объекта", "description": "Тип объекта — файл или папка." }, "code": { "type": "string", "readonly": false, "label": "Символьный код", "description": "Символьный код объекта, заданный при создании или обновлении." }, "fileId": { "type": "number", "readonly": true, "label": "ID файла", "description": "Внутренний идентификатор файла; указывается только для записей-файлов." }, "downloadUrl": { "type": "string", "readonly": true, "label": "Ссылка на скачивание", "description": "Временная ссылка для скачивания файла." }, "detailUrl": { "type": "string", "readonly": true, "label": "Ссылка на объект", "description": "Ссылка на просмотр объекта в интерфейсе Битрикс24." }, "contentProvider": { "type": "string", "readonly": true, "label": "Провайдер контента", "description": "Внешний провайдер контента; для файлов на Диске Битрикс24 не возвращается." }, "globalContentVersion": { "type": "number", "readonly": true, "label": "Версия контента", "description": "Счётчик версий содержимого файла." }, "deletedType": { "type": "number", "readonly": true, "label": "Статус удаления", "description": "Удалён ли объект и каким образом — не удалён, в корзине или удалён вместе с папкой." }, "createdBy": { "type": "number", "readonly": true, "label": "Автор создания", "description": "Идентификатор пользователя, создавшего объект." }, "updatedBy": { "type": "number", "readonly": true, "label": "Автор изменения", "description": "Идентификатор пользователя, последним изменившего объект." }, "createdAt": { "type": "datetime", "readonly": true, "label": "Дата создания", "description": "Дата и время создания объекта." }, "updatedAt": { "type": "datetime", "readonly": true, "label": "Дата изменения", "description": "Дата и время последнего изменения объекта." }, "deletedAt": { "type": "datetime", "readonly": true, "label": "Дата удаления", "description": "Дата и время удаления объекта; null, если объект не удалён." }, "realObjectId": { "type": "number", "readonly": true, "label": "Внутренний ID", "description": "Внутренний идентификатор объекта на Диске." }, "deletedBy": { "type": "number", "readonly": true, "label": "Автор удаления", "description": "Идентификатор пользователя, удалившего объект; null, если объект не удалён." } } } } ``` ## Пример ответа при ошибке 403 — нет скоупа `disk`: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'disk' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `disk` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов портала | | 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список файлов](/docs/entities/files/list) - [Получить файл](/docs/entities/files/get) - [Обновить файл](/docs/entities/files/update) - [Файлы](/docs/entities/files) - [Синтаксис фильтрации](/docs/filtering) --- # Files: Get ## Получить файл `GET /v1/files/:id` Возвращает файл по ID со всеми полями, включая ссылку для скачивания и прямой URL в интерфейсе Битрикс24. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID файла. Получить: `GET /v1/files?folderId=X` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/files/205" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/files/205" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/files/205', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Файл:', data.name, '—', data.size, 'байт') ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/files/205', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Только чтение | Описание | |------|-----|:---:|---------| | `success` | boolean | | Всегда `true` при успехе | | `data.id` | number | ✓ | Идентификатор файла | | `data.name` | string | | Имя файла | | `data.code` | string\|null | | Символьный код файла | | `data.storageId` | number | ✓ | ID хранилища. Список: `GET /v1/storages` | | `data.type` | string | ✓ | Тип объекта: всегда `"file"` | | `data.folderId` | number | | ID родительской папки. Список: `GET /v1/folders` | | `data.deletedType` | number | ✓ | Статус удаления: `0` — активен, `3` — в корзине, `4` — удалён вместе с папкой | | `data.globalContentVersion` | number | ✓ | Счётчик версий файла | | `data.fileId` | number | ✓ | Внутренний идентификатор файла в Битрикс24 | | `data.size` | number | ✓ | Размер файла в байтах | | `data.createdBy` | number | ✓ | ID пользователя-создателя. Список: `GET /v1/users` | | `data.updatedBy` | number | ✓ | ID автора последнего изменения. Список: `GET /v1/users` | | `data.deletedBy` | number\|null | ✓ | ID пользователя, удалившего файл; `null` — файл не удалён | | `data.createdAt` | datetime | ✓ | Дата и время создания (ISO 8601) | | `data.updatedAt` | datetime | ✓ | Дата и время последнего изменения (ISO 8601) | | `data.deletedAt` | datetime\|null | ✓ | Дата и время перемещения в корзину; `null` — файл не удалён | | `data.downloadUrl` | string | ✓ | Ссылка для скачивания файла | | `data.detailUrl` | string | ✓ | Ссылка на файл в интерфейсе Битрикс24 | | `data.contentProvider` | string | ✓ | Поставщик контента (может отсутствовать) | ## Пример ответа ```json { "success": true, "data": { "id": 205, "name": "project-report.pdf", "code": null, "storageId": 1, "type": "file", "folderId": 27, "deletedType": 0, "globalContentVersion": 1, "fileId": 363, "size": 31232, "createdBy": 1, "updatedBy": 1, "deletedBy": null, "createdAt": "2020-05-15T09:29:09.000Z", "updatedAt": "2020-05-15T09:29:09.000Z", "deletedAt": null, "downloadUrl": "https://example.bitrix24.ru/disk/downloadFile/363/?...", "detailUrl": "https://example.bitrix24.ru/disk/file/project-report.pdf/" } } ``` ## Пример ответа при ошибке 404 — файл не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Could not find entity with id '99999999'." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Файл с указанным ID не существует | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `disk` | | 401 | `TOKEN_MISSING` | Ключ не имеет настроенных токенов авторизации | | 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности `downloadUrl` содержит токен авторизации и действует ограниченное время. Для программного скачивания используйте `GET /v1/files/:id/download` — он возвращает перенаправление на актуальную ссылку без встроенного токена. Метод возвращает только объекты типа `"file"`. Чтобы получить данные папки, используйте `GET /v1/folders/:id`. ## Смотрите также - [Список файлов](/docs/entities/files/list) - [Переименовать файл](/docs/entities/files/update) - [Удалить файл](/docs/entities/files/delete) - [Получить папку](/docs/entities/folders) --- # Files: List ## Список файлов папки `GET /v1/files` Возвращает список объектов в указанной папке: папки и файлы вместе. ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `folderId` (query) | number | да | — | ID папки, содержимое которой нужно получить. Список папок: `GET /v1/folders` | | `limit` (query) | number | нет | `50` | Количество записей (до 5000) | | `offset` (query) | number | нет | `0` | Пропустить N записей | | `sort` (query) | string | нет | — | Поле для сортировки | | `filter` (query) | object | нет | — | Фильтрация только по полям, которые умеет фильтровать Битрикс24: `id`, `name`, `code`, `storageId`, `type`, `folderId`, `deletedType`, `createdAt`, `updatedAt`, `deletedAt`. Остальные поля из `GET /v1/files/fields` (например `createdBy`, `size`, `updatedBy`) фильтровать нельзя — такой запрос вернёт `400 UNSUPPORTED_FILTER` со списком допустимых. Операторы (`$gt`, `$contains` и прочие) не поддерживаются: только точное совпадение и `$in`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[type]=file` | **Пагинация.** При `limit > 50` Вайбкод автоматически выполняет несколько запросов к Битрикс24 и возвращает все записи в одном ответе. Максимум — 5000 записей за вызов. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/files?folderId=27&limit=10" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/files?folderId=27&limit=10" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/files?folderId=27&limit=10', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Объектов в папке: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/files?folderId=27&limit=10', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив объектов папки (папки и файлы). Полный список полей элемента — ниже | | `data[].id` | number | Идентификатор объекта | | `data[].name` | string | Имя объекта | | `data[].code` | string\|null | Символьный код; `null`, если не задан | | `data[].storageId` | number | ID хранилища. Список хранилищ: `GET /v1/storages` | | `data[].type` | string | Тип: `"file"` или `"folder"` | | `data[].folderId` | number | ID родительской папки | | `data[].deletedType` | number | Статус удаления: `0` — активен, `3` — в корзине, `4` — удалён вместе с папкой | | `data[].realObjectId` | number | Внутренний ID объекта. Присутствует только у папок | | `data[].createdBy` | number | ID создателя. Список пользователей: `GET /v1/users` | | `data[].updatedBy` | number | ID автора последнего изменения. Список пользователей: `GET /v1/users` | | `data[].deletedBy` | number\|null | ID пользователя, удалившего объект; `null` — не удалён | | `data[].createdAt` | datetime | Дата создания (ISO 8601) | | `data[].updatedAt` | datetime | Дата последнего изменения (ISO 8601) | | `data[].deletedAt` | datetime\|null | Дата удаления (ISO 8601); `null` — не удалён | | `data[].detailUrl` | string | Ссылка на объект в интерфейсе Битрикс24 | | `data[].size` | number | Размер файла в байтах. Приходит у записей-файлов | | `data[].fileId` | number | Внутренний ID файла. Приходит у записей-файлов | | `data[].globalContentVersion` | number | Счётчик версий файла. Приходит у записей-файлов | | `data[].downloadUrl` | string | Временная ссылка для скачивания. Приходит у записей-файлов. Для программного скачивания — [`GET /v1/files/:id/download`](./download.md) | | `data[].contentProvider` | string | Провайдер контента. Возвращается только у файлов из внешних провайдеров контента — у файлов на Диске Битрикс24 не возвращается | | `meta.total` | number | Общее количество объектов в папке | | `meta.hasMore` | boolean | Есть ли ещё объекты за пределами `limit` | ## Пример ответа ```json { "success": true, "data": [ { "id": 1275, "name": "Архив проекта", "code": "ARCHIVE_PROJECT", "storageId": 1, "type": "folder", "folderId": 27, "deletedType": 0, "realObjectId": 1275, "createdBy": 5, "updatedBy": 5, "deletedBy": null, "createdAt": "2023-04-12T08:30:00.000Z", "updatedAt": "2023-04-12T08:30:01.000Z", "deletedAt": null, "detailUrl": "https://example.bitrix24.ru/docs/path/to/folder/" }, { "id": 205, "name": "presentation_q1.pdf", "code": null, "storageId": 1, "type": "file", "folderId": 27, "size": 31232, "fileId": 363, "globalContentVersion": 1, "downloadUrl": "https://example.bitrix24.ru/rest/1/XXXXXX/download/?token=PLACEHOLDER", "deletedType": 0, "createdBy": 5, "updatedBy": 5, "deletedBy": null, "createdAt": "2023-03-15T09:29:09.000Z", "updatedAt": "2023-03-15T09:29:09.000Z", "deletedAt": null, "detailUrl": "https://example.bitrix24.ru/docs/path/to/file/" } ], "meta": { "total": 40, "hasMore": true } } ``` ## Пример ответа при ошибке 400 — не передан `folderId`: ```json { "success": false, "error": { "code": "MISSING_REQUIRED_PARAMS", "message": "GET /v1/files requires query parameters: folderId. Example: GET /v1/files?folderId=..." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_PARAMS` | Не передан обязательный параметр `folderId` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `disk` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов портала | | 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Смешанный список.** Ответ содержит одновременно папки (`type: "folder"`) и файлы (`type: "file"`). Разграничить объекты можно по полю `type`. Поля `size`, `fileId`, `globalContentVersion` и `downloadUrl` приходят у записей-файлов. Поле `contentProvider` у файлов на Диске Битрикс24 не возвращается, поле `realObjectId` — только у папок. ## Смотрите также - [Файлы — обзор](/docs/entities/files) - [Папки](/docs/entities/folders) - [Хранилища](/docs/entities/storages) - [Синтаксис фильтрации](/docs/filtering) - [Entity API](/docs/entity-api) --- # Files: Moveto ## Переместить файл `POST /v1/files/:id/moveto` Перемещает файл в другую папку того же хранилища. После успеха поле `folderId` в ответе содержит ID целевой папки; `id`, `createdAt` и `createdBy` у файла не изменяются. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | number | да | ID файла. Получить через `GET /v1/files` | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|----------| | `targetFolderId` | number | да | ID папки-назначения. Получить через `GET /v1/folders` | ## Примеры ### curl — личный ключ ```bash curl -X POST \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"targetFolderId":649}' \ https://vibecode.bitrix24.tech/v1/files/9251/moveto ``` ### curl — OAuth-приложение ```bash curl -X POST \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"targetFolderId":649}' \ https://vibecode.bitrix24.tech/v1/files/9251/moveto ``` ### JavaScript — личный ключ ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/files/9251/moveto', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ targetFolderId: 649 }), } ) const body = await res.json() if (!body.success) throw new Error(body.error.code) console.log('Файл перемещён, новая папка:', body.data.folderId) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/files/9251/moveto', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ targetFolderId: 649 }), } ) const body = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | `true` при успешном перемещении | | `data.id` | number | ID файла (не изменяется после перемещения) | | `data.name` | string | Имя файла | | `data.code` | string \| null | Символьный код файла | | `data.folderId` | number | ID папки-назначения — равен переданному `targetFolderId` | | `data.storageId` | number | ID хранилища | | `data.type` | string | Тип объекта — всегда `"file"` | | `data.deletedType` | number | Статус удаления: `0` — активен | | `data.globalContentVersion` | number | Счётчик версий файла | | `data.fileId` | number | Внутренний ID файла в Битрикс24 | | `data.size` | number | Размер файла в байтах | | `data.createdBy` | number | ID пользователя, создавшего файл | | `data.updatedBy` | number | ID пользователя, выполнившего перемещение | | `data.deletedBy` | number \| null | ID пользователя, удалившего файл; `null` — не удалён | | `data.createdAt` | string | Дата создания файла (ISO 8601) — не изменяется | | `data.updatedAt` | string | Дата последнего изменения (ISO 8601) | | `data.deletedAt` | string \| null | Дата удаления или `null` | | `data.downloadUrl` | string | URL для скачивания файла | | `data.detailUrl` | string | URL карточки файла в Битрикс24 | ## Пример ответа ```json { "success": true, "data": { "id": 9251, "name": "verify-move-test.txt", "code": null, "storageId": 1, "type": "file", "folderId": 649, "deletedType": 0, "globalContentVersion": 1, "fileId": 34867, "size": 11, "createdBy": 1, "updatedBy": 1, "deletedBy": null, "createdAt": "2026-05-06T09:32:39.000Z", "updatedAt": "2026-05-06T09:34:16.000Z", "deletedAt": null, "downloadUrl": "https://example.bitrix24.ru/disk/downloadFile/34867/?...", "detailUrl": "https://example.bitrix24.ru/company/personal/user/1/disk/file/verify-move-test.txt/" } } ``` ## Пример ответа при ошибке 422 — в целевой папке уже существует файл с таким именем: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Файл с таким именем уже есть (DISK_OBJ_22000)." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `MISSING_PARAMS` | Не передан `targetFolderId` | | 400 | `INVALID_PARAMS` | `targetFolderId` не является положительным целым числом | | 400 | `INVALID_ID` | `id` файла не является положительным целым числом | | 400 | `OPERATION_FAILED` | Перемещение между разными хранилищами не поддерживается — используйте `POST /v1/files/:id/copyto` | | 401 | `TOKEN_MISSING` | Для портала нет токенов авторизации | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `disk` | | 404 | `ENTITY_NOT_FOUND` | Файл с указанным `id` не найден | | 422 | `BITRIX_ERROR` | В целевой папке уже есть файл с таким именем — переименуйте файл через `PATCH /v1/files/:id` перед перемещением | | 429 | `RATE_LIMITED` | Превышен лимит запросов — подождите 1-2 секунды и повторите | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Постоянство идентификатора.** После перемещения `id`, `createdAt` и `createdBy` файла не изменяются — все внешние ссылки на файл по ID остаются рабочими. ## Смотрите также - [Скопировать файл](./copyto.md) - [Получить файл](./get.md) - [Список файлов](/docs/entities/files) - [Список папок](/docs/entities/folders) --- # Files: Search ## Поиск файлов `POST /v1/files/search` Возвращает содержимое папки — то же, что [`GET /v1/files`](./list.md), только условия передаются в теле запроса, а не в строке. Фильтр обязан содержать `folderId`. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `filter` | object | да | Условия отбора. Должен содержать `folderId` — ID папки, содержимое которой возвращается.
[Синтаксис фильтрации](/docs/filtering). Пример: `{"folderId":27,"type":"file"}` | | `select` | array | нет | Список возвращаемых полей. Пример: `["id","name"]` | | `order` | object | нет | Сортировка по полю. Пример: `{"name":"asc"}` | | `limit` | number | нет | Сколько записей вернуть. По умолчанию 50, максимум 5000 | | `offset` | number | нет | Смещение для постраничной выборки | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/files/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"filter":{"folderId":27,"type":"file"},"limit":10}' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/files/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"filter":{"folderId":27,"type":"file"},"limit":10}' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/files/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { folderId: 27, type: 'file' }, limit: 10 }), }) const { success, data, meta } = await res.json() console.log('Найдено:', data.length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/files/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { folderId: 27, type: 'file' }, limit: 10 }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив записей — подпапки и файлы. Все поля — см. [Поля файла](./fields.md) | | `data[].type` | string | Тип записи: `"folder"` или `"file"` | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа ```json { "success": true, "data": [ { "id": 205, "name": "presentation_q1.pdf", "code": null, "storageId": 1, "type": "file", "folderId": 27, "size": 31232, "fileId": 363, "globalContentVersion": 1, "downloadUrl": "https://example.bitrix24.ru/rest/1/XXXXXX/download/?token=PLACEHOLDER", "deletedType": 0, "createdBy": 5, "updatedBy": 5, "deletedBy": null, "createdAt": "2023-03-15T09:29:09.000Z", "updatedAt": "2023-03-15T09:29:09.000Z", "deletedAt": null, "detailUrl": "https://example.bitrix24.ru/docs/path/to/file/" } ], "meta": { "total": 1, "hasMore": false, "durationMs": 206 } } ``` ## Пример ответа при ошибке 403 — нет скоупа `disk`: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'disk' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_PARAMS` | Фильтр не содержит обязательный `folderId`. `message` перечисляет недостающие поля | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `disk` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов портала | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности Поиск ограничен одной папкой, заданной в `folderId`, и не охватывает всё хранилище. Тот же результат даёт [`GET /v1/files`](./list.md) с параметрами в строке запроса. Ответ содержит одновременно папки (`type: "folder"`) и файлы (`type: "file"`) — различать их можно по полю `type`. У папок поле `realObjectId` присутствует, у файлов — нет. Поле `contentProvider` у файлов на Диске Битрикс24 не возвращается. ## Смотрите также - [Список файлов папки](/docs/entities/files/list) - [Поля файла](/docs/entities/files/fields) - [Файлы](/docs/entities/files) - [Синтаксис фильтрации](/docs/filtering) --- # Files: Update ## Переименовать файл `PATCH /v1/files/:id` Переименовывает файл на диске. Принимает только поле `name` — остальные поля файла остаются без изменений, расположение файла не меняется. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `name` | string | ✓ | Новое имя файла с расширением | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/files/9251" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "doc-renamed.txt" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/files/9251" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "doc-renamed.txt" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/files/9251', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'doc-renamed.txt', }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/files/9251', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'doc-renamed.txt', }), }) const { success, data } = await res.json() ``` ## Поля ответа Возвращается полный объект файла с обновлённым именем. Набор полей совпадает с ответом `GET /v1/files/:id`. | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Идентификатор файла | | `data.name` | string | Новое имя файла | | `data.code` | string\|null | Символьный код файла | | `data.storageId` | number | ID хранилища | | `data.type` | string | Тип объекта — всегда `"file"` | | `data.folderId` | number | ID родительской папки | | `data.deletedType` | number | Статус удаления: `0` — активен | | `data.globalContentVersion` | number | Счётчик версий файла | | `data.fileId` | number | Внутренний ID файла в Битрикс24 | | `data.size` | number | Размер файла в байтах | | `data.createdBy` | number | ID пользователя-создателя | | `data.updatedBy` | number | ID пользователя, выполнившего переименование | | `data.deletedBy` | number\|null | ID пользователя, удалившего файл; `null` — не удалён | | `data.createdAt` | string | Дата и время создания (ISO 8601) | | `data.updatedAt` | string | Дата и время переименования (ISO 8601) | | `data.deletedAt` | string\|null | Дата удаления; `null` — файл не удалён | | `data.contentProvider` | string | Поставщик контента (может отсутствовать) | | `data.realObjectId` | number | Внутренний ID объекта | | `data.downloadUrl` | string | Ссылка для скачивания файла | | `data.detailUrl` | string | Ссылка на файл в интерфейсе Битрикс24 | ## Пример ответа ```json { "success": true, "data": { "id": 9251, "name": "doc-renamed.txt", "code": null, "storageId": 1, "type": "file", "folderId": 27, "deletedType": 0, "globalContentVersion": 1, "fileId": 34867, "size": 11, "createdBy": 1, "updatedBy": 1, "deletedBy": null, "createdAt": "2026-05-06T09:32:39.000Z", "updatedAt": "2026-05-26T07:08:50.000Z", "deletedAt": null, "downloadUrl": "https://example.bitrix24.ru/disk/downloadFile/34867/?...", "detailUrl": "https://example.bitrix24.ru/company/personal/user/1/disk/file/doc-renamed.txt/" } } ``` ## Пример ответа при ошибке 404 — файл не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "diskFile 9251 not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Файл с указанным `id` не существует | | 400 | `MISSING_FIELDS` | Тело запроса не содержит поля `name` | | 403 | `SCOPE_DENIED` | Ключ не имеет скоупа `disk` | | 401 | `TOKEN_MISSING` | Ключ не имеет настроенных токенов авторизации | | 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить файл](/docs/entities/files/get) - [Поля файла](/docs/entities/files/fields) - [Переместить файл](/docs/entities/files/moveto) - [Удалить файл](/docs/entities/files/delete) - [Файлы](/docs/entities/files) --- # Files: Upload ## Загрузить файл `POST /v1/files/upload` Загружает файл на Диск Битрикс24. Содержимое передаётся в кодировке Base64 в теле JSON-запроса. Для загрузки необходимо указать папку (`folderId`) или хранилище (`storageId`). ## Поля запроса | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `filename` | string | да | Имя файла с расширением, например `report.pdf` | | `content` | string | да | Содержимое файла в кодировке Base64 | | `folderId` | number | условно | ID папки-назначения. Список папок: `GET /v1/folders`. Обязателен, если не указан `storageId` | | `storageId` | number | условно | ID хранилища (загрузка в корень). Список хранилищ: `GET /v1/storages`. Обязателен, если не указан `folderId` | Необходимо указать один из двух параметров: `folderId` или `storageId`. ## Примеры ### curl — личный ключ ```bash curl -X POST \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"folderId":27,"filename":"report.txt","content":"SGVsbG8gV29ybGQ="}' \ https://vibecode.bitrix24.tech/v1/files/upload ``` ### curl — OAuth-приложение ```bash curl -X POST \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"folderId":27,"filename":"report.txt","content":"SGVsbG8gV29ybGQ="}' \ https://vibecode.bitrix24.tech/v1/files/upload ``` ### JavaScript — личный ключ ```javascript const content = Buffer.from('Hello World').toString('base64') const res = await fetch('https://vibecode.bitrix24.tech/v1/files/upload', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ folderId: 27, filename: 'report.txt', content, }), }) const body = await res.json() console.log(body.data.id, body.data.downloadUrl) ``` ### JavaScript — OAuth-приложение ```javascript const content = Buffer.from('Hello World').toString('base64') const res = await fetch('https://vibecode.bitrix24.tech/v1/files/upload', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ folderId: 27, filename: 'report.txt', content, }), }) const body = await res.json() console.log(body.data.id, body.data.downloadUrl) ``` ### Загрузка в корень хранилища Если нужно загрузить файл в корень хранилища, а не в папку, передайте `storageId` вместо `folderId`. ID хранилища доступен в поле `id` из `GET /v1/storages`, корневая папка — в поле `rootFolderId`. ```bash curl -X POST \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"storageId":1,"filename":"backup.txt","content":"SGVsbG8gV29ybGQ="}' \ https://vibecode.bitrix24.tech/v1/files/upload ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | ID созданного файла | | `data.name` | string | Имя файла | | `data.code` | string \| null | Символьный код файла | | `data.storageId` | number | ID хранилища, в котором находится файл | | `data.type` | string | Тип объекта — всегда `"file"` | | `data.folderId` | number | ID папки, в которой находится файл | | `data.deletedType` | number | Тип удаления: `0` — не удалён | | `data.globalContentVersion` | number | Версия содержимого файла | | `data.fileId` | number | ID файла во внутреннем хранилище Битрикс24 | | `data.size` | number | Размер файла в байтах | | `data.createdBy` | number | ID пользователя, создавшего файл. Список: `GET /v1/users` | | `data.updatedBy` | number | ID пользователя, изменившего файл последним | | `data.deletedBy` | number \| null | ID удалившего файл или `null`, если файл не удалён | | `data.createdAt` | string | Дата и время создания (ISO 8601) | | `data.updatedAt` | string | Дата и время последнего изменения (ISO 8601) | | `data.deletedAt` | string \| null | Дата и время удаления или `null`, если файл не удалён | | `data.downloadUrl` | string | URL для скачивания файла | | `data.detailUrl` | string | URL карточки файла в Битрикс24 | ## Пример ответа При успешной загрузке возвращается HTTP-статус `201 Created`. ```json { "success": true, "data": { "id": 9251, "name": "report.txt", "code": null, "storageId": 1, "type": "file", "folderId": 27, "deletedType": 0, "globalContentVersion": 1, "fileId": 34867, "size": 11, "createdBy": 1, "updatedBy": 1, "deletedBy": null, "createdAt": "2026-05-06T09:32:39.000Z", "updatedAt": "2026-05-06T09:32:39.000Z", "deletedAt": null, "downloadUrl": "https://example.bitrix24.ru/disk/downloadFile/...", "detailUrl": "https://example.bitrix24.ru/company/personal/user/1/disk/file/report.txt" } } ``` ## Пример ответа при ошибке 400 — не указаны `filename` и `content`: ```json { "success": false, "error": { "code": "MISSING_PARAMS", "message": "filename and content (base64) are required." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_PARAMS` | Не переданы `filename` и `content`, либо не указан ни `folderId`, ни `storageId` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ | | 401 | `TOKEN_MISSING` | Токены доступа к порталу Битрикс24 недоступны | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `disk` | | 404 | `ENTITY_NOT_FOUND` | Папка или хранилище с указанным ID не найдены | | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку при загрузке файла | | 429 | `RATE_LIMITED` | Превышен лимит запросов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Содержимое передаётся в Base64.** Файл кодируется в Base64 и передаётся как строка в поле `content`. Передача файла через `multipart/form-data` не поддерживается. **Максимальный размер.** Лимит тела запроса для этого маршрута — 70 МБ. С учётом того, что base64 увеличивает размер примерно на треть, это соответствует исходному файлу около 50 МБ — запись звонка, типовые вложения. Битрикс24 дополнительно применяет собственное ограничение на размер файла Диска: при его превышении возвращается `422 BITRIX_ERROR`. Файлы в сотни МБ загружать через этот эндпоинт не предназначено. ## Смотрите также - [Файлы](/docs/entities/files) - [Папки](/docs/entities/folders) - [Хранилища](/docs/entities/storages) - [Удалить файл](/docs/entities/files/delete) --- # Folders: Copyto ## Скопировать папку `POST /v1/folders/:id/copyto` Копирует папку со всем содержимым в другую родительскую папку. Возвращает **новую** папку с новым `id`. Исходная папка не изменяется. Копирование работает в том числе между разными хранилищами. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | number | да | ID исходной папки. Получить через `GET /v1/folders` | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|----------| | `targetFolderId` | number | да | ID папки-назначения. Получить через `GET /v1/folders` | ## Примеры ### curl — личный ключ ```bash curl -X POST \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"targetFolderId":649}' \ https://vibecode.bitrix24.tech/v1/folders/9297/copyto ``` ### curl — OAuth-приложение ```bash curl -X POST \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"targetFolderId":649}' \ https://vibecode.bitrix24.tech/v1/folders/9297/copyto ``` ### JavaScript — личный ключ ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/folders/9297/copyto', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ targetFolderId: 649 }), } ) const body = await res.json() if (!body.success) throw new Error(body.error.code) console.log('Создана копия, новый id:', body.data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/folders/9297/copyto', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ targetFolderId: 649 }), } ) const body = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | `true` при успешном копировании | | `data.id` | number | ID **новой** папки-копии — отличается от исходной | | `data.name` | string | Имя папки-копии | | `data.code` | string \| null | Символьный код папки | | `data.parentId` | number | ID родительской папки — равен переданному `targetFolderId` | | `data.storageId` | number | ID хранилища | | `data.type` | string | Тип объекта — всегда `"folder"` | | `data.realObjectId` | number | Внутренний ID объекта | | `data.deletedType` | number | Статус удаления: `0` — активна | | `data.createdBy` | number | ID пользователя, создавшего копию | | `data.updatedBy` | number | ID пользователя, выполнившего копирование | | `data.deletedBy` | number | ID пользователя, удалившего папку. `null` — не удалена | | `data.createdAt` | string | Дата создания копии (ISO 8601) | | `data.updatedAt` | string | Дата последнего изменения (ISO 8601) | | `data.deletedAt` | string \| null | Дата удаления или `null` | | `data.detailUrl` | string | URL карточки папки-копии в Битрикс24 | ## Пример ответа ```json { "success": true, "data": { "id": 9301, "name": "Документы", "code": null, "storageId": 1, "type": "folder", "realObjectId": 9301, "parentId": 649, "deletedType": 0, "createdAt": "2026-06-25T12:50:10.000Z", "updatedAt": "2026-06-25T12:50:10.000Z", "deletedAt": null, "createdBy": 1, "updatedBy": 1, "deletedBy": null, "detailUrl": "https://.bitrix24.ru/company/personal/user/1/disk/path/Архив/Документы" } } ``` ## Пример ответа при ошибке 422 — в целевой папке уже есть папка с таким именем: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Папка с таким именем уже есть (DISK_OBJ_22000)." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `MISSING_PARAMS` | Не передан `targetFolderId` | | 400 | `INVALID_PARAMS` | `targetFolderId` не является положительным целым числом | | 400 | `INVALID_ID` | `id` папки не является положительным целым числом | | 400 | `OPERATION_FAILED` | Битрикс24 вернул пустой результат — копирование не выполнено | | 401 | `TOKEN_MISSING` | Для портала нет токенов авторизации | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `disk` | | 404 | `ENTITY_NOT_FOUND` | Папка с указанным `id` не найдена | | 422 | `BITRIX_ERROR` | В целевой папке уже есть папка с таким именем — переименуйте через `PATCH /v1/folders/:id` перед копированием | | 429 | `RATE_LIMITED` | Превышен лимит запросов — подождите 1-2 секунды и повторите | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Копия — независимая папка.** У копии собственный `id`, `createdAt` и `createdBy`. Исходная папка остаётся на месте. Копируется вся вложенная структура. Чтобы перенести папку без дубликата в пределах одного хранилища, используйте [`moveto`](./moveto.md). ## Смотрите также - [Переместить папку](./moveto.md) - [Получить папку](./get.md) - [Список содержимого папки](./list.md) - [Файлы](/docs/entities/files) --- # Folders: Create ## Создать папку `POST /v1/folders` Создаёт новую папку внутри указанной родительской папки. Тело передаётся плоско, без обёртки `fields`. ## Поля запроса (body) | Поле | Битрикс24 | Тип | Обяз. | Описание | |------|----------|-----|:-----:|---------| | `name` | `NAME` | string | да | Имя новой папки | | `parentId` | `PARENT_ID` | number | да | ID родительской папки. Корневая папка хранилища — `rootFolderId` из `GET /v1/storages` | Поле `code` доступно только для чтения — при создании не сохраняется, его передача возвращает `400 READONLY_FIELD`. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/folders" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name":"Документы","parentId":27}' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/folders" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"Документы","parentId":27}' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/folders', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Документы', parentId: 27 }), }) const { success, data } = await res.json() console.log('Создана папка:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/folders', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Документы', parentId: 27 }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект созданной папки. Все поля — см. [Поля папки](./fields.md) | URL карточки папки в Битрикс24 строится из `id`: `https://.bitrix24.ru/company/personal/user/1/disk/path/<имя>/`. `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": { "id": 9301, "name": "Документы", "code": null, "storageId": 1, "type": "folder", "realObjectId": 9301, "parentId": 27, "deletedType": 0, "createdAt": "2026-06-25T12:10:00.000Z", "updatedAt": "2026-06-25T12:10:00.000Z", "deletedAt": null, "createdBy": 1, "updatedBy": 1, "deletedBy": null, "detailUrl": "https://.bitrix24.ru/company/personal/user/1/disk/path/Загруженные файлы/Документы" } } ``` ## Пример ответа при ошибке 400 — не передано обязательное поле `name`: ```json { "success": false, "error": { "code": "MISSING_REQUIRED_FIELDS", "message": "Body field \"name\" is required to create diskFolder." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_FIELDS` | Не передано поле `name` | | 400 | `MISSING_PARENT_ID` | Не передано поле `parentId` | | 400 | `READONLY_FIELD` | В теле передано поле только для чтения, например `code` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `disk` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов портала | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список содержимого папки](/docs/entities/folders/list) - [Получить папку](/docs/entities/folders/get) - [Переименовать папку](/docs/entities/folders/update) - [Поля папки](/docs/entities/folders/fields) - [Хранилища](/docs/entities/storages) --- # Folders: Delete ## Удалить папку `DELETE /v1/folders/:id` Удаляет папку. Удаление мягкое — папка переносится в корзину Битрикс24 вместе со всем содержимым. Восстановить удалённую папку через API нельзя. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|----------| | `id` (path) | number | да | ID папки. Список: `GET /v1/folders` | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/folders/9301" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/folders/9301" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/folders/9301', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Папка удалена') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/folders/9301', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Папка удалена') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом. Признак успеха — код ответа, не содержимое. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — папка не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Could not find entity with id '999999'." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Папки с указанным `id` нет | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `disk` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов портала | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности Удаление помечает папку как удалённую и переносит её в корзину, не стирая физически. Сразу после удаления запись ещё доступна через `GET /v1/folders/:id` с полем `deletedType` равным `3` — в корзине. Удалённая папка остаётся в Битрикс24 до окончательной очистки. ## Смотрите также - [Создать папку](/docs/entities/folders/create) - [Получить папку](/docs/entities/folders/get) - [Переименовать папку](/docs/entities/folders/update) - [Папки](/docs/entities/folders) --- # Folders: Fields ## Поля папки `GET /v1/folders/fields` Возвращает схему доступных полей сущности: типы данных и признак доступности для записи. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/folders/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/folders/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/folders/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data.fields).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/folders/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Битрикс24 | Тип | RO | Описание | |------|----------|-----|:--:|---------| | `id` | `ID` | number | да | Идентификатор папки | | `name` | `NAME` | string | | Имя папки. Обязательно при создании | | `parentId` | `PARENT_ID` | number | | ID родительской папки. Доступно только при создании, изменить нельзя. Список: `GET /v1/folders`, корневая папка: `GET /v1/storages` | | `storageId` | `STORAGE_ID` | number | да | ID хранилища. Список: `GET /v1/storages` | | `code` | `CODE` | string | да | Символьный код. При создании и переименовании не сохраняется | | `type` | `TYPE` | string | да | Тип объекта: `"folder"` или `"file"` | | `realObjectId` | `REAL_OBJECT_ID` | number | да | Внутренний ID объекта | | `detailUrl` | `DETAIL_URL` | string | да | Ссылка на папку в интерфейсе Битрикс24 | | `deletedType` | `DELETED_TYPE` | number | да | Статус удаления: `0` — не удалена, `3` — в корзине, `4` — удалена вместе с родительской папкой | | `createdBy` | `CREATED_BY` | number | да | ID пользователя-создателя. Поиск: `GET /v1/users` | | `updatedBy` | `UPDATED_BY` | number | да | ID автора последнего изменения. Поиск: `GET /v1/users` | | `deletedBy` | `DELETED_BY` | number | да | ID пользователя, удалившего папку. Поиск: `GET /v1/users` | | `createdAt` | `CREATE_TIME` | datetime | да | Дата и время создания (ISO 8601 UTC) | | `updatedAt` | `UPDATE_TIME` | datetime | да | Дата и время последнего изменения | | `deletedAt` | `DELETE_TIME` | datetime | да | Дата и время удаления. `null` — папка не удалена | Поле `name` доступно при создании и переименовании, `parentId` — только при создании. Через `PATCH /v1/folders/:id` обновляется только поле `name`. ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "ID", "description": "Уникальный идентификатор папки." }, "name": { "type": "string", "readonly": false, "label": "Название", "description": "Имя папки; обязательно при создании и единственное поле, доступное при переименовании." }, "parentId": { "type": "number", "readonly": false, "createOnly": true, "label": "Родительская папка", "description": "ID родительской папки; задаётся только при создании и не может быть изменён впоследствии." }, "storageId": { "type": "number", "readonly": true, "label": "Хранилище", "description": "ID хранилища Диска, которому принадлежит папка." }, "code": { "type": "string", "readonly": true, "label": "Символьный код", "description": "Символьный код папки; не сохраняется при создании или переименовании." }, "type": { "type": "string", "readonly": true, "label": "Тип объекта", "description": "Тип объекта Диска — папка или файл." }, "realObjectId": { "type": "number", "readonly": true, "label": "Внутренний ID", "description": "Внутренний идентификатор объекта в системе хранения Диска." }, "detailUrl": { "type": "string", "readonly": true, "label": "Ссылка на папку", "description": "URL-адрес папки в веб-интерфейсе Битрикс24." }, "deletedType": { "type": "number", "readonly": true, "label": "Статус удаления", "description": "Статус удаления: 0 — не удалена, 3 — в корзине, 4 — удалена вместе с родительской папкой." }, "createdBy": { "type": "number", "readonly": true, "label": "Создатель", "description": "ID пользователя, создавшего папку." }, "updatedBy": { "type": "number", "readonly": true, "label": "Автор изменения", "description": "ID пользователя, внёсшего последнее изменение." }, "deletedBy": { "type": "number", "readonly": true, "label": "Кто удалил", "description": "ID пользователя, удалившего папку; null, если папка не удалена." }, "createdAt": { "type": "datetime", "readonly": true, "label": "Дата создания", "description": "Дата и время создания папки." }, "updatedAt": { "type": "datetime", "readonly": true, "label": "Дата изменения", "description": "Дата и время последнего изменения папки." }, "deletedAt": { "type": "datetime", "readonly": true, "label": "Дата удаления", "description": "Дата и время удаления папки; null, если папка не удалена." } }, "relations": { "storage": { "type": "one", "entity": "storages", "includable": true } } } } ``` ## Пример ответа при ошибке 403 — нет скоупа `disk`: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'disk' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `disk` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов портала | | 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список содержимого папки](/docs/entities/folders/list) - [Создать папку](/docs/entities/folders/create) - [Папки](/docs/entities/folders) - [Файлы](/docs/entities/files) - [Синтаксис фильтрации](/docs/filtering) --- # Folders: Get ## Получить папку `GET /v1/folders/:id` Возвращает одну папку по её идентификатору. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|----------| | `id` (path) | number | да | ID папки. Список: `GET /v1/folders` | | `include` (query) | string | нет | Подгрузить связанный объект. Доступное значение — `storage`. Результат приходит в блоке `_included` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/folders/27" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/folders/27" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/folders/27', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log(data.name) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/folders/27', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект папки. Все поля — см. [Поля папки](./fields.md) | `GET /v1/folders/:id` адресует только папки. Идентификатор файла возвращает `404 ENTITY_NOT_FOUND` — карточка файла доступна через [`GET /v1/files/:id`](/docs/entities/files/get). ## Пример ответа ```json { "success": true, "data": { "id": 27, "name": "Загруженные файлы", "code": "FOR_UPLOADED_FILES", "storageId": 1, "type": "folder", "realObjectId": 27, "parentId": 1, "deletedType": 0, "createdAt": "2020-04-21T16:09:38.000Z", "updatedAt": "2026-06-09T12:29:04.000Z", "deletedAt": null, "createdBy": 1, "updatedBy": 1, "deletedBy": null, "detailUrl": "https://.bitrix24.ru/company/personal/user/1/disk/path/Загруженные файлы" } } ``` С параметром `include=storage` добавляется блок `_included`. Показаны основные поля папки: ```json { "success": true, "data": { "id": 27, "name": "Загруженные файлы", "storageId": 1, "type": "folder", "parentId": 1, "_included": { "storage": { "id": 1, "name": "Летта", "code": null, "module": "disk", "entityType": "user", "entityId": "1", "rootFolderId": 1 } } } } ``` ## Пример ответа при ошибке 404 — папка не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Could not find entity with id '999999'." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_INCLUDE` | Значение `include` не поддерживается. Доступное значение — `storage` | | 404 | `ENTITY_NOT_FOUND` | Папки с указанным `id` нет, либо `id` принадлежит файлу | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `disk` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов портала | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список содержимого папки](/docs/entities/folders/list) - [Переименовать папку](/docs/entities/folders/update) - [Удалить папку](/docs/entities/folders/delete) - [Поля папки](/docs/entities/folders/fields) - [Файлы](/docs/entities/files) --- # Folders: List ## Список содержимого папки `GET /v1/folders` Возвращает содержимое папки — вложенные подпапки и файлы. Параметр `parentId` обязателен — без него запрос возвращается с `400`. ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|----------| | `parentId` (query) | number | да | | ID папки, чьё содержимое перечисляется. Корневая папка хранилища — поле `rootFolderId` в `GET /v1/storages` | | `filter` (query) | object | нет | | Фильтрация только по полям, которые умеет фильтровать Битрикс24: `id`, `name`, `code`, `storageId`, `type`, `parentId`, `deletedType`, `createdAt`, `updatedAt`, `deletedAt`. Остальные поля из `GET /v1/folders/fields` (например `createdBy`, `updatedBy`) фильтровать нельзя — такой запрос вернёт `400 UNSUPPORTED_FILTER` со списком допустимых. Операторы (`$gt`, `$contains` и прочие) не поддерживаются: только точное совпадение и `$in`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[type]=folder` | | `select` (query) | string | нет | все поля | Список возвращаемых полей через запятую. Пример: `?select=id,name` | | `order` (query) | object | нет | | Сортировка по полю. Пример: `?order[name]=asc` | | `limit` (query) | number | нет | 50 | Сколько записей вернуть. Максимум 5000 | | `offset` (query) | number | нет | 0 | Смещение для постраничной выборки | | `include` (query) | string | нет | | Подгрузить связанный объект к каждой записи. Доступное значение — `storage`. Результат приходит в блоке `_included`. Для выборки более 200 записей связи не подгружаются, в `meta.includeSkipped` придёт `true` | Для `limit > 50` Вайбкод автоматически пагинирует запрос на стороне сервера. Максимум — 5000 записей за вызов. Если под фильтр попадает больше, в `meta.hasMore` придёт `true`. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/folders?parentId=27&limit=10" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/folders?parentId=27&limit=10" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const params = new URLSearchParams({ parentId: '27', limit: '10' }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/folders?${params}`, { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log('Записей:', data.length, 'всего:', meta.total) ``` ### JavaScript — OAuth-приложение ```javascript const params = new URLSearchParams({ parentId: '27', limit: '10' }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/folders?${params}`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив записей — подпапки (`type: "folder"`) и файлы (`type: "file"`). Все поля — см. [Поля папки](./fields.md) | | `data[].type` | string | Тип записи: `"folder"` или `"file"`. Различает две схемы строк в одном массиве | | `meta.total` | number | Общее количество записей в папке | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | Записи-файлы несут собственный набор полей — `fileId`, `size`, `globalContentVersion`, `downloadUrl`, `folderId` — и не содержат `realObjectId`. Управление файлами — в разделе [Файлы](/docs/entities/files). Поле `detailUrl` — полный URL карточки папки в Битрикс24, например `https://.bitrix24.ru/company/personal/user/1/disk/path/<имя>/`. `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 9301, "name": "Документы", "code": null, "storageId": 1, "type": "folder", "realObjectId": 9301, "parentId": 27, "deletedType": 0, "createdAt": "2026-06-25T12:10:00.000Z", "updatedAt": "2026-06-25T12:10:00.000Z", "deletedAt": null, "createdBy": 1, "updatedBy": 1, "deletedBy": null, "detailUrl": "https://.bitrix24.ru/company/personal/user/1/disk/path/Документы" }, { "id": 205, "name": "отчёт.pdf", "code": null, "storageId": 1, "type": "file", "folderId": 27, "deletedType": 0, "globalContentVersion": 1, "fileId": 363, "size": 31232, "createdAt": "2020-05-15T09:29:09.000Z", "updatedAt": "2020-05-15T09:29:09.000Z", "deletedAt": null, "createdBy": 1, "updatedBy": 1, "deletedBy": null, "downloadUrl": "https://.bitrix24.ru/rest/1/****/download/?token=****" } ], "meta": { "total": 22, "hasMore": false } } ``` С параметром `include=storage` к каждой записи добавляется блок `_included`. Показаны основные поля записи: ```json { "success": true, "data": [ { "id": 9301, "name": "Документы", "storageId": 1, "type": "folder", "parentId": 27, "_included": { "storage": { "id": 1, "name": "Летта", "code": null, "module": "disk", "entityType": "user", "entityId": "1", "rootFolderId": 1 } } } ], "meta": { "total": 22, "hasMore": false } } ``` ## Пример ответа при ошибке 400 — не передан обязательный `parentId`: ```json { "success": false, "error": { "code": "MISSING_REQUIRED_PARAMS", "message": "GET /v1/folders requires query parameters: parentId. Example: GET /v1/folders?parentId=..." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_PARAMS` | Не передан обязательный `parentId` | | 400 | `INVALID_INCLUDE` | Значение `include` не поддерживается. Доступное значение — `storage` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `disk` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов портала | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности `GET /v1/folders` перечисляет детей одной папки, заданной через `parentId`. Это не плоский список всех папок хранилища — для обхода дерева запрашивайте каждую папку отдельно по её `id`. Корневую папку хранилища даёт поле `rootFolderId` в `GET /v1/storages`. ## Смотрите также - [Получить папку](/docs/entities/folders/get) - [Создать папку](/docs/entities/folders/create) - [Поля папки](/docs/entities/folders/fields) - [Файлы](/docs/entities/files) - [Хранилища](/docs/entities/storages) - [Синтаксис фильтрации](/docs/filtering) --- # Folders: Moveto ## Переместить папку `POST /v1/folders/:id/moveto` Перемещает папку в другую родительскую папку того же хранилища. После успеха поле `parentId` в ответе содержит ID целевой папки. Поля `id`, `createdAt` и `createdBy` не изменяются. Перемещение между разными хранилищами не поддерживается — используйте [`copyto`](./copyto.md). ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | number | да | ID папки. Получить через `GET /v1/folders` | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|----------| | `targetFolderId` | number | да | ID папки-назначения. Получить через `GET /v1/folders` | ## Примеры ### curl — личный ключ ```bash curl -X POST \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"targetFolderId":649}' \ https://vibecode.bitrix24.tech/v1/folders/9303/moveto ``` ### curl — OAuth-приложение ```bash curl -X POST \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"targetFolderId":649}' \ https://vibecode.bitrix24.tech/v1/folders/9303/moveto ``` ### JavaScript — личный ключ ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/folders/9303/moveto', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ targetFolderId: 649 }), } ) const body = await res.json() if (!body.success) throw new Error(body.error.code) console.log('Папка перемещена, новый родитель:', body.data.parentId) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/folders/9303/moveto', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ targetFolderId: 649 }), } ) const body = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | `true` при успешном перемещении | | `data.id` | number | ID папки — не изменяется после перемещения | | `data.name` | string | Имя папки | | `data.code` | string \| null | Символьный код папки | | `data.parentId` | number | ID родительской папки — равен переданному `targetFolderId` | | `data.storageId` | number | ID хранилища | | `data.type` | string | Тип объекта — всегда `"folder"` | | `data.realObjectId` | number | Внутренний ID объекта | | `data.deletedType` | number | Статус удаления: `0` — активна | | `data.createdBy` | number | ID пользователя, создавшего папку — не изменяется | | `data.updatedBy` | number | ID пользователя, выполнившего перемещение | | `data.deletedBy` | number | ID пользователя, удалившего папку. `null` — не удалена | | `data.createdAt` | string | Дата создания (ISO 8601) — не изменяется | | `data.updatedAt` | string | Дата последнего изменения (ISO 8601) | | `data.deletedAt` | string \| null | Дата удаления или `null` | | `data.detailUrl` | string | URL карточки папки в Битрикс24 | ## Пример ответа ```json { "success": true, "data": { "id": 9303, "name": "Документы", "code": null, "storageId": 1, "type": "folder", "realObjectId": 9303, "parentId": 649, "deletedType": 0, "createdAt": "2026-06-25T12:54:43.000Z", "updatedAt": "2026-06-25T12:54:43.000Z", "deletedAt": null, "createdBy": 1, "updatedBy": 1, "deletedBy": null, "detailUrl": "https://.bitrix24.ru/company/personal/user/1/disk/path/Архив/Документы" } } ``` ## Пример ответа при ошибке 422 — в целевой папке уже есть папка с таким именем: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Папка с таким именем уже есть (DISK_OBJ_22000)." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `MISSING_PARAMS` | Не передан `targetFolderId` | | 400 | `INVALID_PARAMS` | `targetFolderId` не является положительным целым числом | | 400 | `INVALID_ID` | `id` папки не является положительным целым числом | | 400 | `OPERATION_FAILED` | Перемещение между разными хранилищами не поддерживается — используйте [`POST /v1/folders/:id/copyto`](./copyto.md) | | 401 | `TOKEN_MISSING` | Для портала нет токенов авторизации | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `disk` | | 404 | `ENTITY_NOT_FOUND` | Папка с указанным `id` не найдена | | 422 | `BITRIX_ERROR` | В целевой папке уже есть папка с таким именем — переименуйте через `PATCH /v1/folders/:id` перед перемещением | | 429 | `RATE_LIMITED` | Превышен лимит запросов — подождите 1-2 секунды и повторите | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Постоянство идентификатора.** После перемещения `id`, `createdAt` и `createdBy` папки не изменяются — все внешние ссылки на папку по ID остаются рабочими. Перемещается папка вместе со всем вложенным содержимым. ## Смотрите также - [Скопировать папку](./copyto.md) - [Получить папку](./get.md) - [Список содержимого папки](./list.md) - [Файлы](/docs/entities/files) --- # Folders: Search ## Поиск папок `POST /v1/folders/search` Перечисляет содержимое папки через POST-запрос с фильтром в теле. Поведение совпадает с [`GET /v1/folders`](./list.md) — параметры передаются в теле, а не в строке запроса. Фильтр обязан содержать `parentId`. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `filter` | object | да | Условия отбора. Обязан содержать `parentId` — ID папки, чьё содержимое перечисляется.
[Синтаксис фильтрации](/docs/filtering). Пример: `{"parentId":27,"type":"folder"}` | | `select` | array | нет | Список возвращаемых полей. Пример: `["id","name"]` | | `order` | object | нет | Сортировка по полю. Пример: `{"name":"asc"}` | | `limit` | number | нет | Сколько записей вернуть. По умолчанию 50, максимум 5000 | | `offset` | number | нет | Смещение для постраничной выборки | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/folders/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"filter":{"parentId":27,"type":"folder"},"limit":10}' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/folders/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"filter":{"parentId":27,"type":"folder"},"limit":10}' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/folders/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { parentId: 27, type: 'folder' }, limit: 10 }), }) const { success, data, meta } = await res.json() console.log('Найдено:', data.length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/folders/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { parentId: 27, type: 'folder' }, limit: 10 }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив записей — подпапки и файлы. Все поля — см. [Поля папки](./fields.md) | | `data[].type` | string | Тип записи: `"folder"` или `"file"` | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа ```json { "success": true, "data": [ { "id": 9301, "name": "Документы", "code": null, "storageId": 1, "type": "folder", "realObjectId": 9301, "parentId": 27, "deletedType": 0, "createdAt": "2026-06-25T12:10:00.000Z", "updatedAt": "2026-06-25T12:10:00.000Z", "deletedAt": null, "createdBy": 1, "updatedBy": 1, "deletedBy": null, "detailUrl": "https://.bitrix24.ru/company/personal/user/1/disk/path/Документы" } ], "meta": { "total": 1, "hasMore": false, "durationMs": 125 } } ``` ## Пример ответа при ошибке 403 — нет скоупа `disk`: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'disk' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_PARAMS` | Фильтр не содержит обязательный `parentId`. `message` перечисляет недостающие поля | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `disk` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов портала | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности Поиск перечисляет содержимое одной папки, заданной через `parentId`, а не ищет по всему хранилищу. Для разовых выборок проще использовать [`GET /v1/folders`](./list.md) с тем же набором параметров в строке запроса. ## Смотрите также - [Список содержимого папки](/docs/entities/folders/list) - [Поля папки](/docs/entities/folders/fields) - [Папки](/docs/entities/folders) - [Синтаксис фильтрации](/docs/filtering) --- # Folders: Update ## Переименовать папку `PATCH /v1/folders/:id` Переименовывает папку. Принимает только поле `name`. Чтобы переместить папку в другую родительскую, используйте [`POST /v1/folders/:id/moveto`](./moveto.md). ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|----------| | `id` (path) | number | да | ID папки. Список: `GET /v1/folders` | ## Поля запроса (body) | Поле | Битрикс24 | Тип | Обяз. | Описание | |------|----------|-----|:-----:|---------| | `name` | `NAME` | string | да | Новое имя папки | Поля `parentId` и `code` неизменяемы — их передача возвращает `400 READONLY_FIELD`. Чтобы переместить папку в другую родительскую, используйте [`POST /v1/folders/:id/moveto`](./moveto.md). ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/folders/9301" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name":"Договоры"}' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/folders/9301" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"Договоры"}' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/folders/9301', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Договоры' }), }) const { success, data } = await res.json() console.log(data.name) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/folders/9301', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Договоры' }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект папки после переименования. Все поля — см. [Поля папки](./fields.md) | ## Пример ответа ```json { "success": true, "data": { "id": 9301, "name": "Договоры", "code": null, "storageId": 1, "type": "folder", "realObjectId": 9301, "parentId": 27, "deletedType": 0, "createdAt": "2026-06-25T12:10:00.000Z", "updatedAt": "2026-06-25T12:15:30.000Z", "deletedAt": null, "createdBy": 1, "updatedBy": 1, "deletedBy": null, "detailUrl": "https://.bitrix24.ru/company/personal/user/1/disk/path/Загруженные файлы/Договоры" } } ``` ## Пример ответа при ошибке 400 — попытка изменить неизменяемое поле: ```json { "success": false, "error": { "code": "READONLY_FIELD", "message": "Field 'parentId' is read-only and cannot be set" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `READONLY_FIELD` | В теле передано неизменяемое поле — `parentId` или `code` | | 404 | `ENTITY_NOT_FOUND` | Папки с указанным `id` нет | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `disk` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов портала | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать папку](/docs/entities/folders/create) - [Получить папку](/docs/entities/folders/get) - [Удалить папку](/docs/entities/folders/delete) - [Поля папки](/docs/entities/folders/fields) --- # Invoices: Aggregate ## Агрегация счетов `POST /v1/invoices/aggregate` Подсчёт количества, сумма, среднее, минимум и максимум по счетам с фильтрацией и группировкой. **Стандартные поля:** - `opportunity` — сумма счёта (числовое агрегирование имеет смысл) - `stageId` — стадия (для `groupBy`) - `assignedById` — ответственный (для `groupBy`) **Пользовательские поля (UF):** UF-поля типов `integer`, `double`, `money` — для числовых функций; UF любого типа — для `groupBy`. Полный список UF-полей конкретного портала приходит в тексте ошибки `INVALID_PARAMS`, если передать несуществующее имя. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций. Каждый элемент: `{ "field": "opportunity", "function": "sum" }`. Функции: `count`, `sum`, `avg`, `min`, `max`. Для `count` поле — `"*"`. Без массива — только `count` | | `filter` | object | нет | Фильтрация по полям `GET /v1/invoices/fields`. [Синтаксис фильтрации](/docs/filtering) | | `groupBy` | string \| string[] | нет | Поле или массив полей для группировки (максимум 5). Допустимые значения — из списка выше | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/invoices/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "opportunity", "function": "sum" }, { "field": "opportunity", "function": "avg" } ], "filter": { "assignedById": 1 }, "groupBy": "stageId" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/invoices/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "opportunity", "function": "sum" }, { "field": "opportunity", "function": "avg" } ], "filter": { "assignedById": 1 }, "groupBy": "stageId" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [ { field: 'opportunity', function: 'sum' }, { field: 'opportunity', function: 'avg' }, ], filter: { assignedById: 1 }, groupBy: 'stageId', }), }) const { success, data } = await res.json() console.log('Всего счетов:', data.count) console.log('По стадиям:', data.groups) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [ { field: 'opportunity', function: 'sum' }, { field: 'opportunity', function: 'avg' }, ], filter: { assignedById: 1 }, groupBy: 'stageId', }), }) const { success, data } = await res.json() ``` > Для группировки по нескольким полям передайте массив: `"groupBy": ["stageId", "assignedById"]` (максимум 5). ## Другие сценарии Подсчёт записей — `count` с полем `"*"`, самый быстрый запрос без выгрузки записей. Без массива `aggregate` результат тот же: ```json { "aggregate": [{ "field": "*", "function": "count" }] } ``` Работа с пользовательскими полями (UF) — `sum` по UF + группировка по другому UF: ```json { "aggregate": [{ "field": "UF_CRM_TAX", "function": "sum" }], "groupBy": "UF_CRM_PAYMENT_METHOD" } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Общее количество записей под фильтр | | `data.aggregates` | object | Результаты агрегаций: `{ "opportunity": { "sum": 120000, "avg": 2200 } }` | | `data.groups` | array | Группы (только при `groupBy`). Каждый элемент: поля группировки + `count` + `aggregates` | | `data.meta.totalRecords` | number | Общее количество записей под фильтр | | `data.meta.recordsProcessed` | number | Сколько записей обработано для числовых агрегаций (максимум 5000) | | `data.meta.truncated` | boolean | `true`, если под фильтр попало больше 5000 записей | ## Пример ответа Ответ на основной запрос (агрегации + `groupBy: "stageId"`): ```json { "success": true, "data": { "count": 55, "aggregates": { "opportunity": { "sum": 120000, "avg": 2200 } }, "groups": [ { "stageId": "DT31_5:N", "count": 30, "aggregates": { "opportunity": { "sum": 70000 } } }, { "stageId": "DT31_5:P", "count": 25, "aggregates": { "opportunity": { "sum": 50000 } } } ], "meta": { "totalRecords": 55, "recordsProcessed": 55, "truncated": false } } } ``` Без `groupBy` поле `data.groups` в ответе отсутствует. ## Пример ответа при ошибке 400 — неверное имя функции, несуществующее поле или `groupBy` по неаггрегируемому полю: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "Field 'foo' not found. Available numeric fields: opportunity, stageId, assignedById" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Некорректное имя функции, несуществующее поле, нечисловое поле в `sum`/`avg`/`min`/`max`, `groupBy` по неаггрегируемому полю или больше 5 полей в `groupBy` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`count` vs числовые функции.** `count` считается одним вызовом в Битрикс24 на любом объёме данных. Функции `sum`/`avg`/`min`/`max` подгружают записи постранично (максимум 5000) и считают на стороне Вайбкод — если под фильтр попадает больше 5000 записей, `meta.truncated` будет `true`, агрегация выполнится по первым 5000. Для точных счётчиков на больших выборках используйте `count` или сужайте фильтр. **Money-поля.** UF-поля типа `money` хранятся в формате `"сумма|валюта"` (`"1500|RUB"`) — агрегат извлекает числовую часть автоматически, складывать можно без парсинга. **Фильтрация по UF работает.** В `filter` можно передавать любые поля — стандартные и пользовательские, любого типа. Например, `{ "filter": { "ufCrm_1234": "value" } }` вернёт количество счетов с этим значением UF. ## Смотрите также - [Список счетов](/docs/entities/invoices/list) - [Поиск счетов](/docs/entities/invoices/search) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Invoices: Create ## Создать счёт `POST /v1/invoices` Создаёт новый счёт в CRM. ## Поля запроса (body) | Параметр | Тип | Описание | |----------|-----|---------| | `title` | string | Название счёта | | `stageId` | string | Стадия. Формат: `DT31_{categoryId}:{stage}`. Список стадий: `GET /v1/statuses?filter[entityId]=SMART_INVOICE_STAGE_{categoryId}` — categoryId зависит от портала. Узнать: `GET /v1/invoices?limit=1&select=categoryId` или запросить у администратора | | `categoryId` | number | ID воронки | | `contactId` | number | ID контакта-плательщика. Поиск: `GET /v1/contacts` | | `companyId` | number | ID компании-плательщика. Поиск: `GET /v1/companies` | | `mycompanyId` | number | ID своей компании | | `opportunity` | number | Сумма счёта | | `currencyId` | string | Валюта. Список: `GET /v1/currencies` | | `assignedById` | number | Ответственный. Список: `GET /v1/users` | | `comments` | string | Комментарий | Полный список полей: [GET /v1/invoices/fields](/docs/entities/invoices/fields). Пользовательские поля (`ufCrm_*`) также принимаются. ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/invoices \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Счёт за услуги", "stageId": "DT31_5:N", "contactId": 42, "companyId": 15, "opportunity": 150000, "currencyId": "RUB", "assignedById": 1 }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/invoices \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Счёт за услуги", "stageId": "DT31_5:N", "contactId": 42, "companyId": 15, "opportunity": 150000, "currencyId": "RUB", "assignedById": 1 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Счёт за услуги', stageId: 'DT31_5:N', contactId: 42, companyId: 15, opportunity: 150000, currencyId: 'RUB', assignedById: 1, }), }) const { success, data } = await res.json() console.log('Invoice ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Счёт за услуги', stageId: 'DT31_5:N', contactId: 42, companyId: 15, opportunity: 150000, currencyId: 'RUB', assignedById: 1, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID созданного счёта | | `title` | string | Название | | `stageId` | string | Стадия | | `contactId` | number | ID контакта | | `companyId` | number | ID компании | | `opportunity` | number | Сумма | | `currencyId` | string | Валюта | | `assignedById` | number | Ответственный | | `createdBy` | number | Создатель | | `createdTime` | datetime | Дата создания | | `updatedTime` | datetime | Дата изменения | Ответ содержит все поля счёта, включая пользовательские (`ufCrm_*`). URL карточки счёта в Битрикс24 строится из `id`: ``` https://.bitrix24.ru/crm/type/31/details// ``` `31` — `entityTypeId` смарт-счёта в Битрикс24. `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": { "id": 891, "title": "Счёт за услуги", "stageId": "DT31_5:N", "categoryId": 5, "contactId": 42, "companyId": 15, "opportunity": 150000, "currencyId": "RUB", "assignedById": 1, "createdBy": 1, "createdTime": "2026-04-15T14:30:00+03:00", "updatedTime": "2026-04-15T14:30:00+03:00" } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 400 | `INVALID_REQUEST` | Некорректные поля | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Работа с файлами в полях CRM](/docs/recipes/crm-files) - [Список счетов](/docs/entities/invoices/list) - [Поля счёта](/docs/entities/invoices/fields) - [Контакты](/docs/entities/contacts) - [Компании](/docs/entities/companies) - [Entity API](/docs/entity-api) --- # Invoices: Delete ## Удалить счёт `DELETE /v1/invoices/:id` Удаляет счёт по ID. Восстановить удалённый счёт через API нельзя — создавайте новый при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID счёта | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/invoices/891" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/invoices/891" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/891', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) if (res.status === 204) { console.log('Счёт удалён') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/891', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — счёт не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Счёт с указанным ID не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список счетов](/docs/entities/invoices/list) - [Создать счёт](/docs/entities/invoices/create) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Invoices: Fields ## Поля счёта `GET /v1/invoices/fields` Возвращает описание всех полей счёта, включая пользовательские (`ufCrm_*`). ## Примеры ### curl — личный ключ ```bash curl -X GET https://vibecode.bitrix24.tech/v1/invoices/fields \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X GET https://vibecode.bitrix24.tech/v1/invoices/fields \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Только чтение | Описание | |------|-----|:---:|---------| | `id` | number | да | ID счёта | | `title` | string | | Название | | `stageId` | string | | Стадия. Формат: `DT31_{categoryId}:{stage}`. Список стадий: `GET /v1/statuses?filter[entityId]=SMART_INVOICE_STAGE_{categoryId}` — categoryId зависит от портала. Узнать: `GET /v1/invoices?limit=1&select=categoryId` или запросить у администратора | | `categoryId` | number | | ID воронки | | `contactId` | number | | ID контакта-плательщика. Поиск: `GET /v1/contacts` | | `companyId` | number | | ID компании-плательщика. Поиск: `GET /v1/companies` | | `mycompanyId` | number | | ID своей компании | | `opportunity` | number | | Сумма | | `currencyId` | string | | Валюта. Список: `GET /v1/currencies` | | `assignedById` | number | | Ответственный. Список: `GET /v1/users` | | `createdBy` | number | да | ID создателя | | `createdTime` | datetime | да | Дата создания | | `updatedTime` | datetime | да | Дата изменения | Пользовательские поля (`ufCrm_*`) возвращаются в ответе и доступны для записи. ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "ID счёта", "description": "Уникальный числовой идентификатор счёта." }, "title": { "type": "string", "readonly": false, "label": "Название", "description": "Название счёта." }, "assignedById": { "type": "number", "readonly": false, "label": "Ответственный", "description": "ID ответственного пользователя. Список: GET /v1/users." } }, "batch": ["create", "update", "delete"] } } ``` Показаны 3 из множества полей. Полный список в таблице выше. ## Доступные include Эндпоинт `GET /v1/invoices/fields` возвращает список доступных include: `contact`, `company`. Пример использования: [Получить invoices](/docs/entities/invoices/get#связанные-данные). Подробнее об include: [Связанные данные](/docs/includes). ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать счёт](/docs/entities/invoices/create) - [Список счетов](/docs/entities/invoices/list) - [Entity API](/docs/entity-api) --- # Invoices: Get ## Получить счёт `GET /v1/invoices/:id` Возвращает счёт по ID. Поддерживает включение связанных сущностей через `include`. ## Параметры запроса | Параметр | Тип | Описание | |----------|-----|---------| | `id` | number | ID счёта (в URL) | ## Примеры ### curl — личный ключ ```bash curl -X GET "https://vibecode.bitrix24.tech/v1/invoices/891" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X GET "https://vibecode.bitrix24.tech/v1/invoices/891" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/891', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() console.log('Получено:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/891', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` Подробнее об include: [Связанные данные](/docs/includes). ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID счёта | | `title` | string | Название | | `stageId` | string | Стадия | | `categoryId` | number | ID воронки | | `contactId` | number | ID контакта | | `companyId` | number | ID компании | | `opportunity` | number | Сумма | | `currencyId` | string | Валюта | | `assignedById` | number | Ответственный | | `createdBy` | number | Создатель | | `createdTime` | datetime | Дата создания | | `updatedTime` | datetime | Дата изменения | | `_included` | object | Связанные сущности (при `include`) | ## Связанные данные (include) ``` GET /v1/invoices/1?include=contact,company ``` Доступные include: `contact`, `company`. Результат в поле `_included`. ## Пример ответа ```json { "success": true, "data": { "id": 891, "title": "Счёт за услуги", "stageId": "DT31_5:N", "categoryId": 5, "contactId": 42, "companyId": 15, "opportunity": 150000, "currencyId": "RUB", "assignedById": 1, "createdBy": 1, "createdTime": "2026-04-15T14:30:00+03:00", "updatedTime": "2026-04-15T14:30:00+03:00", "_included": { "contact": { "id": 42, "name": "Иван", "lastName": "Петров" }, "company": { "id": 15, "title": "ООО Ромашка" } } } } ``` ## Пример ответа при ошибке 404 — счёт не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` Подробнее об include: [Связанные данные](/docs/includes). ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Счёт с указанным ID не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Работа с файлами в полях CRM](/docs/recipes/crm-files) - [Список счетов](/docs/entities/invoices/list) - [Обновить счёт](/docs/entities/invoices/update) - [Контакты](/docs/entities/contacts) - [Компании](/docs/entities/companies) - [Entity API](/docs/entity-api) --- # Invoices: List ## Список счетов `GET /v1/invoices` Возвращает список счетов с фильтрацией, сортировкой и пагинацией. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей | | `order` | object | — | Сортировка: `?order[createdTime]=desc` | | `select` | string | — | Выборка полей: `?select=id,title,stageId` | | `filter` | object | — | Фильтрация по полям `GET /v1/invoices/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[stageId]=DT31_5:N` | ## Примеры ### curl — личный ключ ```bash curl -X GET "https://vibecode.bitrix24.tech/v1/invoices?limit=10&sort=-createdTime&filter[stageId]=DT31_5:N" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X GET "https://vibecode.bitrix24.tech/v1/invoices?limit=10&sort=-createdTime&filter[stageId]=DT31_5:N" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const params = new URLSearchParams({ limit: '10', sort: '-createdTime', 'filter[stageId]': 'DT31_5:N', }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/invoices?${params}`, { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data, meta } = await res.json() console.log(`Найдено: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const params = new URLSearchParams({ limit: '10', sort: '-createdTime', 'filter[stageId]': 'DT31_5:N', }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/invoices?${params}`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив счетов | | `meta.total` | number | Общее количество записей под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `data[].id` | number | ID счёта | | `data[].title` | string | Название | | `data[].stageId` | string | Стадия | | `data[].opportunity` | number | Сумма | | `data[].currencyId` | string | Валюта | | `data[].contactId` | number | ID контакта | | `data[].companyId` | number | ID компании | | `data[].assignedById` | number | Ответственный | | `data[].createdTime` | datetime | Дата создания | URL карточки любого счёта из массива `data` — его `id`: ``` https://.bitrix24.ru/crm/type/31/details// ``` `31` — `entityTypeId` смарт-счёта в Битрикс24. `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 891, "title": "Счёт за услуги", "stageId": "DT31_5:N", "categoryId": 5, "contactId": 42, "companyId": 15, "opportunity": 150000, "currencyId": "RUB", "assignedById": 1, "createdBy": 1, "createdTime": "2026-04-15T14:30:00+03:00", "updatedTime": "2026-04-15T14:30:00+03:00" } ], "meta": { "total": 47, "hasMore": false } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить счёт](/docs/entities/invoices/get) - [Поиск счетов](/docs/entities/invoices/search) - [Поля счёта](/docs/entities/invoices/fields) - [Entity API](/docs/entity-api) - [Лимиты и оптимизация](/docs/optimization) --- # Invoices: Products Add > Поле, которого нет среди записываемых, больше не отбрасывается молча — запрос отклоняется с `400 INVALID_PARAMS`, и в тексте ошибки перечислены записываемые имена. Поля только для чтения, которые приходят в ответах товарных позиций (`priceAccount`, `ownerId`, `storeId` и другие) по-прежнему принимаются и игнорируются, поэтому объект, прочитанный через GET, можно отправить обратно без чистки. ## Добавить товар в счёт `POST /v1/invoices/:id/products` Добавляет одну товарную позицию в счёт. В отличие от `PUT /v1/invoices/:id/products`, не заменяет существующие позиции. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID счёта | | `productId` | number | нет | ID товара из каталога. Если задан без `productName`, имя подставляется из каталога. Каталог: `GET /v1/products` | | `productName` | string | нет | Название товарной позиции — для произвольной строки без товара из каталога. Укажите хотя бы одно из `productId` / `productName`. | | `price` | number | нет | Цена за единицу | | `quantity` | number | нет | Количество | | `discount` | number | нет | Сумма скидки | | `taxRate` | number | нет | Ставка налога (%) | | `taxIncluded` | boolean | нет | Налог включён в цену | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/invoices/58/products" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "productId": 1, "price": 25000, "quantity": 2 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/invoices/58/products" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "productId": 1, "price": 25000, "quantity": 2 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/58/products', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ productId: 1, price: 25000, quantity: 2 }), }) const { success, data } = await res.json() console.log('ID строки:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/58/products', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ productId: 1, price: 25000, quantity: 2 }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | object | Созданная товарная строка целиком, HTTP-статус `201`. Состав полей — [Поля товаров](/docs/entities/invoices/products-fields) | ## Пример ответа Показаны основные поля. Полный список — [Поля товаров](/docs/entities/invoices/products-fields). ```json { "success": true, "data": { "id": 1465, "productId": 1, "productName": "Серверное оборудование", "price": 25000, "quantity": 2, "discount": 0, "discountTypeId": 2, "taxIncluded": false } } ``` ## Пример ответа при ошибке 404 — счёт не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Тело содержит имя, которого нет среди записываемых полей — см. [Поля товаров](/docs/entities/invoices/products-fields) | | 404 | `ENTITY_NOT_FOUND` | Счёт не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Товарные позиции](/docs/entities/invoices/products-get) - [Установить товары](/docs/entities/invoices/products-set) - [Удалить товар](/docs/entities/invoices/products-delete) - [Товары каталога](/docs/entities/products) --- # Invoices: Products Delete ## Удалить товар из счёта `DELETE /v1/invoices/:id/products/:rowId` Удаляет одну товарную позицию из счёта по ID строки. Восстановить удалённую позицию через API нельзя — добавляйте новую при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID счёта | | `rowId` (path) | number | да | ID товарной строки (из ответа add или list) | `rowId` — это ID товарной строки, а не `productId` из каталога товаров. ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/invoices/58/products/1465" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/invoices/58/products/1465" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/58/products/1465', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Товар удалён из счёта') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/58/products/1465', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — счёт не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Счёт или товарная строка не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Товарные позиции](/docs/entities/invoices/products-get) - [Добавить товар](/docs/entities/invoices/products-add) - [Установить товары](/docs/entities/invoices/products-set) - [Товары каталога](/docs/entities/products) --- # Invoices: Products Fields ## Поля товаров счёта `GET /v1/invoices/:id/products/fields` Возвращает описание полей товарных позиций счёта: названия, типы, доступность для чтения и записи. > **Сумма скидки называется `discount`** — как в данных и при записи. Прежнее имя `discountSum` осталось устаревшим псевдонимом: оно по-прежнему приходит в этом справочнике и принимается при записи, поэтому код, написанный по старому списку полей, продолжает работать. В самих товарных позициях приходит только `discount` — переходите на него. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID счёта | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/invoices/741/products/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/invoices/741/products/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/741/products/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/741/products/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | RO | Обяз. | Описание | |------|-----|:--:|:-----:|---------| | `id` | integer | да | | ID позиции | | `productId` | integer | | да | ID товара. Каталог: `GET /v1/products` | | `productName` | string | | | Название товара | | `price` | double | | | Цена | | `quantity` | double | | | Количество | | `discount` | double | | | Сумма скидки | | `discountSum` | double | | | Устаревший псевдоним `discount` — принимается при записи, в товарных позициях не приходит | | `discountRate` | double | | | Величина скидки (%) | | `discountTypeId` | integer | | | Тип скидки | | `taxRate` | double | | | Налог (%) | | `taxIncluded` | char | | | Налог включён в цену (`Y`/`N`) | | `priceExclusive` | double | да | | Цена без налога со скидкой | | `priceNetto` | double | да | | Цена нетто | | `priceBrutto` | double | да | | Цена брутто | | `measureCode` | integer | | | Код единицы измерения | | `measureName` | string | да | | Единица измерения | | `customized` | char | да | | Изменён (`Y`/`N`) | | `sort` | integer | | | Сортировка | | `type` | integer | да | | Тип | | `storeId` | integer | да | | ID склада | | `ownerId` | integer | да | | ID владельца (счёта) | | `ownerType` | string | да | | Тип владельца | | `priceAccount` | double | да | | Цена в валюте отчёта | | `xmlId` | string | да | | Внешний код позиции | ## Пример ответа ```json { "success": true, "data": { "id": { "type": "integer", "isRequired": false, "isReadOnly": true, "title": "ID", "description": "Row identity. Read-only as an attribute; echo it back in PUT /products items to update a row in place instead of recreating it." }, "ownerId": { "type": "integer", "isRequired": false, "isReadOnly": true, "isImmutable": true, "title": "ID владельца" }, "ownerType": { "type": "string", "isRequired": false, "isReadOnly": true, "isImmutable": true, "title": "Тип владельца" }, "productId": { "type": "integer", "isRequired": true, "isReadOnly": false, "title": "Товар" }, "productName": { "type": "string", "isRequired": false, "isReadOnly": false, "title": "Название товара" }, "price": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Цена" }, "priceExclusive": { "type": "double", "isRequired": false, "isReadOnly": true, "title": "Цена без налога со скидкой" }, "priceNetto": { "type": "double", "isRequired": false, "isReadOnly": true, "title": "PRICE_NETTO" }, "priceBrutto": { "type": "double", "isRequired": false, "isReadOnly": true, "title": "PRICE_BRUTTO" }, "quantity": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Количество" }, "discountTypeId": { "type": "integer", "isRequired": false, "isReadOnly": false, "title": "Тип скидки" }, "discountRate": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Величина скидки" }, "discount": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Сумма скидки" }, "discountSum": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Сумма скидки", "description": "Deprecated alias of `discount`; kept so clients written against the previous field list keep working. Accepted on write, never present in row data — migrate to `discount`." }, "taxRate": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Налог" }, "taxIncluded": { "type": "char", "isRequired": false, "isReadOnly": false, "title": "Налог включен в цену" }, "customized": { "type": "char", "isRequired": false, "isReadOnly": true, "title": "Изменен" }, "measureCode": { "type": "integer", "isRequired": false, "isReadOnly": false, "title": "Код единицы измерения" }, "measureName": { "type": "string", "isRequired": false, "isReadOnly": true, "title": "Единица измерения" }, "sort": { "type": "integer", "isRequired": false, "isReadOnly": false, "title": "Сортировка" }, "type": { "type": "integer", "isRequired": false, "isReadOnly": true, "title": "TYPE" }, "storeId": { "type": "integer", "isRequired": false, "isReadOnly": true, "title": "STORE_ID" }, "priceAccount": { "type": "double", "isRequired": false, "isReadOnly": true }, "xmlId": { "type": "string", "isRequired": false, "isReadOnly": true } } } ``` ## Пример ответа при ошибке 404 — счёт не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Счёт не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Товарные позиции](/docs/entities/invoices/products-get) - [Добавить товар](/docs/entities/invoices/products-add) - [Установить товары](/docs/entities/invoices/products-set) - [Поля счёта](/docs/entities/invoices/fields) --- # Invoices: Products Get ## Товарные позиции счёта `GET /v1/invoices/:id/products` Возвращает список товарных позиций, привязанных к счёту. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID счёта | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/invoices/741/products" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/invoices/741/products" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/741/products', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Товаров:', data.length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/741/products', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив товарных позиций | | `data[].productId` | number | ID товара. Каталог: `GET /v1/products` | | `data[].productName` | string | Название товара | | `data[].price` | number | Цена за единицу | | `data[].quantity` | number | Количество | | `data[].discount` | number | Сумма скидки | | `data[].taxRate` | number/null | Ставка налога (%) | | `data[].taxIncluded` | boolean | Налог включён в цену | Показаны основные поля. Полный список (23 поля, включая priceAccount, measureCode и др.): [Поля товаров](/docs/entities/invoices/products-fields). ## Пример ответа ```json { "success": true, "data": [ { "productId": 1, "productName": "Серверное оборудование", "price": 1000, "quantity": 2, "discount": 0, "taxRate": null, "taxIncluded": false } ] } ``` ## Пример ответа при ошибке 404 — счёт не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Счёт не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Установить товары](/docs/entities/invoices/products-set) - [Получить счёт](/docs/entities/invoices/get) - [Товары каталога](/docs/entities/products) - [Лимиты и оптимизация](/docs/optimization) --- # Invoices: Products Get Single ## Получить товар из счёта `GET /v1/invoices/:id/products/:rowId` Возвращает одну товарную позицию счёта по ID строки. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID счёта | | `rowId` (path) | number | да | ID товарной строки (из ответа add или list) | `rowId` — это ID товарной строки, а не `productId` из каталога товаров. ## Примеры ### curl — личный ключ ```bash curl -X GET "https://vibecode.bitrix24.tech/v1/invoices/741/products/1471" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X GET "https://vibecode.bitrix24.tech/v1/invoices/741/products/1471" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/741/products/1471', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Цена:', data.price) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/741/products/1471', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.id` | number | ID товарной строки | | `data.productId` | number | ID товара из каталога | | `data.productName` | string | Название товара | | `data.price` | number | Цена за единицу | | `data.quantity` | number | Количество | | `data.discount` | number | Сумма скидки | | `data.discountRate` | number | Процент скидки | | `data.discountTypeId` | number | Тип скидки (1 — сумма, 2 — процент) | | `data.taxRate` | number \| null | Ставка налога (%) | | `data.taxIncluded` | boolean | Налог включён в цену | | `data.priceExclusive` | number | Цена без скидки | | `data.priceNetto` | number | Цена нетто | | `data.priceBrutto` | number | Цена брутто | | `data.priceAccount` | number | Цена в валюте учёта | | `data.measureCode` | number | Код единицы измерения | | `data.measureName` | string | Название единицы измерения | | `data.sort` | number | Сортировка | | `data.ownerId` | number | ID сущности-владельца, которой принадлежит позиция | | `data.ownerType` | string | Код типа владельца (`D` у сделок, `T` у смарт-процессов) | | `data.storeId` | number \| null | ID склада; `null`, если складской учёт выключен | ## Пример ответа ```json { "success": true, "data": { "id": 1471, "productId": 1, "productName": "День добрый!", "price": 5000, "priceAccount": 5000, "priceExclusive": 5000, "priceNetto": 5000, "priceBrutto": 5000, "quantity": 3, "discountTypeId": 2, "discountRate": 0, "discount": 0, "taxRate": null, "taxIncluded": false, "customized": "Y", "measureCode": 796, "measureName": "шт", "sort": 0, "ownerId": 741, "ownerType": "D", "storeId": 3, "xmlId": "sale_basket_995", "type": 1 } } ``` ## Пример ответа при ошибке 404 — счёт или товарная строка не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Счёт или товарная строка не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Товарные позиции](/docs/entities/invoices/products-get) - [Обновить товар](/docs/entities/invoices/products-update) - [Добавить товар](/docs/entities/invoices/products-add) - [Удалить товар](/docs/entities/invoices/products-delete) - [Товары каталога](/docs/entities/products) --- # Invoices: Products Set > Поле, которого нет среди записываемых, больше не отбрасывается молча — запрос отклоняется с `400 INVALID_PARAMS`, и в тексте ошибки перечислены записываемые имена. Поля только для чтения, которые приходят в ответах товарных позиций (`priceAccount`, `ownerId`, `storeId` и другие) по-прежнему принимаются и игнорируются, поэтому объект, прочитанный через GET, можно отправить обратно без чистки. > Сохраняйте `id` у элемента, чтобы обновить существующую строку на месте: без него строка будет создана заново с новым идентификатором. ## Установить товары счёта `PUT /v1/invoices/:id/products` Устанавливает товарные позиции счёта. Полностью заменяет текущий список — передайте все нужные позиции. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `items` | array | да | Массив товарных позиций | | `items[].productId` | number | да | ID товара. Каталог: `GET /v1/products` | | `items[].price` | number | да | Цена за единицу | | `items[].quantity` | number | да | Количество | | `items[].discount` | number | нет | Сумма скидки | | `items[].taxRate` | number | нет | Ставка налога (%) | | `items[].taxIncluded` | boolean | нет | Налог включён в цену | ## Примеры ### curl — личный ключ ```bash curl -X PUT "https://vibecode.bitrix24.tech/v1/invoices/58/products" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "items": [ { "productId": 1, "price": 25000, "quantity": 2 }, { "productId": 5, "price": 5000, "quantity": 1, "discount": 500 } ] }' ``` ### curl — OAuth-приложение ```bash curl -X PUT "https://vibecode.bitrix24.tech/v1/invoices/58/products" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "items": [ { "productId": 1, "price": 25000, "quantity": 2 }, { "productId": 5, "price": 5000, "quantity": 1, "discount": 500 } ] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/58/products', { method: 'PUT', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ items: [ { productId: 1, price: 25000, quantity: 2 }, { productId: 5, price: 5000, quantity: 1, discount: 500 }, ], }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/58/products', { method: 'PUT', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ items: [ { productId: 1, price: 25000, quantity: 2 }, { productId: 5, price: 5000, quantity: 1, discount: 500 }, ], }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив установленных позиций с полями productId, productName, price, quantity, discount, taxRate, taxIncluded | Массив установленных позиций с полями `productId`, `productName`, `price`, `quantity`, `discount`, `taxRate`, `taxIncluded`. ## Пример ответа ```json { "success": true, "data": [ { "productId": 1, "productName": "Серверное оборудование", "price": 25000, "quantity": 2, "discount": 0, "taxRate": null, "taxIncluded": false }, { "productId": 5, "productName": "Установка и настройка", "price": 5000, "quantity": 1, "discount": 500, "taxRate": null, "taxIncluded": false } ] } ``` ## Пример ответа при ошибке 400 — неверный формат: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "items must be an array" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Тело содержит имя, которого нет среди записываемых полей — см. [Поля товаров](/docs/entities/invoices/products-fields) | | 400 | `INVALID_PARAMS` | `items` не является массивом | | 404 | `ENTITY_NOT_FOUND` | Счёт не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Полная замена:** PUT заменяет весь список товаров. Чтобы добавить позицию — сначала получите текущие (`GET`), добавьте новую в массив, отправьте всё (`PUT`). ## Смотрите также - [Товарные позиции](/docs/entities/invoices/products-get) - [Получить счёт](/docs/entities/invoices/get) - [Товары каталога](/docs/entities/products) - [Лимиты и оптимизация](/docs/optimization) --- # Invoices: Products Update > Поле, которого нет среди записываемых, больше не отбрасывается молча — запрос отклоняется с `400 INVALID_PARAMS`, и в тексте ошибки перечислены записываемые имена. Поля только для чтения, которые приходят в ответах товарных позиций (`priceAccount`, `ownerId`, `storeId` и другие) по-прежнему принимаются и игнорируются, поэтому объект, прочитанный через GET, можно отправить обратно без чистки. ## Обновить товар счёта `PATCH /v1/invoices/:id/products/:rowId` Обновляет товарную позицию счёта. Передайте только изменяемые поля. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID счёта | | `rowId` (path) | number | да | ID товарной позиции (из ответа list или add, не productId из каталога) | ## Поля запроса (body) | Параметр | Тип | Описание | |----------|-----|---------| | `price` | number | Цена за единицу | | `quantity` | number | Количество | | `productId` | number | ID товара. Каталог: `GET /v1/products` | | `discount` | number | Сумма скидки | | `taxRate` | number | Ставка налога (%) | | `taxIncluded` | boolean | Налог включён в цену | | `sort` | number | Сортировка | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/invoices/741/products/1471" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "price": 9999, "quantity": 10 }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/invoices/741/products/1471" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "price": 9999, "quantity": 10 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/741/products/1471', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ price: 9999, quantity: 10 }), }) const { success, data } = await res.json() console.log('Обновлено:', data.price, 'x', data.quantity) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/741/products/1471', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ price: 9999, quantity: 10 }), }) const { success, data } = await res.json() ``` ## Поля ответа Обновлённый объект товарной позиции: `id`, `productId`, `productName`, `price`, `quantity`, `discount`, `taxRate`, `taxIncluded`. ## Пример ответа ```json { "success": true, "data": { "id": 1471, "productId": 1, "productName": "Серверное оборудование", "price": 9999, "quantity": 10, "discount": 0, "taxRate": null, "taxIncluded": false } } ``` ## Пример ответа при ошибке 404 — позиция не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Тело содержит имя, которого нет среди записываемых полей — см. [Поля товаров](/docs/entities/invoices/products-fields) | | 404 | `ENTITY_NOT_FOUND` | Позиция не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить товар](/docs/entities/invoices/products-get-single) - [Получить товары](/docs/entities/invoices/products-get) - [Добавить товар](/docs/entities/invoices/products-add) - [Лимиты и оптимизация](/docs/optimization) --- # Invoices: Search ## Поиск счетов `POST /v1/invoices/search` Расширенный поиск счетов с фильтрацией, сортировкой и авто-пагинацией. Поддерживает до 5000 записей. ## Поля запроса (body) | Параметр | Тип | Описание | |----------|-----|---------| | `filter` | object | Фильтрация по полям `GET /v1/invoices/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[stageId]=DT31_5:N` | | `sort` | string | Сортировка. Префикс `-` — по убыванию | | `limit` | number | Количество записей (по умолчанию 50, макс. 5000) | | `offset` | number | Пропустить N записей. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки» | | `select` | array | Список возвращаемых полей | | `autoWindow` | boolean | Разбивать выборку по недельным окнам при фильтре по диапазону дат шире 14 дней. По умолчанию `true`. `false` отключает разбиение | ### Синтаксис фильтров Поддерживаются три формата: ```json { "filter": { ">=opportunity": 100000 } } { "filter": { "opportunity": { "$gte": 100000 } } } { "filter": { "opportunity": { ">=": 100000 } } } ``` ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/invoices/search \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { ">=opportunity": 100000, "assignedById": 1 }, "sort": "-createdTime", "limit": 100 }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/invoices/search \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { ">=opportunity": 100000, "assignedById": 1 }, "sort": "-createdTime", "limit": 100 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { '>=opportunity': 100000, assignedById: 1 }, sort: '-createdTime', limit: 100, }), }) const { success, data, meta } = await res.json() console.log(`Найдено: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { '>=opportunity': 100000, assignedById: 1 }, sort: '-createdTime', limit: 100, }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив счетов | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временны́м окнам | | `meta.windowCount` | number | Число окон. Приходит при `autoWindowed: true` | | `meta.batchWaves` | number | Число волн параллельных запросов. Приходит при `autoWindowed: true` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. URL карточки любого счёта из массива `data` — его `id`: ``` https://.bitrix24.ru/crm/type/31/details// ``` `31` — `entityTypeId` смарт-счёта в Битрикс24. `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 891, "title": "Счёт за услуги", "stageId": "DT31_5:N", "opportunity": 150000, "currencyId": "RUB", "assignedById": 1, "createdTime": "2026-04-15T14:30:00+03:00" } ], "meta": { "total": 12, "hasMore": false, "durationMs": 240 } } ``` С фильтром по диапазону дат шире 14 дней в `meta` дополнительно приходят `autoWindowed`, `windowCount` и `batchWaves`: ```json { "success": true, "data": [ /* ... */ ], "meta": { "total": 16, "hasMore": true, "autoWindowed": true, "windowCount": 131, "batchWaves": 3, "durationMs": 3090 } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 400 | `INVALID_REQUEST` | Некорректный фильтр или параметры | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Разбиение по временны́м окнам.** Фильтр по диапазону дат шире 14 дней автоматически разбивается на недельные окна, которые выполняются параллельными волнами — так выборка обходит потолок в 5000 записей на один вызов. В `meta` тогда приходят `autoWindowed: true`, число окон `windowCount` и число волн `batchWaves`. Отключает разбиение параметр `autoWindow: false`. При активном разбиении `offset` больше нуля отклоняется с `UNSTABLE_OFFSET_PAGINATION`. ## Смотрите также - [Список счетов](/docs/entities/invoices/list) - [Поля счёта](/docs/entities/invoices/fields) - [Batch](/docs/batch) - [Entity API](/docs/entity-api) --- # Invoices: Update ## Обновить счёт `PATCH /v1/invoices/:id` Обновляет поля счёта. Передавайте только изменяемые поля. ## Параметры запроса | Параметр | Тип | Описание | |----------|-----|---------| | `id` | number | ID счёта (в URL) | ## Поля запроса (body) | Параметр | Тип | Описание | |----------|-----|---------| | `title` | string | Название счёта | | `stageId` | string | Стадия. Формат: `DT31_{categoryId}:{stage}`. Список стадий: `GET /v1/statuses?filter[entityId]=SMART_INVOICE_STAGE_{categoryId}` — categoryId зависит от портала. Узнать: `GET /v1/invoices?limit=1&select=categoryId` или запросить у администратора | | `contactId` | number | ID контакта-плательщика | | `companyId` | number | ID компании-плательщика | | `opportunity` | number | Сумма | | `currencyId` | string | Валюта. Список: `GET /v1/currencies` | | `assignedById` | number | Ответственный. Список: `GET /v1/users` | | `comments` | string | Комментарий | Полный список полей: [GET /v1/invoices/fields](/docs/entities/invoices/fields). Пользовательские поля (`ufCrm_*`) также принимаются. ## Примеры ### curl — личный ключ ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/invoices/891 \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "opportunity": 200000, "stageId": "DT31_5:WON" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/invoices/891 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "opportunity": 200000, "stageId": "DT31_5:WON" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/891', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ opportunity: 200000, stageId: 'DT31_5:WON', }), }) const { success, data } = await res.json() console.log('Обновлён:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/invoices/891', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ opportunity: 200000, stageId: 'DT31_5:WON', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID счёта | | `title` | string | Название | | `stageId` | string | Стадия | | `opportunity` | number | Сумма | | `currencyId` | string | Валюта | | `assignedById` | number | Ответственный | | `updatedTime` | datetime | Дата изменения | Ответ содержит все поля счёта после обновления. ## Пример ответа ```json { "success": true, "data": { "id": 891, "title": "Счёт за услуги", "stageId": "DT31_5:WON", "categoryId": 5, "contactId": 42, "companyId": 15, "opportunity": 200000, "currencyId": "RUB", "assignedById": 1, "createdBy": 1, "createdTime": "2026-04-15T14:30:00+03:00", "updatedTime": "2026-04-15T15:10:00+03:00" } } ``` ## Пример ответа при ошибке 404 — счёт не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Счёт с указанным ID не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 400 | `INVALID_REQUEST` | Некорректные поля | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Работа с файлами в полях CRM](/docs/recipes/crm-files) - [Получить счёт](/docs/entities/invoices/get) - [Поля счёта](/docs/entities/invoices/fields) - [Создать счёт](/docs/entities/invoices/create) - [Entity API](/docs/entity-api) --- # Items: Aggregate ## Агрегация элементов `POST /v1/items/:entityTypeId/aggregate` Подсчёт количества, сумма, среднее, минимум и максимум по элементам смарт-процесса с фильтрацией и группировкой. Смарт-процесс задаётся в пути через `entityTypeId` — ID типа процесса, который можно получить через [GET /v1/smart-processes](/docs/entities/smart-processes/list). **Стандартные поля:** - `opportunity` — сумма элемента (числовое агрегирование имеет смысл) - `categoryId` — категория (для `groupBy`) - `assignedById` — ответственный (для `groupBy`) - `stageId` — стадия (для `groupBy`) - `createdBy` — создал (для `groupBy`) - `updatedBy` — последний изменил (для `groupBy`) **Пользовательские поля (UF):** имена UF-полей имеют префикс с внутренним номером типа смарт-процесса — `ufCrm_*` (например, `ufCrm7_1652689362`). Этот номер не равен `entityTypeId` из пути — точные имена UF-полей берите из ответа [`GET /v1/items/:entityTypeId/fields`](/docs/entities/items/fields) или из текста ошибки `INVALID_PARAMS`, она перечисляет доступные поля портала. Типы `integer`, `double`, `money` — для числовых функций, UF любого типа — для `groupBy`. Основной источник бизнес-данных в смарт-процессах — именно UF. ## Path-параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `entityTypeId` | number | да | ID типа смарт-процесса. Для пользовательских смарт-процессов — любое положительное целое из `GET /v1/smart-processes`. Значения `1` (лиды), `2` (сделки), `3` (контакты), `4` (компании), `7` (предложения), `31` (счета) зарезервированы — используйте специализированные API: [/v1/deals](/docs/entities/deals/aggregate), [/v1/leads](/docs/entities/leads/aggregate) и т.д. | ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций. Каждый элемент: `{ "field": "opportunity", "function": "sum" }`. Функции: `count`, `sum`, `avg`, `min`, `max`. Для `count` поле — `"*"`. Без массива — только `count` | | `filter` | object | нет | Фильтрация по полям `GET /v1/items/:entityTypeId/fields`. [Синтаксис фильтрации](/docs/filtering) | | `groupBy` | string \| string[] | нет | Поле или массив полей для группировки (максимум 5). Принимает стандартные поля и UF-поля любого типа | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/items/177/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "opportunity", "function": "sum" }, { "field": "opportunity", "function": "avg" } ], "filter": { "categoryId": 7 }, "groupBy": "stageId" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/items/177/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "opportunity", "function": "sum" }, { "field": "opportunity", "function": "avg" } ], "filter": { "categoryId": 7 }, "groupBy": "stageId" }' ``` ### JavaScript — личный ключ ```javascript const entityTypeId = 177 const res = await fetch(`https://vibecode.bitrix24.tech/v1/items/${entityTypeId}/aggregate`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [ { field: 'opportunity', function: 'sum' }, { field: 'opportunity', function: 'avg' }, ], filter: { categoryId: 7 }, groupBy: 'stageId', }), }) const { success, data } = await res.json() console.log('Всего элементов:', data.count) console.log('По стадиям:', data.groups) ``` ### JavaScript — OAuth-приложение ```javascript const entityTypeId = 177 const res = await fetch(`https://vibecode.bitrix24.tech/v1/items/${entityTypeId}/aggregate`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [ { field: 'opportunity', function: 'sum' }, { field: 'opportunity', function: 'avg' }, ], filter: { categoryId: 7 }, groupBy: 'stageId', }), }) const { success, data } = await res.json() ``` > Для группировки по нескольким полям передайте массив: `"groupBy": ["stageId", "categoryId"]` (максимум 5). ## Другие сценарии Подсчёт записей — `count` с полем `"*"`, самый быстрый запрос без выгрузки записей. Без массива `aggregate` результат тот же: ```json { "aggregate": [{ "field": "*", "function": "count" }] } ``` Работа с пользовательскими полями (UF) — `sum` по UF + группировка по другому UF: ```json { "aggregate": [{ "field": "ufCrm7_1741091916816", "function": "sum" }], "groupBy": "ufCrm7_1652689362" } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Количество элементов, соответствующих фильтру | | `data.aggregates` | object | Результаты агрегаций: `{ "opportunity": { "sum": 65911, "avg": 4707.92 } }` | | `data.groups` | array | Группы (только при `groupBy`). Каждый элемент: поля группировки + `count` + `aggregates` | | `data.meta.totalRecords` | number | Общее количество записей под фильтр | | `data.meta.recordsProcessed` | number | Сколько записей было фактически обработано для агрегации | | `data.meta.truncated` | boolean | `true`, если под фильтр попало больше 5000 записей | | `data.meta.groupTotal` | number | Количество групп (только при `groupBy`) | | `data.meta.groupsTruncated` | boolean | `true`, если список групп был усечён | ## Пример ответа Ответ на основной запрос (агрегации + `groupBy: "stageId"`): ```json { "success": true, "data": { "count": 14, "aggregates": { "opportunity": { "sum": 65911, "avg": 4707.92 } }, "groups": [ { "stageId": "DT177_7:NEW", "count": 8, "aggregates": { "opportunity": { "sum": 40000 } } }, { "stageId": "DT177_7:SUCCESS", "count": 6, "aggregates": { "opportunity": { "sum": 25911 } } } ], "meta": { "totalRecords": 14, "recordsProcessed": 14, "truncated": false, "groupTotal": 2, "groupsTruncated": false } } } ``` Без `groupBy` поле `data.groups` в ответе отсутствует. ## Пример ответа при ошибке 400 — зарезервированный `entityTypeId` (для стандартных CRM-сущностей): ```json { "success": false, "error": { "code": "INVALID_DYNAMIC_PARAM", "message": "entityTypeId 2 has a dedicated API: use /v1/deals instead" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_DYNAMIC_PARAM` | `entityTypeId` не является положительным целым или является зарезервированным (1, 2, 3, 4, 7, 31) | | 400 | `INVALID_PARAMS` | Некорректное имя функции, несуществующее поле или нечисловое поле в `sum`/`avg`/`min`/`max` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Без массива `aggregate` — только `count`.** Если не передать `aggregate`, метод сделает один быстрый вызов в Битрикс24 и вернёт `count` записей под фильтр. Подходит для счётчиков на дашбордах. **Несколько агрегаций в одном запросе.** Можно объединить в одном вызове: `[{ "field": "opportunity", "function": "sum" }, { "field": "opportunity", "function": "avg" }]`. **Money-поля.** UF-поля типа `money` хранятся в формате `"сумма|валюта"` (`"1500|RUB"`) — агрегат извлекает числовую часть автоматически, складывать можно без парсинга. **Фильтрация по UF работает.** В `filter` можно передавать любые поля — стандартные и пользовательские, любого типа. Например, `{ "filter": { "ufCrm7_1652689362": 1435 } }` вернёт количество элементов с этим значением UF. **Ограничение 5000 записей.** Числовые агрегации подгружают записи постранично и считают на стороне Вайбкод. Если под фильтр попадает больше 5000 записей, результат будет помечен `meta.truncated: true` — берётся только первые 5000. Для точного количества используйте `count` (он работает на любом объёме) или сужайте фильтр. **Зарезервированные `entityTypeId`.** Значения `1` (лиды), `2` (сделки), `3` (контакты), `4` (компании), `7` (предложения), `31` (счета) обслуживаются специализированными API — используйте [/v1/deals/aggregate](/docs/entities/deals/aggregate), [/v1/leads/aggregate](/docs/entities/leads/aggregate), [/v1/contacts/aggregate](/docs/entities/contacts/aggregate), [/v1/companies/aggregate](/docs/entities/companies/aggregate), [/v1/quotes/aggregate](/docs/entities/quotes/aggregate), [/v1/invoices/aggregate](/docs/entities/invoices/aggregate). ## Смотрите также - [Список смарт-процессов](/docs/entities/smart-processes/list) - [Список элементов](/docs/entities/items/list) - [Поиск элементов](/docs/entities/items/search) - [Поля смарт-процесса](/docs/entities/items/fields) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Items: Create ## Создать элемент смарт-процесса `POST /v1/items/:entityTypeId` Создаёт новый элемент в указанном смарт-процессе. Параметр `entityTypeId` определяет тип смарт-процесса. Узнать доступные типы: `GET /v1/smart-processes`. ## Поля запроса (body) | Параметр | Тип | Описание | |----------|-----|---------| | `title` | string | Название | | `xmlId` | string | Внешний код | | `stageId` | string | Стадия. Формат: `DT{typeId}_{catId}:{stage}`. Список: `GET /v1/statuses?filter[entityId]=DYNAMIC_{entityTypeId}_STAGE_{categoryId}` | | `categoryId` | number | ID воронки. Список: `GET /v1/categories/:entityTypeId` | | `contactId` | number | ID контакта. Поиск: `GET /v1/contacts` | | `companyId` | number | ID компании. Поиск: `GET /v1/companies` | | `mycompanyId` | number | ID своей компании | | `assignedById` | number | Ответственный. Список: `GET /v1/users` | | `opportunity` | number | Сумма | | `currencyId` | string | Валюта. Список: `GET /v1/currencies` | | `opened` | boolean | Доступен для всех | | `begindate` | datetime | Дата начала. Принимает ISO 8601, но сохраняется только дата — время отбрасывается | | `closedate` | datetime | Дата завершения. Принимает ISO 8601, но сохраняется только дата — время отбрасывается | | `sourceId` | string | Источник | | `observers` | array | ID наблюдателей | Полный список полей: [GET /v1/items/:entityTypeId/fields](/docs/entities/items/fields). Пользовательские поля (`ufCrmN_*`) также принимаются. ## Примеры В примерах `entityTypeId = 156` — замените на ID вашего смарт-процесса. ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/items/156 \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Новый договор", "categoryId": 41, "assignedById": 1, "companyId": 15, "opportunity": 500000, "currencyId": "RUB" }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/items/156 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Новый договор", "categoryId": 41, "assignedById": 1, "companyId": 15, "opportunity": 500000, "currencyId": "RUB" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/156', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Новый договор', categoryId: 41, assignedById: 1, companyId: 15, opportunity: 500000, currencyId: 'RUB', }), }) const { success, data } = await res.json() console.log('Item ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/156', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Новый договор', categoryId: 41, assignedById: 1, companyId: 15, opportunity: 500000, currencyId: 'RUB', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID элемента | | `title` | string | Название | | `stageId` | string | Стадия | | `categoryId` | number | ID воронки | | `companyId` | number | ID компании | | `contactId` | number | ID контакта | | `opportunity` | number | Сумма | | `currencyId` | string | Валюта | | `assignedById` | number | Ответственный | | `createdBy` | number | Создатель | | `createdTime` | datetime | Дата создания | | `updatedTime` | datetime | Дата изменения | Ответ содержит все поля элемента, включая пользовательские (`ufCrmN_*`). URL карточки элемента в Битрикс24 строится из `id`: ``` https://.bitrix24.ru/crm/type//details// ``` `` — ID типа смарт-процесса (тот же, что в пути запроса). `` — домен портала. Если смарт-процесс вынесен в отдельный раздел портала, Битрикс24 откроет карточку по соответствующему пути. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": { "id": 783, "title": "Новый договор", "stageId": "DT156_41:NEW", "categoryId": 41, "companyId": 15, "contactId": null, "opportunity": 500000, "currencyId": "RUB", "assignedById": 1, "createdBy": 1, "createdTime": "2026-04-15T14:30:00+03:00", "updatedTime": "2026-04-15T14:30:00+03:00" } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_DYNAMIC_PARAM` | `entityTypeId` не является положительным целым или является зарезервированным (1, 2, 3, 4, 7, 31) | | 400 | `READONLY_FIELD` | В теле передано поле только для чтения (`id`, `createdTime`, `updatedTime` и другие) | | 400 | `CLIENT_BLOCK_DISABLED` | В теле передан клиент (`contactId`, `contactIds` или `companyId`), а у смарт-процесса выключен блок «Клиент». Проверить: `GET /v1/smart-processes/:entityTypeId`, поле `isClientEnabled` | | 422 | `BITRIX_ERROR` | Ошибка валидации полей от Битрикс24. Конкретная причина — в поле `message` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Работа с файлами в полях CRM](/docs/recipes/crm-files) - [Список элементов](/docs/entities/items/list) - [Поля элемента](/docs/entities/items/fields) - [Смарт-процессы](/docs/entities/smart-processes) - [Контакты](/docs/entities/contacts) - [Компании](/docs/entities/companies) - [Entity API](/docs/entity-api) --- # Items: Delete ## Удалить элемент `DELETE /v1/items/:entityTypeId/:id` Удаляет элемент смарт-процесса по ID. Восстановить удалённый элемент через API нельзя — создавайте новый при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `entityTypeId` (path) | number | да | ID типа смарт-процесса. Получить: [GET /v1/smart-processes](/docs/entities/smart-processes/list). Зарезервированные значения (`1`, `2`, `3`, `4`, `7`, `31`) обслуживаются специализированными API: `/v1/leads`, `/v1/deals`, `/v1/contacts`, `/v1/companies`, `/v1/quotes`, `/v1/invoices` | | `id` (path) | number | да | ID элемента | ## Примеры В примерах `entityTypeId = 177`, `id = 783` — замените на ваши значения. ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/items/177/783" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/items/177/783" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/177/783', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) if (res.status === 204) { console.log('Элемент удалён') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/177/783', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 400 — зарезервированный `entityTypeId` (для стандартных CRM-сущностей): ```json { "success": false, "error": { "code": "INVALID_DYNAMIC_PARAM", "message": "entityTypeId 2 has a dedicated API: use /v1/deals instead" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_DYNAMIC_PARAM` | `entityTypeId` не является положительным целым или является зарезервированным (1, 2, 3, 4, 7, 31) | | 404 | `ENTITY_NOT_FOUND` | Элемент с указанным ID не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список элементов](/docs/entities/items/list) - [Создать элемент](/docs/entities/items/create) - [Смарт-процессы](/docs/entities/smart-processes/list) - [Лимиты и оптимизация](/docs/optimization) --- # Items: Fields ## Поля элемента смарт-процесса `GET /v1/items/:entityTypeId/fields` Возвращает описание всех полей для указанного типа смарт-процесса, включая пользовательские (`ufCrmN_*`) и родительские ссылки (`parentIdN`). Набор полей зависит от `entityTypeId` — каждый тип смарт-процесса имеет собственные пользовательские поля. ## Примеры В примерах `entityTypeId = 156` — замените на ID вашего смарт-процесса. ### curl — личный ключ ```bash curl -X GET https://vibecode.bitrix24.tech/v1/items/156/fields \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X GET https://vibecode.bitrix24.tech/v1/items/156/fields \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/156/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/156/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Только чтение | Описание | |------|-----|:---:|---------| | `id` | number | да | ID элемента | | `title` | string | | Название | | `xmlId` | string | | Внешний код | | `stageId` | string | | Стадия. Формат: `DT{typeId}_{catId}:{stage}` | | `categoryId` | number | | ID воронки. Список: `GET /v1/categories/:entityTypeId` | | `assignedById` | number | | Ответственный. Список: `GET /v1/users` | | `companyId` | number | | ID компании. Поиск: `GET /v1/companies`. Требует включённого блока «Клиент» у смарт-процесса, иначе `400 CLIENT_BLOCK_DISABLED` | | `contactId` | number | | ID контакта. Поиск: `GET /v1/contacts`. Требует включённого блока «Клиент» у смарт-процесса, иначе `400 CLIENT_BLOCK_DISABLED` | | `contactIds` | array | | Привязанные контакты. Передавайте полный список — набор привязок заменяется целиком, а не дополняется. Требует включённого блока «Клиент» у смарт-процесса, иначе `400 CLIENT_BLOCK_DISABLED` | | `opportunity` | number | | Сумма | | `currencyId` | string | | Валюта. Список: `GET /v1/currencies` | | `opened` | boolean | | Доступен для всех | | `begindate` | datetime | | Дата начала. Хранится без времени — переданное время отбрасывается | | `closedate` | datetime | | Дата завершения. Хранится без времени — переданное время отбрасывается | | `sourceId` | string | | Источник | | `observers` | array | | Наблюдатели | | `mycompanyId` | number | | ID своей компании | | `createdBy` | number | да | Создатель | | `updatedBy` | number | да | Последний редактор | | `movedBy` | number | да | Переместил стадию | | `createdTime` | datetime | да | Дата создания | | `updatedTime` | datetime | да | Дата изменения | | `movedTime` | datetime | да | Дата смены стадии | | `isManualOpportunity` | boolean | | Сумма задана вручную (`Y`/`N` → `true`/`false`) | | `isRecurring` | boolean | да | Признак регулярного элемента | | `lastActivityTime` | datetime | да | Время последней активности | | `entityTypeId` | number | да | ID типа смарт-процесса. Берётся из сегмента пути, в теле запроса не принимается | | `utmSource` | string \| null | да | Метка `utm_source` источника трафика | | `utmMedium` | string \| null | да | Метка `utm_medium` — канал трафика, например `cpc` или `email` | | `utmCampaign` | string \| null | да | Метка `utm_campaign` — название рекламной кампании | | `utmContent` | string \| null | да | Метка `utm_content` — содержание или вариант объявления | | `utmTerm` | string \| null | да | Метка `utm_term` — ключевое слово объявления | UTM-поля Битрикс24 отдаёт в `list`/`get`, но у элементов смарт-процессов не принимает их ни в теле запроса, ни в фильтре, ни в сортировке — поэтому они помечены «только чтение», а запрос с `filter[utmSource]` возвращает ошибку. `isManualOpportunity` и `isRecurring` приходят от Битрикс24 строкой `"Y"`/`"N"` — платформа нормализует их в JSON-`boolean` на чтении (и принимает `true`/`false` на запись для `isManualOpportunity`), как и `opened`. Пользовательские поля (`ufCrmN_*`) и родительские ссылки (`parentIdN`) зависят от конкретного смарт-процесса. Для полей типа `enumeration` ответ содержит массив `items` с доступными значениями. > **Нульность.** Многие поля приходят `null`, когда не заполнены — в частности `xmlId`, `sourceDescription`, `lastActivityTime` и UTM-поля (`utmSource`/`utmMedium`/`utmCampaign`/`utmContent`/`utmTerm`, если включены на портале). Типобезопасным клиентам (TS) объявляйте такие поля как `T | null`. > ⚠ **`/fields` отражает живой контракт Битрикс24, а не форму платформенных доков.** Это сквозной проброс схемы полей Битрикс24 как есть: типы приходят в нотации Битрикс24 (`number`, `string`, `boolean`, `datetime`, `double`, `enumeration`, `crm_contact`, `crm_status`, `user` и другие), флаг — `readonly` (а не `isReadOnly`), у части полей есть `label`, отдельного `isRequired` или `title` нет. Привязанные контакты читаются и пишутся через `contactId` и `contactIds`. Служебное поле `contacts` из схемы Битрикс24 платформа в справочнике **не показывает**: значения по нему не приходит ни в списке, ни в карточке, а на запись Битрикс24 принимает только пустой массив — любое непустое значение он отклоняет ошибкой своего внутреннего слоя данных. Поле было бы обещанием, которое нечем выполнить. Системные поля, которые Битрикс24 отдаёт в list/get, но не описаны выше (`taxValue`, `previousStageId`, `lastActivityBy`, `lastCommunication*`), проходят сквозным проксированием. Поля из таблицы выше платформа описывает сама, поэтому у них есть человекочитаемые `label` и `description`. ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true }, "title": { "type": "string", "readonly": false }, "stageId": { "type": "string", "readonly": false }, "begindate": { "type": "datetime", "readonly": false }, "ufCrm156_custom": { "type": "string", "readonly": false }, "parentId156": { "type": "number", "readonly": false } } } } ``` Поля приходят внутри `data.fields`. Объект ответа также содержит `data.products` (схема товарных строк), `data.aggregatable` (поля, доступные в [агрегации](/docs/entities/items/aggregate)) и `data.batch`. ## Пример ответа при ошибке 404 — не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 400 | `INVALID_DYNAMIC_PARAM` | `entityTypeId` не является положительным целым или является зарезервированным (1, 2, 3, 4, 7, 31) | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать элемент](/docs/entities/items/create) - [Список элементов](/docs/entities/items/list) - [Смарт-процессы](/docs/entities/smart-processes) - [Entity API](/docs/entity-api) --- # Items: Get ## Получить элемент смарт-процесса `GET /v1/items/:entityTypeId/:id` Возвращает элемент смарт-процесса по ID. ## Параметры запроса | Параметр | Тип | Описание | |----------|-----|---------| | `entityTypeId` | number | ID типа смарт-процесса (в URL) | | `id` | number | ID элемента (в URL) | ## Примеры В примерах `entityTypeId = 156`, `id = 783` — замените на ваши значения. ### curl — личный ключ ```bash curl -X GET https://vibecode.bitrix24.tech/v1/items/156/783 \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X GET https://vibecode.bitrix24.tech/v1/items/156/783 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/156/783', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() console.log('Элемент:', data.title) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/156/783', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID элемента | | `title` | string | Название | | `xmlId` | string | Внешний код | | `stageId` | string | Стадия | | `categoryId` | number | ID воронки | | `companyId` | number | ID компании | | `contactId` | number | ID контакта | | `contactIds` | array | Привязанные контакты | | `opportunity` | number | Сумма | | `currencyId` | string | Валюта | | `opened` | boolean | Доступен для всех | | `assignedById` | number | Ответственный | | `createdBy` | number | Создатель | | `updatedBy` | number | Последний редактор | | `movedBy` | number | Переместил стадию | | `createdTime` | datetime | Дата создания | | `updatedTime` | datetime | Дата изменения | | `movedTime` | datetime | Дата смены стадии | | `observers` | array | Наблюдатели | Ответ содержит все поля элемента, включая пользовательские (`ufCrmN_*`) и родительские ссылки (`parentIdN`). ## Пример ответа ```json { "success": true, "data": { "id": 783, "title": "Договор на поставку", "xmlId": null, "stageId": "DT156_41:NEW", "categoryId": 41, "companyId": 15, "contactId": 42, "contactIds": [42], "opportunity": 500000, "currencyId": "RUB", "opened": true, "assignedById": 1, "createdBy": 1, "updatedBy": 1, "movedBy": 1, "createdTime": "2026-04-15T14:30:00+03:00", "updatedTime": "2026-04-15T14:30:00+03:00", "movedTime": "2026-04-15T14:30:00+03:00", "observers": [1, 5], "mycompanyId": 0 } } ``` ## Пример ответа при ошибке 404 — элемент не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_DYNAMIC_PARAM` | `entityTypeId` не является положительным целым или является зарезервированным (1, 2, 3, 4, 7, 31) | | 404 | `ENTITY_NOT_FOUND` | Элемент с указанным ID не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Работа с файлами в полях CRM](/docs/recipes/crm-files) - [Список элементов](/docs/entities/items/list) - [Обновить элемент](/docs/entities/items/update) - [Поля элемента](/docs/entities/items/fields) - [Смарт-процессы](/docs/entities/smart-processes) - [Entity API](/docs/entity-api) --- # Items: List ## Список элементов смарт-процесса `GET /v1/items/:entityTypeId` Возвращает список элементов указанного смарт-процесса с фильтрацией, сортировкой и пагинацией. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `entityTypeId` (path) | number | — | ID типа смарт-процесса. Список: `GET /v1/smart-processes` | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей. Для обхода всей коллекции дешевле курсор — `order[id]=asc` и `filter[>id]` из `meta.nextAfterId` | | `order` | object | — | Сортировка: `?order[createdTime]=desc` | | `select` | string | — | Выборка полей: `?select=id,title,stageId` | | `filter` | object | — | Фильтрация по полям `GET /v1/items/:entityTypeId/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[assignedById]=1` | | `withTotal` | string | — | Нужно ли количество: `true` или `false`. `false` — не заказывать подсчёт. Это единственный способ гарантированно убрать `meta.total` из ответа. Без параметра — настройка ключа, затем платформенное умолчание, и тогда на короткой странице точное количество приходит и без заказа. [Листание и количество](/docs/entity-api#листание-и-количество-записей) | ## Примеры В примерах `entityTypeId = 156` — замените на ID вашего смарт-процесса. ### curl — личный ключ ```bash curl -X GET "https://vibecode.bitrix24.tech/v1/items/156?limit=10&order[createdTime]=desc&filter[assignedById]=1" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X GET "https://vibecode.bitrix24.tech/v1/items/156?limit=10&order[createdTime]=desc&filter[assignedById]=1" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const params = new URLSearchParams({ limit: '10', 'order[createdTime]': 'desc', 'filter[assignedById]': '1', }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/items/156?${params}`, { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data, meta } = await res.json() console.log(`Найдено: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const params = new URLSearchParams({ limit: '10', 'order[createdTime]': 'desc', 'filter[assignedById]': '1', }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/items/156?${params}`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа Пагинация возвращается в объекте `meta` (как у всех списочных эндпоинтов платформы), **не** на верхнем уровне. | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив элементов | | `meta.total` | number | Общее количество записей. Необязательное поле: если количество не заказывалось, его в ответе нет | | `meta.hasMore` | boolean | Есть ли ещё страницы | | `meta.nextAfterId` | string | Идентификатор последней отданной записи. Приходит при сортировке строго по `id` по возрастанию, пока `hasMore` равен `true`. Передайте его обратно как `filter[>id]` — это дешёвая замена растущему `offset` | | `data[].id` | number | ID элемента | | `data[].title` | string | Название | | `data[].stageId` | string | Стадия | | `data[].categoryId` | number | ID воронки | | `data[].opportunity` | number | Сумма | | `data[].currencyId` | string | Валюта | | `data[].assignedById` | number | Ответственный | | `data[].createdTime` | datetime | Дата создания | URL карточки любого элемента из массива `data` — его `id`: ``` https://.bitrix24.ru/crm/type//details// ``` `` — ID типа смарт-процесса (тот же, что в пути запроса). `` — домен портала. Если смарт-процесс вынесен в отдельный раздел портала, Битрикс24 откроет карточку по соответствующему пути. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 783, "title": "Договор на поставку", "stageId": "DT156_41:NEW", "categoryId": 41, "companyId": 15, "contactId": 42, "opportunity": 500000, "currencyId": "RUB", "assignedById": 1, "createdBy": 1, "createdTime": "2026-04-15T14:30:00+03:00", "updatedTime": "2026-04-15T14:30:00+03:00" } ], "meta": { "total": 23, "hasMore": true } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 400 | `INVALID_DYNAMIC_PARAM` | `entityTypeId` не является положительным целым или является зарезервированным (1, 2, 3, 4, 7, 31) | | 400 | `UNKNOWN_FILTER_FIELD` | Поле фильтра не существует у сущности — сообщение перечисляет доступные поля | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить элемент](/docs/entities/items/get) - [Поиск элементов](/docs/entities/items/search) - [Поля элемента](/docs/entities/items/fields) - [Смарт-процессы](/docs/entities/smart-processes) - [Entity API](/docs/entity-api) - [Лимиты и оптимизация](/docs/optimization) --- # Items: Products Add > Поле, которого нет среди записываемых, больше не отбрасывается молча — запрос отклоняется с `400 INVALID_PARAMS`, и в тексте ошибки перечислены записываемые имена. Поля только для чтения, которые приходят в ответах товарных позиций (`priceAccount`, `ownerId`, `storeId` и другие) по-прежнему принимаются и игнорируются, поэтому объект, прочитанный через GET, можно отправить обратно без чистки. ## Добавить товар в элемент смарт-процесса `POST /v1/items/:entityTypeId/:id/products` Добавляет одну товарную позицию в элемент смарт-процесса. В отличие от `PUT /v1/items/:entityTypeId/:id/products`, не заменяет существующие позиции. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `entityTypeId` (path) | number | да | ID типа смарт-процесса | | `id` (path) | number | да | ID элемента | | `productId` | number | нет | ID товара из каталога. Если задан без `productName`, имя подставляется из каталога. Каталог: `GET /v1/products` | | `productName` | string | нет | Название товарной позиции — для произвольной строки без товара из каталога. Укажите хотя бы одно из `productId` / `productName`. | | `price` | number | нет | Цена за единицу | | `quantity` | number | нет | Количество | | `discount` | number | нет | Сумма скидки | | `taxRate` | number | нет | Ставка налога (%) | | `taxIncluded` | boolean | нет | Налог включён в цену | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/items/180/47/products" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "productId": 1, "price": 25000, "quantity": 2 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/items/180/47/products" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "productId": 1, "price": 25000, "quantity": 2 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/180/47/products', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ productId: 1, price: 25000, quantity: 2 }), }) const { success, data } = await res.json() console.log('ID строки:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/180/47/products', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ productId: 1, price: 25000, quantity: 2 }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | object | Созданная товарная строка целиком, HTTP-статус `201`. Состав полей — [Поля товаров](/docs/entities/items/products-fields) | ## Пример ответа Показаны основные поля. Полный список — [Поля товаров](/docs/entities/items/products-fields). ```json { "success": true, "data": { "id": 1465, "productId": 1, "productName": "Серверное оборудование", "price": 25000, "quantity": 2, "discount": 0, "discountTypeId": 2, "taxIncluded": false } } ``` ## Пример ответа при ошибке 404 — элемент не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Тело содержит имя, которого нет среди записываемых полей — см. [Поля товаров](/docs/entities/items/products-fields) | | 400 | `INVALID_DYNAMIC_PARAM` | `entityTypeId` не является положительным целым или является зарезервированным (1, 2, 3, 4, 7, 31) | | 400 | `INVALID_PARAMS` | Тело запроса не объект или не содержит распознанных полей товарной строки | | 404 | `ENTITY_NOT_FOUND` | Элемент не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Товарные позиции](/docs/entities/items/products-get) - [Установить товары](/docs/entities/items/products-set) - [Удалить товар](/docs/entities/items/products-delete) - [Товары каталога](/docs/entities/products) --- # Items: Products Delete ## Удалить товар из элемента смарт-процесса `DELETE /v1/items/:entityTypeId/:id/products/:rowId` Удаляет одну товарную позицию из элемента смарт-процесса по ID строки. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `entityTypeId` (path) | number | да | ID типа смарт-процесса | | `id` (path) | number | да | ID элемента | | `rowId` (path) | number | да | ID товарной строки (из ответа add или list) | `rowId` — это ID товарной строки, а не `productId` из каталога товаров. ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/items/180/47/products/1465" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/items/180/47/products/1465" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/180/47/products/1465', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Товар удалён') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/180/47/products/1465', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Товар удалён') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — элемент не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_DYNAMIC_PARAM` | `entityTypeId` не является положительным целым или является зарезервированным (1, 2, 3, 4, 7, 31) | | 400 | `INVALID_ROW_ID` | `rowId` не является положительным целым | | 404 | `ENTITY_NOT_FOUND` | Элемент или товарная строка не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Товарные позиции](/docs/entities/items/products-get) - [Добавить товар](/docs/entities/items/products-add) - [Установить товары](/docs/entities/items/products-set) - [Товары каталога](/docs/entities/products) --- # Items: Products Fields ## Поля товаров элемента `GET /v1/items/:entityTypeId/:id/products/fields` Возвращает описание полей товарных позиций элемента: названия, типы, доступность для чтения и записи. > **Сумма скидки называется `discount`** — как в данных и при записи. Прежнее имя `discountSum` осталось устаревшим псевдонимом: оно по-прежнему приходит в этом справочнике и принимается при записи, поэтому код, написанный по старому списку полей, продолжает работать. В самих товарных позициях приходит только `discount` — переходите на него. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `entityTypeId` (path) | number | да | ID типа смарт-процесса | | `id` (path) | number | да | ID элемента | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/items/156/741/products/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/items/156/741/products/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/156/741/products/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/156/741/products/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | RO | Обяз. | Описание | |------|-----|:--:|:-----:|---------| | `id` | integer | да | | ID позиции | | `productId` | integer | | да | ID товара. Каталог: `GET /v1/products` | | `productName` | string | | | Название товара | | `price` | double | | | Цена | | `quantity` | double | | | Количество | | `discount` | double | | | Сумма скидки | | `discountSum` | double | | | Устаревший псевдоним `discount` — принимается при записи, в товарных позициях не приходит | | `discountRate` | double | | | Величина скидки (%) | | `discountTypeId` | integer | | | Тип скидки | | `taxRate` | double | | | Налог (%) | | `taxIncluded` | char | | | Налог включён в цену (`Y`/`N`) | | `priceExclusive` | double | да | | Цена без налога со скидкой | | `priceNetto` | double | да | | Цена нетто | | `priceBrutto` | double | да | | Цена брутто | | `measureCode` | integer | | | Код единицы измерения | | `measureName` | string | да | | Единица измерения | | `customized` | char | да | | Изменён (`Y`/`N`) | | `sort` | integer | | | Сортировка | | `type` | integer | да | | Тип | | `storeId` | integer | да | | ID склада | | `ownerId` | integer | да | | ID владельца (элемента) | | `ownerType` | string | да | | Тип владельца | | `priceAccount` | double | да | | Цена в валюте отчёта | | `xmlId` | string | да | | Внешний код позиции | ## Пример ответа Показаны 6 полей из 24 (23 имени товарной позиции плюс устаревший псевдоним `discountSum`). Каждое поле описано ключами `type`, `isRequired`, `isReadOnly`, `isImmutable`, `isMultiple`, `isDynamic`, `title`. Полный список полей — в таблице выше. ```json { "success": true, "data": { "id": { "type": "integer", "isRequired": false, "isReadOnly": true, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "ID", "description": "Row identity. Read-only as an attribute; echo it back in PUT /products items to update a row in place instead of recreating it." }, "ownerId": { "type": "integer", "isRequired": false, "isReadOnly": true, "isImmutable": true, "isMultiple": false, "isDynamic": false, "title": "ID владельца" }, "ownerType": { "type": "string", "isRequired": false, "isReadOnly": true, "isImmutable": true, "isMultiple": false, "isDynamic": false, "title": "Тип владельца" }, "productId": { "type": "integer", "isRequired": true, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Товар" }, "price": { "type": "double", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Цена" }, "priceExclusive": { "type": "double", "isRequired": false, "isReadOnly": true, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Цена без налога со скидкой" } } } ``` ## Пример ответа при ошибке 404 — элемент не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_DYNAMIC_PARAM` | `entityTypeId` не является положительным целым или является зарезервированным (1, 2, 3, 4, 7, 31) | | 404 | `ENTITY_NOT_FOUND` | Элемент не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Товарные позиции](/docs/entities/items/products-get) - [Добавить товар](/docs/entities/items/products-add) - [Установить товары](/docs/entities/items/products-set) - [Поля элемента](/docs/entities/items/fields) --- # Items: Products Get ## Товарные позиции элемента `GET /v1/items/:entityTypeId/:id/products` Возвращает список товарных позиций, привязанных к элементу смарт-процесса. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `entityTypeId` (path) | number | да | ID типа смарт-процесса | | `id` (path) | number | да | ID элемента | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/items/156/741/products" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/items/156/741/products" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/156/741/products', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Товаров:', data.length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/156/741/products', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив товарных позиций | | `data[].productId` | number | ID товара. Каталог: `GET /v1/products` | | `data[].productName` | string | Название товара | | `data[].price` | number | Цена за единицу | | `data[].quantity` | number | Количество | | `data[].discount` | number | Сумма скидки | | `data[].taxRate` | number/null | Ставка налога (%) | | `data[].taxIncluded` | boolean | Налог включён в цену | Показаны основные поля. Полный список — [Поля товаров](/docs/entities/items/products-fields). ## Пример ответа ```json { "success": true, "data": [ { "productId": 1, "productName": "Серверное оборудование", "price": 1000, "quantity": 2, "discount": 0, "taxRate": null, "taxIncluded": false } ] } ``` ## Пример ответа при ошибке 404 — элемент не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_DYNAMIC_PARAM` | `entityTypeId` не является положительным целым или является зарезервированным (1, 2, 3, 4, 7, 31) | | 404 | `ENTITY_NOT_FOUND` | Элемент не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Установить товары](/docs/entities/items/products-set) - [Получить элемент](/docs/entities/items/get) - [Товары каталога](/docs/entities/products) - [Лимиты и оптимизация](/docs/optimization) --- # Items: Products Get Single ## Получить товар из элемента `GET /v1/items/:entityTypeId/:id/products/:rowId` Возвращает одну товарную позицию элемента по ID строки. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `entityTypeId` (path) | number | да | ID типа смарт-процесса | | `id` (path) | number | да | ID элемента | | `rowId` (path) | number | да | ID товарной строки (из ответа add или list) | `rowId` — это ID товарной строки, а не `productId` из каталога товаров. ## Примеры ### curl — личный ключ ```bash curl -X GET "https://vibecode.bitrix24.tech/v1/items/156/741/products/1471" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X GET "https://vibecode.bitrix24.tech/v1/items/156/741/products/1471" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/156/741/products/1471', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Цена:', data.price) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/156/741/products/1471', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.id` | number | ID товарной строки | | `data.productId` | number | ID товара. Каталог: `GET /v1/products` | | `data.productName` | string | Название товара | | `data.price` | number | Цена за единицу | | `data.quantity` | number | Количество | | `data.discount` | number | Сумма скидки | | `data.discountRate` | number | Процент скидки | | `data.discountTypeId` | number | Тип скидки (1 — сумма, 2 — процент) | | `data.taxRate` | number \| null | Ставка налога (%) | | `data.taxIncluded` | boolean | Налог включён в цену | | `data.priceExclusive` | number | Цена без налога со скидкой | | `data.priceNetto` | number | Цена нетто | | `data.priceBrutto` | number | Цена брутто | | `data.priceAccount` | number | Цена в валюте учёта | | `data.measureCode` | number | Код единицы измерения | | `data.measureName` | string | Название единицы измерения | | `data.sort` | number | Сортировка | | `data.ownerId` | number | ID сущности-владельца, которой принадлежит позиция | | `data.ownerType` | string | Код типа владельца (`D` у сделок, `T` у смарт-процессов) | | `data.storeId` | number \| null | ID склада; `null`, если складской учёт выключен | ## Пример ответа ```json { "success": true, "data": { "id": 1471, "productId": 1, "productName": "День добрый!", "price": 5000, "priceAccount": 5000, "priceExclusive": 5000, "priceNetto": 5000, "priceBrutto": 5000, "quantity": 3, "discountTypeId": 2, "discountRate": 0, "discount": 0, "taxRate": null, "taxIncluded": false, "customized": "Y", "measureCode": 796, "measureName": "шт", "sort": 0, "ownerId": 741, "ownerType": "D", "storeId": 3, "xmlId": "sale_basket_995", "type": 1 } } ``` ## Пример ответа при ошибке 404 — элемент или товарная строка не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_DYNAMIC_PARAM` | `entityTypeId` не является положительным целым или является зарезервированным (1, 2, 3, 4, 7, 31) | | 400 | `INVALID_ROW_ID` | `rowId` не является положительным целым | | 404 | `ENTITY_NOT_FOUND` | Элемент или товарная строка не найдена | | 404 | `NOT_FOUND` | Битрикс24 вернул успех, но товарная строка отсутствует (`Product row not found`) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Товарные позиции](/docs/entities/items/products-get) - [Обновить товар](/docs/entities/items/products-update) - [Добавить товар](/docs/entities/items/products-add) - [Удалить товар](/docs/entities/items/products-delete) - [Товары каталога](/docs/entities/products) --- # Items: Products Set > Поле, которого нет среди записываемых, больше не отбрасывается молча — запрос отклоняется с `400 INVALID_PARAMS`, и в тексте ошибки перечислены записываемые имена. Поля только для чтения, которые приходят в ответах товарных позиций (`priceAccount`, `ownerId`, `storeId` и другие) по-прежнему принимаются и игнорируются, поэтому объект, прочитанный через GET, можно отправить обратно без чистки. > Сохраняйте `id` у элемента, чтобы обновить существующую строку на месте: без него строка будет создана заново с новым идентификатором. ## Установить товары элемента смарт-процесса `PUT /v1/items/:entityTypeId/:id/products` Устанавливает товарные позиции элемента смарт-процесса. Полностью заменяет текущий список — передайте все нужные позиции. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `entityTypeId` (path) | number | да | ID типа смарт-процесса | | `id` (path) | number | да | ID элемента | | `items` | array | да | Массив товарных позиций | | `items[].productId` | number | да | ID товара. Каталог: `GET /v1/products` | | `items[].price` | number | да | Цена за единицу | | `items[].quantity` | number | да | Количество | | `items[].discount` | number | нет | Сумма скидки | | `items[].taxRate` | number | нет | Ставка налога (%) | | `items[].taxIncluded` | boolean | нет | Налог включён в цену | ## Примеры ### curl — личный ключ ```bash curl -X PUT "https://vibecode.bitrix24.tech/v1/items/180/47/products" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "items": [ { "productId": 1, "price": 25000, "quantity": 2 }, { "productId": 5, "price": 5000, "quantity": 1, "discount": 500 } ] }' ``` ### curl — OAuth-приложение ```bash curl -X PUT "https://vibecode.bitrix24.tech/v1/items/180/47/products" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "items": [ { "productId": 1, "price": 25000, "quantity": 2 }, { "productId": 5, "price": 5000, "quantity": 1, "discount": 500 } ] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/180/47/products', { method: 'PUT', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ items: [ { productId: 1, price: 25000, quantity: 2 }, { productId: 5, price: 5000, quantity: 1, discount: 500 }, ], }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/180/47/products', { method: 'PUT', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ items: [ { productId: 1, price: 25000, quantity: 2 }, { productId: 5, price: 5000, quantity: 1, discount: 500 }, ], }), }) const { success, data } = await res.json() ``` ## Поля ответа Массив установленных позиций с полями `productId`, `productName`, `price`, `quantity`, `discount`, `taxRate`, `taxIncluded`. ## Пример ответа ```json { "success": true, "data": [ { "productId": 1, "productName": "Серверное оборудование", "price": 25000, "quantity": 2, "discount": 0, "taxRate": null, "taxIncluded": false }, { "productId": 5, "productName": "Установка и настройка", "price": 5000, "quantity": 1, "discount": 500, "taxRate": null, "taxIncluded": false } ] } ``` ## Пример ответа при ошибке 400 — неверный формат: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "items must be an array" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Тело содержит имя, которого нет среди записываемых полей — см. [Поля товаров](/docs/entities/items/products-fields) | | 400 | `INVALID_DYNAMIC_PARAM` | `entityTypeId` не является положительным целым или является зарезервированным (1, 2, 3, 4, 7, 31) | | 400 | `INVALID_PARAMS` | `items` не является массивом или элемент массива не является объектом товарной строки | | 404 | `ENTITY_NOT_FOUND` | Элемент не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Полная замена:** PUT заменяет весь список товаров. Чтобы добавить позицию — сначала получите текущие (`GET`), добавьте новую в массив, отправьте всё (`PUT`). ## Смотрите также - [Товарные позиции](/docs/entities/items/products-get) - [Получить элемент](/docs/entities/items/get) - [Товары каталога](/docs/entities/products) - [Лимиты и оптимизация](/docs/optimization) --- # Items: Products Update > Поле, которого нет среди записываемых, больше не отбрасывается молча — запрос отклоняется с `400 INVALID_PARAMS`, и в тексте ошибки перечислены записываемые имена. Поля только для чтения, которые приходят в ответах товарных позиций (`priceAccount`, `ownerId`, `storeId` и другие) по-прежнему принимаются и игнорируются, поэтому объект, прочитанный через GET, можно отправить обратно без чистки. ## Обновить товар элемента `PATCH /v1/items/:entityTypeId/:id/products/:rowId` Обновляет товарную позицию элемента. Передайте только изменяемые поля. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `entityTypeId` (path) | number | да | ID типа смарт-процесса | | `id` (path) | number | да | ID элемента | | `rowId` (path) | number | да | ID товарной позиции (из ответа list или add, не productId из каталога) | ## Поля запроса (body) | Параметр | Тип | Описание | |----------|-----|---------| | `price` | number | Цена за единицу | | `quantity` | number | Количество | | `productId` | number | ID товара. Каталог: `GET /v1/products` | | `discount` | number | Сумма скидки | | `taxRate` | number | Ставка налога (%) | | `taxIncluded` | boolean | Налог включён в цену | | `sort` | number | Сортировка | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/items/156/741/products/1471" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "price": 9999, "quantity": 10 }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/items/156/741/products/1471" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "price": 9999, "quantity": 10 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/156/741/products/1471', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ price: 9999, quantity: 10 }), }) const { success, data } = await res.json() console.log('Обновлено:', data.price, 'x', data.quantity) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/156/741/products/1471', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ price: 9999, quantity: 10 }), }) const { success, data } = await res.json() ``` ## Поля ответа Обновлённый объект товарной позиции: `id`, `productId`, `productName`, `price`, `quantity`, `discount`, `taxRate`, `taxIncluded`. ## Пример ответа ```json { "success": true, "data": { "id": 1471, "productId": 1, "productName": "Серверное оборудование", "price": 9999, "quantity": 10, "discount": 0, "taxRate": null, "taxIncluded": false } } ``` ## Пример ответа при ошибке 404 — позиция не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Тело содержит имя, которого нет среди записываемых полей — см. [Поля товаров](/docs/entities/items/products-fields) | | 400 | `INVALID_DYNAMIC_PARAM` | `entityTypeId` не является положительным целым или является зарезервированным (1, 2, 3, 4, 7, 31) | | 400 | `INVALID_ROW_ID` | `rowId` не является положительным целым | | 400 | `INVALID_PARAMS` | Тело запроса не объект или не содержит распознанных полей товарной строки | | 404 | `ENTITY_NOT_FOUND` | Позиция не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить товар](/docs/entities/items/products-get-single) - [Получить товары](/docs/entities/items/products-get) - [Добавить товар](/docs/entities/items/products-add) - [Лимиты и оптимизация](/docs/optimization) --- # Items: Search ## Поиск элементов смарт-процесса `POST /v1/items/:entityTypeId/search` Расширенный поиск элементов с фильтрацией, сортировкой и авто-пагинацией. Поддерживает до 5000 записей. ## Поля запроса (body) | Параметр | Тип | Описание | |----------|-----|---------| | `filter` | object | Фильтрация по полям `GET /v1/items/:entityTypeId/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "filter": { "assignedById": 1 } }` | | `sort` | string | Сортировка. Префикс `-` — по убыванию | | `limit` | number | Количество записей (по умолчанию 50, макс. 5000) | | `offset` | number | Пропустить N записей. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки» | | `select` | array | Список возвращаемых полей | | `autoWindow` | boolean | Разбивать выборку по недельным окнам при фильтре по диапазону дат шире 14 дней. По умолчанию `true`. `false` отключает разбиение | ### Синтаксис фильтров Поддерживаются три формата: ```json { "filter": { ">=opportunity": 100000 } } { "filter": { "opportunity": { "$gte": 100000 } } } { "filter": { "opportunity": { ">=": 100000 } } } ``` ## Примеры В примерах `entityTypeId = 156` — замените на ID вашего смарт-процесса. ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/items/156/search \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "assignedById": 1, "stageId": "DT156_41:NEW" }, "select": ["id", "title", "opportunity", "stageId"], "sort": "-createdTime", "limit": 100 }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/items/156/search \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "assignedById": 1, "stageId": "DT156_41:NEW" }, "select": ["id", "title", "opportunity", "stageId"], "sort": "-createdTime", "limit": 100 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/156/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { assignedById: 1, stageId: 'DT156_41:NEW' }, select: ['id', 'title', 'opportunity', 'stageId'], sort: '-createdTime', limit: 100, }), }) const { success, data, meta } = await res.json() console.log(`Найдено: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/156/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { assignedById: 1, stageId: 'DT156_41:NEW' }, select: ['id', 'title', 'opportunity', 'stageId'], sort: '-createdTime', limit: 100, }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив элементов | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.nextAfterId` | string | Идентификатор последней отданной записи. Приходит при сортировке строго по `id` по возрастанию, пока `hasMore` равен `true`. Передайте его обратно в фильтр `>id` — это дешёвая замена растущему `offset` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временны́м окнам | | `meta.windowCount` | number | Число окон. Приходит при `autoWindowed: true` | | `meta.batchWaves` | number | Число волн параллельных запросов. Приходит при `autoWindowed: true` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. URL карточки любого элемента из массива `data` — его `id`: ``` https://.bitrix24.ru/crm/type//details// ``` `` — ID типа смарт-процесса (тот же, что в пути запроса). `` — домен портала. Если смарт-процесс вынесен в отдельный раздел портала, Битрикс24 откроет карточку по соответствующему пути. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 783, "title": "Договор на поставку", "stageId": "DT156_41:NEW", "opportunity": 500000 } ], "meta": { "total": 5, "hasMore": false, "durationMs": 320 } } ``` С фильтром по диапазону дат шире 14 дней в `meta` дополнительно приходят `autoWindowed`, `windowCount` и `batchWaves`: ```json { "success": true, "data": [ /* ... */ ], "meta": { "total": 8, "hasMore": true, "autoWindowed": true, "windowCount": 339, "batchWaves": 7, "durationMs": 15817 } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 400 | `INVALID_DYNAMIC_PARAM` | `entityTypeId` не является положительным целым или является зарезервированным (1, 2, 3, 4, 7, 31) | | 400 | `UNKNOWN_FILTER_FIELD` | Поле фильтра не существует у сущности — сообщение перечисляет доступные поля | | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Разбиение по временны́м окнам.** Фильтр по диапазону дат шире 14 дней автоматически разбивается на недельные окна, которые выполняются параллельными волнами — так выборка обходит потолок в 5000 записей на один вызов. В `meta` тогда приходят `autoWindowed: true`, число окон `windowCount` и число волн `batchWaves`. Отключает разбиение параметр `autoWindow: false`. При активном разбиении `offset` больше нуля отклоняется с `UNSTABLE_OFFSET_PAGINATION`. ## Смотрите также - [Список элементов](/docs/entities/items/list) - [Поля элемента](/docs/entities/items/fields) - [Batch](/docs/batch) - [Смарт-процессы](/docs/entities/smart-processes) - [Entity API](/docs/entity-api) --- # Items: Update ## Обновить элемент смарт-процесса `PATCH /v1/items/:entityTypeId/:id` Обновляет поля элемента смарт-процесса. Передавайте только изменяемые поля. ## Параметры запроса | Параметр | Тип | Описание | |----------|-----|---------| | `entityTypeId` | number | ID типа смарт-процесса (в URL) | | `id` | number | ID элемента (в URL) | ## Поля запроса (body) | Параметр | Тип | Описание | |----------|-----|---------| | `title` | string | Название | | `stageId` | string | Стадия. Список: `GET /v1/statuses?filter[entityId]=DYNAMIC_{entityTypeId}_STAGE_{categoryId}` | | `contactId` | number | ID контакта | | `companyId` | number | ID компании | | `opportunity` | number | Сумма | | `currencyId` | string | Валюта. Список: `GET /v1/currencies` | | `assignedById` | number | Ответственный. Список: `GET /v1/users` | | `opened` | boolean | Доступен для всех | | `begindate` | datetime | Дата начала. Принимает ISO 8601, но сохраняется только дата — время отбрасывается | | `closedate` | datetime | Дата завершения. Принимает ISO 8601, но сохраняется только дата — время отбрасывается | | `observers` | array | ID наблюдателей | Полный список полей: [GET /v1/items/:entityTypeId/fields](/docs/entities/items/fields). Пользовательские поля (`ufCrmN_*`) также принимаются. ## Примеры В примерах `entityTypeId = 156`, `id = 783` — замените на ваши значения. ### curl — личный ключ ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/items/156/783 \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "stageId": "DT156_41:WON", "opportunity": 750000 }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/items/156/783 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "stageId": "DT156_41:WON", "opportunity": 750000 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/156/783', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ stageId: 'DT156_41:WON', opportunity: 750000, }), }) const { success, data } = await res.json() console.log('Обновлён:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/items/156/783', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ stageId: 'DT156_41:WON', opportunity: 750000, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID элемента | | `title` | string | Название | | `stageId` | string | Стадия | | `opportunity` | number | Сумма | | `assignedById` | number | Ответственный | | `updatedBy` | number | Последний редактор | | `updatedTime` | datetime | Дата изменения | Ответ содержит все поля элемента после обновления. ## Пример ответа ```json { "success": true, "data": { "id": 783, "title": "Договор на поставку", "stageId": "DT156_41:WON", "categoryId": 41, "companyId": 15, "contactId": 42, "opportunity": 750000, "currencyId": "RUB", "assignedById": 1, "createdBy": 1, "updatedBy": 1, "movedBy": 1, "createdTime": "2026-04-15T14:30:00+03:00", "updatedTime": "2026-04-15T16:45:00+03:00", "movedTime": "2026-04-15T16:45:00+03:00" } } ``` ## Пример ответа при ошибке 404 — элемент не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_DYNAMIC_PARAM` | `entityTypeId` не является положительным целым или является зарезервированным (1, 2, 3, 4, 7, 31) | | 400 | `READONLY_FIELD` | В теле передано поле только для чтения (`id`, `createdTime`, `updatedTime` и другие) | | 400 | `CLIENT_BLOCK_DISABLED` | В теле передан клиент (`contactId`, `contactIds` или `companyId`), а у смарт-процесса выключен блок «Клиент». Проверить: `GET /v1/smart-processes/:entityTypeId`, поле `isClientEnabled` | | 404 | `ENTITY_NOT_FOUND` | Элемент с указанным ID не найден | | 422 | `BITRIX_ERROR` | Ошибка валидации полей от Битрикс24. Конкретная причина — в поле `message` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Работа с файлами в полях CRM](/docs/recipes/crm-files) - [Получить элемент](/docs/entities/items/get) - [Поля элемента](/docs/entities/items/fields) - [Создать элемент](/docs/entities/items/create) - [Entity API](/docs/entity-api) --- # Leads: Aggregate ## Агрегация лидов `POST /v1/leads/aggregate` Подсчёт количества, сумма, среднее, минимум и максимум по лидам с фильтрацией и группировкой. **Стандартные поля:** - `opportunity` — сумма, каноническое имя, алиас `amount`. Числовые функции и `groupBy` - `stageId` — статус, каноническое имя, алиас `statusId`. Для `groupBy` - `sourceId` — источник. Для `groupBy` - `assignedById` — ответственный. Для `groupBy` **Пользовательские поля (UF):** UF-поля типов `integer`, `double`, `money` — для числовых функций. UF любого типа — для `groupBy`. Полный список UF-полей конкретного портала приходит в тексте ошибки `INVALID_PARAMS`, если передать несуществующее имя. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций. Каждый элемент: `{ "field": "amount", "function": "sum" }`. Функции: `count`, `sum`, `avg`, `min`, `max`. Для `count` поле — `"*"`. Без массива — только `count` | | `filter` | object | нет | Фильтрация по полям `GET /v1/leads/fields`. [Синтаксис фильтрации](/docs/filtering) | | `groupBy` | string \| string[] | нет | Поле или массив полей для группировки (максимум 5). Допустимые значения — из списка выше | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/leads/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "amount", "function": "sum" }, { "field": "amount", "function": "avg" } ], "filter": { "sourceId": "WEB" }, "groupBy": "statusId" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/leads/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "amount", "function": "sum" }, { "field": "amount", "function": "avg" } ], "filter": { "sourceId": "WEB" }, "groupBy": "statusId" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [ { field: 'amount', function: 'sum' }, { field: 'amount', function: 'avg' }, ], filter: { sourceId: 'WEB' }, groupBy: 'statusId', }), }) const { success, data } = await res.json() console.log('Всего лидов:', data.count) console.log('По статусам:', data.groups) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [ { field: 'amount', function: 'sum' }, { field: 'amount', function: 'avg' }, ], filter: { sourceId: 'WEB' }, groupBy: 'statusId', }), }) const { success, data } = await res.json() ``` > Для группировки по нескольким полям передайте массив: `"groupBy": ["statusId", "sourceId"]` (максимум 5). ## Другие сценарии Подсчёт записей — `count` с полем `"*"`, самый быстрый запрос без выгрузки записей. Без массива `aggregate` результат тот же: ```json { "aggregate": [{ "field": "*", "function": "count" }] } ``` Работа с пользовательскими полями (UF) — `sum` по UF + группировка по другому UF: ```json { "aggregate": [{ "field": "UF_CRM_BUDGET", "function": "sum" }], "groupBy": "UF_CRM_PRIORITY" } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Общее количество записей под фильтр | | `data.aggregates` | object | Результаты агрегаций: `{ "amount": { "sum": 500000, "avg": 5000 } }` | | `data.groups` | array | Группы (только при `groupBy`). Каждый элемент: поля группировки + `count` + `aggregates` | | `data.meta.totalRecords` | number | Общее количество записей под фильтр | | `data.meta.recordsProcessed` | number | Сколько записей обработано для числовых агрегаций (максимум 5000) | | `data.meta.truncated` | boolean | `true`, если под фильтр попало больше 5000 записей | ## Пример ответа Ответ на основной запрос (агрегации + `groupBy: "statusId"`): ```json { "success": true, "data": { "count": 100, "aggregates": { "amount": { "sum": 500000, "avg": 5000 } }, "groups": [ { "statusId": "NEW", "count": 60, "aggregates": { "amount": { "sum": 300000 } } }, { "statusId": "CONVERTED", "count": 40, "aggregates": { "amount": { "sum": 200000 } } } ], "meta": { "totalRecords": 100, "recordsProcessed": 100, "truncated": false } } } ``` Без `groupBy` поле `data.groups` в ответе отсутствует. ## Пример ответа при ошибке 400 — неверное имя функции, несуществующее поле или `groupBy` по неаггрегируемому полю: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "Field 'foo' not found. Available numeric fields: stageId, statusId, opportunity, amount, sourceId, assignedById" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Некорректное имя функции, несуществующее поле, нечисловое поле в `sum`/`avg`/`min`/`max`, `groupBy` по неаггрегируемому полю или больше 5 полей в `groupBy` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`count` vs числовые функции.** `count` считается одним вызовом в Битрикс24 на любом объёме данных. Функции `sum`/`avg`/`min`/`max` подгружают записи постранично (максимум 5000) и считают на стороне Вайбкод — если под фильтр попадает больше 5000 записей, `meta.truncated` будет `true`, агрегация выполнится по первым 5000. Для точных счётчиков на больших выборках используйте `count` или сужайте фильтр. **Money-поля.** UF-поля типа `money` хранятся в формате `"сумма|валюта"` (`"1500|RUB"`) — агрегат извлекает числовую часть автоматически, складывать можно без парсинга. **Фильтрация по UF работает.** В `filter` можно передавать любые поля — стандартные и пользовательские, любого типа. Например, `{ "filter": { "ufCrm_1234": "value" } }` вернёт количество лидов с этим значением UF. ## Смотрите также - [Список лидов](/docs/entities/leads/list) - [Поиск лидов](/docs/entities/leads/search) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Leads: Create ## Создать лид `POST /v1/leads` Создаёт новый лид в CRM. ## Поля запроса (body) | Параметр | Тип | Описание | |----------|-----|---------| | `title` | string | Название лида | | `name` | string | Имя контакта | | `lastName` | string | Фамилия контакта | | `secondName` | string | Отчество | | `stageId` | string | Статус лида — каноническое имя, принимается и алиас `statusId`. Стандартные: `NEW`, `IN_PROCESS`, `PROCESSED`. Портал может иметь свои — список: `GET /v1/statuses?filter[entityId]=STATUS`. В ответе значение возвращается в поле `stageId` | | `opportunity` | number | Сумма — каноническое имя, принимается и алиас `amount`. ⚠ Чтобы значение сохранилось, передайте в том же запросе `isManualOpportunity: true` — иначе Битрикс24 пересчитает сумму по товарным позициям | | `isManualOpportunity` | boolean | Ручной режим суммы (см. `opportunity`) | | `currency` | string | Валюта (алиас `currencyId`). Список: `GET /v1/currencies` | | `companyTitle` | string | Название компании (текст, не ID) | | `phone` | string \| string[] \| object[] | Телефон. Принимает три формы: строка `"+7..."`, массив строк `["+7...", "+7..."]`, или массив объектов `[{ "value": "+7...", "typeId": "WORK" }, …]`. `typeId`: `WORK \| HOME \| MOBILE \| OTHER` (по умолчанию `WORK`). ⚠ UPPER-форма `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` **не принимается** — вернёт `400 INVALID_MULTIFIELD_SHAPE`. Используйте camelCase: `[{ "value": "...", "typeId": "WORK" }]` | | `email` | string \| string[] \| object[] | Email. Принимает три формы: строка `"a@b.com"`, массив строк `["a@b.com", "b@c.com"]`, или массив объектов `[{ "value": "a@b.com", "typeId": "WORK" }, …]`. `typeId`: `WORK \| HOME \| MAILING \| OTHER` (по умолчанию `WORK`). ⚠ UPPER-форма `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` **не принимается** — вернёт `400 INVALID_MULTIFIELD_SHAPE`. Используйте camelCase: `[{ "value": "...", "typeId": "WORK" }]` | | `post` | string | Должность | | `comments` | string | Комментарий | | `sourceId` | string | Источник. Список: `GET /v1/statuses?filter[entityId]=SOURCE` | | `sourceDescription` | string | Описание источника | | `assignedById` | number | Ответственный. Список: `GET /v1/users` | | `opened` | boolean | Доступен для всех | Полный список полей: [GET /v1/leads/fields](/docs/entities/leads/fields). ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/leads \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Заявка с сайта", "name": "Мария", "lastName": "Сидорова", "phone": "+79161234567", "sourceId": "WEB", "stageId": "NEW" }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/leads \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Заявка с сайта", "name": "Мария", "lastName": "Сидорова", "phone": "+79161234567", "sourceId": "WEB", "stageId": "NEW" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Заявка с сайта', name: 'Мария', lastName: 'Сидорова', phone: '+79161234567', sourceId: 'WEB', stageId: 'NEW', }), }) const { success, data } = await res.json() console.log('Lead ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Заявка с сайта', name: 'Мария', lastName: 'Сидорова', phone: '+79161234567', sourceId: 'WEB', stageId: 'NEW', }), }) const { success, data } = await res.json() ``` ### Альтернативная форма — массив объектов с явным `typeId` Если нужно указать несколько значений или явный тип (`HOME`, `MOBILE`): ```json { "phone": [ { "value": "+79161234567", "typeId": "WORK" }, { "value": "+79161112233", "typeId": "MOBILE" } ], "email": [ { "value": "work@company.ru", "typeId": "WORK" }, { "value": "personal@me.ru", "typeId": "HOME" } ] } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID созданного лида | | `title` | string | Название | | `stageId` | string | Статус (стадия) лида | | `assignedById` | number | Ответственный | | `createdBy` | number | Создатель | | `createdTime` | datetime | Дата создания | Ответ содержит все поля лида. URL карточки лида в Битрикс24 строится из `id`: ``` https://.bitrix24.ru/crm/lead/details// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": { "id": 5001, "title": "Заявка с сайта", "stageId": "NEW", "assignedById": 1, "createdBy": 1, "createdTime": "2026-04-15T13:00:00+03:00", "updatedTime": "2026-04-15T13:00:00+03:00", "opened": true, "sourceId": "WEB" } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 400 | `INVALID_MULTIFIELD_SHAPE` | Неверная форма поля `phone` или `email` — нужен `[{ "value", "typeId" }]` | | 400 | `READONLY_FIELD` | Попытка записать read-only поле | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Конвертация лида:** Битрикс24 REST не имеет отдельного метода конвертации. Чтобы «конвертировать» лид, создайте сделку/контакт/компанию с `leadId` и обновите статус лида: ```javascript // 1. Создать сделку из лида await fetch('/v1/deals', { body: { title: 'Из лида', leadId: 5001 } }) // 2. Закрыть лид await fetch('/v1/leads/5001', { method: 'PATCH', body: { statusId: 'CONVERTED' } }) ``` ## Смотрите также - [Работа с файлами в полях CRM](/docs/recipes/crm-files) - [Список лидов](/docs/entities/leads/list) - [Поля лида](/docs/entities/leads/fields) - [Поиск дубликатов](/docs/duplicates) - [Сделки](/docs/entities/deals) - [Entity API](/docs/entity-api) - [Лимиты и оптимизация](/docs/optimization) --- # Leads: Delete ## Удалить лид `DELETE /v1/leads/:id` Удаляет лид по ID. Восстановить удалённый лид через API нельзя — создавайте новый при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID лида | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/leads/42" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/leads/42" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/42', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Лид удалён') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/42', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — лид не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Лид не найден | | 403 | `ACCESS_DENIED` | Нет доступа | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список лидов](/docs/entities/leads/list) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Leads: Fields ## Поля лида `GET /v1/leads/fields` Возвращает полный список доступных полей, включая пользовательские (`ufCrm_*`). ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/leads/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/leads/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | RO | Описание | |------|-----|:--:|---------| | `id` | number | да | ID лида | | `title` | string | | Название лида | | `name` | string | | Имя | | `lastName` | string | | Фамилия | | `secondName` | string | | Отчество | | `stageId` | string | | Статус (стадия) лида — каноническое имя в ответах: `NEW`, `IN_PROCESS`, … Список: `GET /v1/statuses?filter[entityId]=STATUS` | | `statusId` | string | | Алиас `stageId` на запись, в фильтрах и сортировке. ⚠ В ответах list/get/search значение приходит в поле `stageId`, ключ `statusId` в ответе не возвращается — читайте `stageId`. Не передавайте алиас и каноническое имя одновременно в одном запросе | | `companyTitle` | string | | Название компании | | `companyId` | number | | ID компании. Поиск: `GET /v1/companies` | | `contactId` | number | | ID контакта. Поиск: `GET /v1/contacts` | | `opportunity` | number | | Сумма — каноническое имя в ответах. ⚠ Чтобы записанное значение сохранилось, передайте `isManualOpportunity: true` в том же запросе | | `amount` | number | | Алиас `opportunity` на запись/в фильтрах. В ответах значение приходит в поле `opportunity` | | `isManualOpportunity` | boolean | | Ручной режим суммы. Без `true` сумма пересчитывается по товарным позициям и записанное значение затирается | | `currency` | string | | Алиас `currencyId` на запись/в фильтрах. Валюта. Список: `GET /v1/currencies` | | `currencyId` | string | | Валюта — каноническое имя в ответах | | `sourceId` | string | | Источник. Список: `GET /v1/statuses?filter[entityId]=SOURCE` | | `sourceDescription` | string | | Описание источника | | `assignedById` | number | | Ответственный. Список: `GET /v1/users` | | `createdBy` | number | да | Создатель. Поиск: `GET /v1/users` | | `opened` | boolean | | Доступен для всех | | `comments` | string | | Комментарий | | `post` | string | | Должность | | `phone` | multifield | | Телефон. На вход (POST/PATCH) принимает `string \| string[] \| object[]`. На выходе `phone` — строка с первичным значением, значения по типам — в полях `phoneWork`/`phoneMobile`, полный перечень с типами — в массиве `fm[]` (формат `{ id, typeId, valueType, value }`). ⚠ PATCH **только добавляет** новые записи — старые `phone` не удаляются. См. [Обновить лид](/docs/entities/leads/update). ⚠ UPPER-форма `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` **не принимается** — вернёт `400 INVALID_MULTIFIELD_SHAPE`. Используйте camelCase: `[{ "value": "...", "typeId": "WORK" }]`. | | `email` | multifield | | Email. На вход принимает `string \| string[] \| object[]`. На выходе `email` — строка с первичным значением, значения по типам — в полях `emailWork`/`emailHome`/`emailMailing`, полный перечень — в массиве `fm[]`. ⚠ PATCH **только добавляет** новые записи — старые `email` не удаляются. ⚠ UPPER-форма `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` **не принимается** — вернёт `400 INVALID_MULTIFIELD_SHAPE`. Используйте camelCase: `[{ "value": "...", "typeId": "WORK" }]`. | | `birthdate` | datetime | | Дата рождения | | `hasPhone` | boolean | да | Указан ли телефон | | `hasEmail` | boolean | да | Указан ли email | | `hasImol` | boolean | да | Есть ли контакт в открытой линии | | `isReturnCustomer` | boolean | да | Повторное обращение | | `createdTime` | datetime | да | Дата создания | | `updatedTime` | datetime | да | Дата изменения | | `originatorId` | string | | Внешний источник — идентификатор внешней системы, из которой импортирован лид. Приходит `null` для лидов, созданных в Битрикс24 | | `dateClosed` | datetime | да | Дата закрытия лида. Приходит `null`, пока лид не закрыт | | `lastCommunicationTime` | string | да | Дата последней коммуникации с лидом. Приходит `null`, если её не было | | `utmSource` | string | | Метка `utm_source` источника трафика. Приходит `null`, если не задана | | `utmMedium` | string | | Метка `utm_medium` источника трафика. Приходит `null`, если не задана | | `utmCampaign` | string | | Метка `utm_campaign` источника трафика. Приходит `null`, если не задана | | `utmContent` | string | | Метка `utm_content` источника трафика. Приходит `null`, если не задана | | `utmTerm` | string | | Метка `utm_term` источника трафика. Приходит `null`, если не задана | **Пользовательские поля** (`ufCrm_*`) также возвращаются в ответах и принимаются при создании/обновлении. ## Доступные include Эндпоинт `GET /v1/leads/fields` возвращает список доступных include: `contact`, `company`. Пример использования: [Получить leads](/docs/entities/leads/get#связанные-данные). Подробнее об include: [Связанные данные](/docs/includes). ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "ID лида", "description": "Уникальный числовой идентификатор лида." }, "title": { "type": "string", "readonly": false, "label": "Название лида", "description": "Название лида." }, "assignedById": { "type": "number", "readonly": false, "label": "Ответственный", "description": "ID ответственного пользователя. Список: GET /v1/users." } }, "batch": ["create", "update", "delete"] } } ``` Показаны 3 из множества полей. Полный список в таблице выше. ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Обновить лид](/docs/entities/leads/update) - [Сделки](/docs/entities/deals) - [Пользовательские поля](/docs/userfields) - [Entity API](/docs/entity-api) - [Лимиты и оптимизация](/docs/optimization) --- # Leads: Get ## Получить лид `GET /v1/leads/:id` Возвращает лид по ID со всеми полями. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID лида | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/leads/42" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/leads/42" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/42', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Лид:', data.title, '— статус:', data.stageId) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/42', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа Объект лида со всеми полями — см. [Поля лида](/docs/entities/leads/fields). ## Связанные данные Запрос со связанными сущностями — параметр `include`: ``` GET /v1/leads/5001?include=contact,company ``` Доступные include: `contact`, `company`. Результат в поле `_included`. Подробнее — [Связанные данные](/docs/includes). ## Пример ответа ```json { "success": true, "data": { "id": 42, "title": "Заявка с сайта #42", "name": "Алексей", "lastName": "Иванов", "secondName": "Петрович", "stageId": "NEW", "companyTitle": "ООО Ромашка", "companyId": 15, "contactId": 71, "opportunity": 150000, "currencyId": "RUB", "sourceId": "WEB", "sourceDescription": "Форма обратной связи", "assignedById": 1, "createdBy": 1, "opened": true, "comments": "Звонить после 14:00", "phone": "+70000000001", "phoneWork": "+70000000001", "email": "info@example.com", "emailWork": "info@example.com", "emailHome": "home@example.com", "hasPhone": true, "hasEmail": true, "fm": [ { "id": 41, "typeId": "PHONE", "valueType": "WORK", "value": "+70000000001" }, { "id": 43, "typeId": "EMAIL", "valueType": "WORK", "value": "info@example.com" }, { "id": 45, "typeId": "EMAIL", "valueType": "HOME", "value": "home@example.com" } ], "createdTime": "2026-04-10T14:30:00+03:00", "updatedTime": "2026-04-12T09:15:00+03:00" } } ``` Телефон и почта в ответе — строки с первичным значением, значения по типам — в полях `phoneWork`, `phoneMobile`, `emailWork`, `emailHome`. Полный перечень с типами — в массиве `fm[]` (`{ id, typeId, valueType, value }`, где `id` — идентификатор записи). Наличие проверяйте по `hasPhone`/`hasEmail`: при отсутствии телефона `phone` приходит пустой строкой. Отдельную запись `fm[]` по её `id` через API не изменить и не удалить — PATCH добавляет новые записи. ## Пример ответа при ошибке 404 — лид не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Лид не найден | | 403 | `ACCESS_DENIED` | Нет доступа к лиду | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Работа с файлами в полях CRM](/docs/recipes/crm-files) - [Обновить лид](/docs/entities/leads/update) - [Поля лида](/docs/entities/leads/fields) - [Лимиты и оптимизация](/docs/optimization) --- # Leads: List ## Список лидов `GET /v1/leads` Возвращает список лидов с поддержкой фильтрации, сортировки и авто-пагинации. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` авто-пагинация | | `offset` | number | `0` | Пропустить N записей. При `offset > 0` рекомендуется `limit <= 500`. Для обхода всей коллекции дешевле курсор — `order[id]=asc` и `filter[>id]` из `meta.nextAfterId` | | `select` | string | — | Выборка полей: `?select=id,title,stageId,amount`. Неизвестные поля игнорируются | | `order` | object | — | Сортировка: `?order[createdTime]=desc`. Имена для сортировки — из `GET /v1/leads/fields` | | `filter` | object | — | Фильтрация по полям `GET /v1/leads/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[stageId]=NEW` | | `withTotal` | string | — | Нужно ли количество: `true` или `false`. `false` — не заказывать подсчёт. Это единственный способ гарантированно убрать `meta.total` из ответа. Без параметра — настройка ключа, затем платформенное умолчание, и тогда на короткой странице точное количество приходит и без заказа. [Листание и количество](/docs/entity-api#листание-и-количество-записей) | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/leads?limit=10&filter[stageId]=NEW&select=id,title,stageId,amount" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/leads?limit=10&filter[stageId]=NEW&select=id,title,stageId,amount" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads?limit=10&filter[stageId]=NEW&select=id,title,stageId,amount', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} лидов`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads?limit=10&filter[stageId]=NEW&select=id,title,stageId,amount', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив лидов (поля — см. [Поля](/docs/entities/leads/fields)) | | `meta.total` | number | Общее количество записей. Необязательное поле: если количество не заказывалось, его в ответе нет | | `meta.hasMore` | boolean | Есть ещё записи | | `meta.nextAfterId` | string | Идентификатор последней отданной записи. Приходит при сортировке строго по `id` по возрастанию, пока `hasMore` равен `true`. Передайте его обратно как `filter[>id]` — это дешёвая замена растущему `offset` | URL карточки любого лида из массива `data` — его `id`: ``` https://.bitrix24.ru/crm/lead/details// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 42, "title": "Заявка с сайта #42", "name": "Алексей", "lastName": "Иванов", "stageId": "NEW", "opportunity": 150000, "currencyId": "RUB", "assignedById": 1, "sourceId": "WEB", "createdTime": "2026-04-10T14:30:00+03:00" } ], "meta": { "total": 834, "hasMore": true } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Фильтр по телефону подходит не для всякого поиска.** Значение без оператора сравнивается со всей сохранённой строкой: лид с номером `+7 (999) 123-45-67` найдётся по этой же строке и не найдётся по `79991234567`, потому что плюс, пробелы, скобки и дефисы — часть значения. Вдобавок фильтр видит только первый номер записи: если записаны рабочий и мобильный, по мобильному он вернёт пустой список. Чтобы найти лид по номеру телефона в любом написании и по любому из его номеров, используйте [Поиск дубликатов](/docs/duplicates). **Авто-пагинация:** при `limit > 50` Вайбкод автоматически запрашивает несколько страниц. **Когда использовать search:** для сложных фильтров — `POST /v1/leads/search`, параметры передаются в body. См. [Поиск лидов](/docs/entities/leads/search). ## Смотрите также - [Поиск лидов](/docs/entities/leads/search) - [Поля лида](/docs/entities/leads/fields) - [Поиск дубликатов](/docs/duplicates) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Leads: Products Add > Поле, которого нет среди записываемых, больше не отбрасывается молча — запрос отклоняется с `400 INVALID_PARAMS`, и в тексте ошибки перечислены записываемые имена. Поля только для чтения, которые приходят в ответах товарных позиций (`priceAccount`, `ownerId`, `storeId` и другие) по-прежнему принимаются и игнорируются, поэтому объект, прочитанный через GET, можно отправить обратно без чистки. ## Добавить товар в лид `POST /v1/leads/:id/products` Добавляет одну товарную позицию в лид. В отличие от `PUT /v1/leads/:id/products`, не заменяет существующие позиции. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID лида | | `productId` | number | нет | ID товара из каталога. Если задан без `productName`, имя подставляется из каталога. Каталог: `GET /v1/products` | | `productName` | string | нет | Название товарной позиции — для произвольной строки без товара из каталога. Укажите хотя бы одно из `productId` / `productName`. | | `price` | number | нет | Цена за единицу | | `quantity` | number | нет | Количество | | `discount` | number | нет | Сумма скидки | | `taxRate` | number | нет | Ставка налога (%) | | `taxIncluded` | boolean | нет | Налог включён в цену | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/leads/312/products" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "productId": 1, "price": 25000, "quantity": 2 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/leads/312/products" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "productId": 1, "price": 25000, "quantity": 2 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/312/products', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ productId: 1, price: 25000, quantity: 2 }), }) const { success, data } = await res.json() console.log('ID строки:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/312/products', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ productId: 1, price: 25000, quantity: 2 }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | object | Созданная товарная строка целиком, HTTP-статус `201`. Состав полей — [Поля товаров](/docs/entities/leads/products-fields) | ## Пример ответа Показаны основные поля. Полный список — [Поля товаров](/docs/entities/leads/products-fields). ```json { "success": true, "data": { "id": 1465, "productId": 1, "productName": "Серверное оборудование", "price": 25000, "quantity": 2, "discount": 0, "discountTypeId": 2, "taxIncluded": false } } ``` ## Пример ответа при ошибке 404 — лид не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Тело содержит имя, которого нет среди записываемых полей — см. [Поля товаров](/docs/entities/leads/products-fields) | | 404 | `ENTITY_NOT_FOUND` | Лид не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Товарные позиции](/docs/entities/leads/products-get) - [Установить товары](/docs/entities/leads/products-set) - [Удалить товар](/docs/entities/leads/products-delete) - [Товары каталога](/docs/entities/products) --- # Leads: Products Delete ## Удалить товар из лида `DELETE /v1/leads/:id/products/:rowId` Удаляет одну товарную позицию из лида по ID строки. Восстановить удалённую позицию через API нельзя — добавляйте новую при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID лида | | `rowId` (path) | number | да | ID товарной строки (из ответа add или list) | `rowId` — это ID товарной строки, а не `productId` из каталога товаров. ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/leads/312/products/1465" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/leads/312/products/1465" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/312/products/1465', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Товар удалён из лида') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/312/products/1465', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — лид не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Лид или товарная строка не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Товарные позиции](/docs/entities/leads/products-get) - [Добавить товар](/docs/entities/leads/products-add) - [Установить товары](/docs/entities/leads/products-set) - [Товары каталога](/docs/entities/products) --- # Leads: Products Fields ## Поля товаров лида `GET /v1/leads/:id/products/fields` Возвращает описание полей товарных позиций лида: названия, типы, доступность для чтения и записи. > **Сумма скидки называется `discount`** — как в данных и при записи. Прежнее имя `discountSum` осталось устаревшим псевдонимом: оно по-прежнему приходит в этом справочнике и принимается при записи, поэтому код, написанный по старому списку полей, продолжает работать. В самих товарных позициях приходит только `discount` — переходите на него. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID лида | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/leads/741/products/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/leads/741/products/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/741/products/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/741/products/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | RO | Обяз. | Описание | |------|-----|:--:|:-----:|---------| | `id` | integer | да | | ID позиции | | `productId` | integer | | да | ID товара. Каталог: `GET /v1/products` | | `productName` | string | | | Название товара | | `price` | double | | | Цена | | `quantity` | double | | | Количество | | `discount` | double | | | Сумма скидки | | `discountSum` | double | | | Устаревший псевдоним `discount` — принимается при записи, в товарных позициях не приходит | | `discountRate` | double | | | Величина скидки (%) | | `discountTypeId` | integer | | | Тип скидки | | `taxRate` | double | | | Налог (%) | | `taxIncluded` | char | | | Налог включён в цену (`Y`/`N`) | | `priceExclusive` | double | да | | Цена без налога со скидкой | | `priceNetto` | double | да | | Цена нетто | | `priceBrutto` | double | да | | Цена брутто | | `measureCode` | integer | | | Код единицы измерения | | `measureName` | string | да | | Единица измерения | | `customized` | char | да | | Изменён (`Y`/`N`) | | `sort` | integer | | | Сортировка | | `type` | integer | да | | Тип | | `storeId` | integer | да | | ID склада | | `ownerId` | integer | да | | ID владельца (лида) | | `ownerType` | string | да | | Тип владельца | | `priceAccount` | double | да | | Цена в валюте отчёта | | `xmlId` | string | да | | Внешний код позиции | ## Пример ответа ```json { "success": true, "data": { "id": { "type": "integer", "isRequired": false, "isReadOnly": true, "title": "ID", "description": "Row identity. Read-only as an attribute; echo it back in PUT /products items to update a row in place instead of recreating it." }, "ownerId": { "type": "integer", "isRequired": false, "isReadOnly": true, "isImmutable": true, "title": "ID владельца" }, "ownerType": { "type": "string", "isRequired": false, "isReadOnly": true, "isImmutable": true, "title": "Тип владельца" }, "productId": { "type": "integer", "isRequired": true, "isReadOnly": false, "title": "Товар" }, "productName": { "type": "string", "isRequired": false, "isReadOnly": false, "title": "Название товара" }, "price": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Цена" }, "priceExclusive": { "type": "double", "isRequired": false, "isReadOnly": true, "title": "Цена без налога со скидкой" }, "priceNetto": { "type": "double", "isRequired": false, "isReadOnly": true, "title": "PRICE_NETTO" }, "priceBrutto": { "type": "double", "isRequired": false, "isReadOnly": true, "title": "PRICE_BRUTTO" }, "quantity": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Количество" }, "discountTypeId": { "type": "integer", "isRequired": false, "isReadOnly": false, "title": "Тип скидки" }, "discountRate": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Величина скидки" }, "discount": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Сумма скидки" }, "discountSum": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Сумма скидки", "description": "Deprecated alias of `discount`; kept so clients written against the previous field list keep working. Accepted on write, never present in row data — migrate to `discount`." }, "taxRate": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Налог" }, "taxIncluded": { "type": "char", "isRequired": false, "isReadOnly": false, "title": "Налог включен в цену" }, "customized": { "type": "char", "isRequired": false, "isReadOnly": true, "title": "Изменен" }, "measureCode": { "type": "integer", "isRequired": false, "isReadOnly": false, "title": "Код единицы измерения" }, "measureName": { "type": "string", "isRequired": false, "isReadOnly": true, "title": "Единица измерения" }, "sort": { "type": "integer", "isRequired": false, "isReadOnly": false, "title": "Сортировка" }, "type": { "type": "integer", "isRequired": false, "isReadOnly": true, "title": "TYPE" }, "storeId": { "type": "integer", "isRequired": false, "isReadOnly": true, "title": "STORE_ID" }, "priceAccount": { "type": "double", "isRequired": false, "isReadOnly": true }, "xmlId": { "type": "string", "isRequired": false, "isReadOnly": true } } } ``` ## Пример ответа при ошибке 404 — лид не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Лид не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Товарные позиции](/docs/entities/leads/products-get) - [Добавить товар](/docs/entities/leads/products-add) - [Установить товары](/docs/entities/leads/products-set) - [Поля лида](/docs/entities/leads/fields) --- # Leads: Products Get ## Товарные позиции лида `GET /v1/leads/:id/products` Возвращает список товарных позиций, привязанных к лиду. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID лида | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/leads/741/products" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/leads/741/products" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/741/products', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Товаров:', data.length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/741/products', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив товарных позиций | | `data[].productId` | number | ID товара. Каталог: `GET /v1/products` | | `data[].productName` | string | Название товара | | `data[].price` | number | Цена за единицу | | `data[].quantity` | number | Количество | | `data[].discount` | number | Сумма скидки | | `data[].taxRate` | number/null | Ставка налога (%) | | `data[].taxIncluded` | boolean | Налог включён в цену | Показаны основные поля. Полный список (23 поля, включая priceAccount, measureCode и др.): [Поля товаров](/docs/entities/leads/products-fields). ## Пример ответа ```json { "success": true, "data": [ { "productId": 1, "productName": "Серверное оборудование", "price": 1000, "quantity": 2, "discount": 0, "taxRate": null, "taxIncluded": false } ] } ``` ## Пример ответа при ошибке 404 — лид не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Лид не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Установить товары](/docs/entities/leads/products-set) - [Получить лид](/docs/entities/leads/get) - [Товары каталога](/docs/entities/products) - [Лимиты и оптимизация](/docs/optimization) --- # Leads: Products Get Single ## Получить товар из лида `GET /v1/leads/:id/products/:rowId` Возвращает одну товарную позицию лида по ID строки. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID лида | | `rowId` (path) | number | да | ID товарной строки (из ответа add или list) | `rowId` — это ID товарной строки, а не `productId` из каталога товаров. ## Примеры ### curl — личный ключ ```bash curl -X GET "https://vibecode.bitrix24.tech/v1/leads/741/products/1471" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X GET "https://vibecode.bitrix24.tech/v1/leads/741/products/1471" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/741/products/1471', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Цена:', data.price) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/741/products/1471', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.id` | number | ID товарной строки | | `data.productId` | number | ID товара из каталога | | `data.productName` | string | Название товара | | `data.price` | number | Цена за единицу | | `data.quantity` | number | Количество | | `data.discount` | number | Сумма скидки | | `data.discountRate` | number | Процент скидки | | `data.discountTypeId` | number | Тип скидки (1 — сумма, 2 — процент) | | `data.taxRate` | number \| null | Ставка налога (%) | | `data.taxIncluded` | boolean | Налог включён в цену | | `data.priceExclusive` | number | Цена без скидки | | `data.priceNetto` | number | Цена нетто | | `data.priceBrutto` | number | Цена брутто | | `data.priceAccount` | number | Цена в валюте учёта | | `data.measureCode` | number | Код единицы измерения | | `data.measureName` | string | Название единицы измерения | | `data.sort` | number | Сортировка | | `data.ownerId` | number | ID сущности-владельца, которой принадлежит позиция | | `data.ownerType` | string | Код типа владельца (`D` у сделок, `T` у смарт-процессов) | | `data.storeId` | number \| null | ID склада; `null`, если складской учёт выключен | ## Пример ответа ```json { "success": true, "data": { "id": 1471, "productId": 1, "productName": "День добрый!", "price": 5000, "priceAccount": 5000, "priceExclusive": 5000, "priceNetto": 5000, "priceBrutto": 5000, "quantity": 3, "discountTypeId": 2, "discountRate": 0, "discount": 0, "taxRate": null, "taxIncluded": false, "customized": "Y", "measureCode": 796, "measureName": "шт", "sort": 0, "ownerId": 741, "ownerType": "D", "storeId": 3, "xmlId": "sale_basket_995", "type": 1 } } ``` ## Пример ответа при ошибке 404 — лид или товарная строка не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Лид или товарная строка не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Товарные позиции](/docs/entities/leads/products-get) - [Обновить товар](/docs/entities/leads/products-update) - [Добавить товар](/docs/entities/leads/products-add) - [Удалить товар](/docs/entities/leads/products-delete) - [Товары каталога](/docs/entities/products) --- # Leads: Products Set > Поле, которого нет среди записываемых, больше не отбрасывается молча — запрос отклоняется с `400 INVALID_PARAMS`, и в тексте ошибки перечислены записываемые имена. Поля только для чтения, которые приходят в ответах товарных позиций (`priceAccount`, `ownerId`, `storeId` и другие) по-прежнему принимаются и игнорируются, поэтому объект, прочитанный через GET, можно отправить обратно без чистки. > Сохраняйте `id` у элемента, чтобы обновить существующую строку на месте: без него строка будет создана заново с новым идентификатором. ## Установить товары лида `PUT /v1/leads/:id/products` Устанавливает товарные позиции лида. Полностью заменяет текущий список — передайте все нужные позиции. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `items` | array | да | Массив товарных позиций | | `items[].productId` | number | да | ID товара. Каталог: `GET /v1/products` | | `items[].price` | number | да | Цена за единицу | | `items[].quantity` | number | да | Количество | | `items[].discount` | number | нет | Сумма скидки | | `items[].taxRate` | number | нет | Ставка налога (%) | | `items[].taxIncluded` | boolean | нет | Налог включён в цену | ## Примеры ### curl — личный ключ ```bash curl -X PUT "https://vibecode.bitrix24.tech/v1/leads/312/products" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "items": [ { "productId": 1, "price": 25000, "quantity": 2 }, { "productId": 5, "price": 5000, "quantity": 1, "discount": 500 } ] }' ``` ### curl — OAuth-приложение ```bash curl -X PUT "https://vibecode.bitrix24.tech/v1/leads/312/products" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "items": [ { "productId": 1, "price": 25000, "quantity": 2 }, { "productId": 5, "price": 5000, "quantity": 1, "discount": 500 } ] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/312/products', { method: 'PUT', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ items: [ { productId: 1, price: 25000, quantity: 2 }, { productId: 5, price: 5000, quantity: 1, discount: 500 }, ], }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/312/products', { method: 'PUT', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ items: [ { productId: 1, price: 25000, quantity: 2 }, { productId: 5, price: 5000, quantity: 1, discount: 500 }, ], }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив итоговых товарных позиций с полями productId, productName, price, quantity, discount, taxRate, taxIncluded | Массив итоговых товарных позиций с полями `productId`, `productName`, `price`, `quantity`, `discount`, `taxRate`, `taxIncluded`. ## Пример ответа ```json { "success": true, "data": [ { "productId": 1, "productName": "Серверное оборудование", "price": 25000, "quantity": 2, "discount": 0, "taxRate": null, "taxIncluded": false }, { "productId": 5, "productName": "Установка и настройка", "price": 5000, "quantity": 1, "discount": 500, "taxRate": null, "taxIncluded": false } ] } ``` ## Пример ответа при ошибке 400 — неверный формат: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "items must be an array" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Тело содержит имя, которого нет среди записываемых полей — см. [Поля товаров](/docs/entities/leads/products-fields) | | 400 | `INVALID_PARAMS` | `items` не является массивом | | 404 | `ENTITY_NOT_FOUND` | Лид не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Полная замена:** PUT заменяет весь список товаров. Чтобы добавить позицию — сначала получите текущие (`GET`), добавьте новую в массив, отправьте всё (`PUT`). ## Смотрите также - [Товарные позиции](/docs/entities/leads/products-get) - [Получить лид](/docs/entities/leads/get) - [Товары каталога](/docs/entities/products) - [Лимиты и оптимизация](/docs/optimization) --- # Leads: Products Update > Поле, которого нет среди записываемых, больше не отбрасывается молча — запрос отклоняется с `400 INVALID_PARAMS`, и в тексте ошибки перечислены записываемые имена. Поля только для чтения, которые приходят в ответах товарных позиций (`priceAccount`, `ownerId`, `storeId` и другие) по-прежнему принимаются и игнорируются, поэтому объект, прочитанный через GET, можно отправить обратно без чистки. ## Обновить товар лида `PATCH /v1/leads/:id/products/:rowId` Обновляет товарную позицию лида. Передайте только изменяемые поля. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID лида | | `rowId` (path) | number | да | ID товарной позиции (из ответа list или add, не productId из каталога) | ## Поля запроса (body) | Параметр | Тип | Описание | |----------|-----|---------| | `price` | number | Цена за единицу | | `quantity` | number | Количество | | `productId` | number | ID товара. Каталог: `GET /v1/products` | | `discount` | number | Сумма скидки | | `taxRate` | number | Ставка налога (%) | | `taxIncluded` | boolean | Налог включён в цену | | `sort` | number | Сортировка | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/leads/741/products/1471" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "price": 9999, "quantity": 10 }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/leads/741/products/1471" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "price": 9999, "quantity": 10 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/741/products/1471', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ price: 9999, quantity: 10 }), }) const { success, data } = await res.json() console.log('Обновлено:', data.price, 'x', data.quantity) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/741/products/1471', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ price: 9999, quantity: 10 }), }) const { success, data } = await res.json() ``` ## Поля ответа Обновлённый объект товарной позиции: `id`, `productId`, `productName`, `price`, `quantity`, `discount`, `taxRate`, `taxIncluded`. ## Пример ответа ```json { "success": true, "data": { "id": 1471, "productId": 1, "productName": "Серверное оборудование", "price": 9999, "quantity": 10, "discount": 0, "taxRate": null, "taxIncluded": false } } ``` ## Пример ответа при ошибке 404 — позиция не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Тело содержит имя, которого нет среди записываемых полей — см. [Поля товаров](/docs/entities/leads/products-fields) | | 404 | `ENTITY_NOT_FOUND` | Позиция не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить товар](/docs/entities/leads/products-get-single) - [Получить товары](/docs/entities/leads/products-get) - [Добавить товар](/docs/entities/leads/products-add) - [Лимиты и оптимизация](/docs/optimization) --- # Leads: Search ## Поиск лидов `POST /v1/leads/search` Поиск лидов по условиям в теле запроса. Принимает те же фильтры, что и список лидов, и рассчитан на составные условия и большие выборки. ## Поля запроса (body) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям `GET /v1/leads/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "stageId": "NEW" }` | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки» | | `order` | object | — | Сортировка: `{ "createdTime": "desc" }` | | `select` | string[] | — | Выборка полей: `["id", "title", "stageId", "amount"]` | | `autoWindow` | boolean | `true` | Разбивать выборку по недельным окнам при фильтре по диапазону дат шире 14 дней. `false` отключает разбиение | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/leads/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "stageId": "NEW", ">=amount": 100000 }, "limit": 10, "order": { "createdTime": "desc" } }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/leads/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "stageId": "NEW", ">=amount": 100000 }, "limit": 10, "order": { "createdTime": "desc" } }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { stageId: 'NEW', '>=amount': 100000 }, limit: 10, order: { createdTime: 'desc' }, }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { stageId: 'NEW', '>=amount': 100000 }, limit: 10, order: { createdTime: 'desc' }, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив лидов (поля — см. [Поля](/docs/entities/leads/fields)) | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.nextAfterId` | string | Идентификатор последней отданной записи. Приходит при сортировке строго по `id` по возрастанию, пока `hasMore` равен `true`. Передайте его обратно в фильтр `>id` — это дешёвая замена растущему `offset` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временны́м окнам | | `meta.windowCount` | number | Число окон. Приходит при `autoWindowed: true` | | `meta.batchWaves` | number | Число волн параллельных запросов. Приходит при `autoWindowed: true` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. URL карточки любого лида из массива `data` — его `id`: ``` https://.bitrix24.ru/crm/lead/details// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 42, "title": "Заявка с сайта #42", "stageId": "NEW", "opportunity": 150000, "currencyId": "RUB", "assignedById": 1, "sourceId": "WEB", "createdTime": "2026-04-10T14:30:00+03:00" } ], "meta": { "total": 31, "hasMore": true, "durationMs": 653 } } ``` С фильтром по диапазону дат шире 14 дней в `meta` дополнительно приходят `autoWindowed`, `windowCount` и `batchWaves`: ```json { "success": true, "data": [ /* ... */ ], "meta": { "total": 43, "hasMore": true, "autoWindowed": true, "windowCount": 131, "batchWaves": 3, "durationMs": 1653 } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Разбиение по временны́м окнам.** Фильтр по диапазону дат шире 14 дней автоматически разбивается на недельные окна, которые выполняются параллельными волнами — так выборка обходит потолок в 5000 записей на один вызов. В `meta` тогда приходят `autoWindowed: true`, число окон `windowCount` и число волн `batchWaves`. Отключает разбиение параметр `autoWindow: false`. При активном разбиении `offset` больше нуля отклоняется с `UNSTABLE_OFFSET_PAGINATION`. **Фильтр по телефону подходит не для всякого поиска.** Значение без оператора сравнивается со всей сохранённой строкой: лид с номером `+7 (999) 123-45-67` найдётся по этой же строке и не найдётся по `79991234567`, потому что плюс, пробелы, скобки и дефисы — часть значения. Вдобавок фильтр видит только первый номер записи: если записаны рабочий и мобильный, по мобильному он вернёт пустой список. Чтобы найти лид по номеру телефона в любом написании и по любому из его номеров, используйте [Поиск дубликатов](/docs/duplicates). Оператор `$contains` при этом работает — он ищет кусок текста внутри значения, это рабочий способ для почты: `{ "email": { "$contains": "@example.com" } }`. ## Смотрите также - [Список лидов](/docs/entities/leads/list) - [Поиск дубликатов](/docs/duplicates) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Leads: Update ## Обновить лид `PATCH /v1/leads/:id` Обновляет поля существующего лида. Передайте только изменяемые поля. Полный список в [справочнике полей](/docs/entities/leads/fields), включая пользовательские (`ufCrm_*`). > ⚠ **Важно про `email` / `phone` (multifield):** При обновлении Битрикс24 **только добавляет** новые multifield-записи. PATCH `{"email": "new@y.com"}` к лиду, у которого уже есть email, **не заменит** старый — у лида станет два email. Это особенность Битрикс24, не Вайбкод. Чтобы заменить или удалить email/phone — отредактируйте лид через интерфейс Битрикс24. ## Часто обновляемые поля | Параметр | Тип | Описание | |----------|-----|---------| | `stageId` | string | Статус лида — каноническое имя, принимается и алиас `statusId`. Список: `GET /v1/statuses?filter[entityId]=STATUS`. В ответе значение возвращается в поле `stageId` | | `opportunity` | number | Сумма — каноническое имя, принимается и алиас `amount`. ⚠ Чтобы значение сохранилось, передайте в том же запросе `isManualOpportunity: true` | | `assignedById` | number | Ответственный. Список: `GET /v1/users` | | `title` | string | Название лида | | `phone` | string \| string[] \| object[] | Телефон. Принимает три формы: строка `"+7..."`, массив строк `["+7...", "+7..."]`, или массив объектов `[{ "value": "+7...", "typeId": "WORK" }, …]`. `typeId`: `WORK \| HOME \| MOBILE \| OTHER` (по умолчанию `WORK`). ⚠ UPPER-форма `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` **не принимается** — вернёт `400 INVALID_MULTIFIELD_SHAPE`. Используйте camelCase: `[{ "value": "...", "typeId": "WORK" }]` | | `email` | string \| string[] \| object[] | Email. Принимает три формы: строка `"a@b.com"`, массив строк `["a@b.com", "b@c.com"]`, или массив объектов `[{ "value": "a@b.com", "typeId": "WORK" }, …]`. `typeId`: `WORK \| HOME \| MAILING \| OTHER` (по умолчанию `WORK`). ⚠ UPPER-форма `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` **не принимается** — вернёт `400 INVALID_MULTIFIELD_SHAPE`. Используйте camelCase: `[{ "value": "...", "typeId": "WORK" }]` | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/leads/42" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "stageId": "IN_PROCESS", "opportunity": 250000, "isManualOpportunity": true, "assignedById": 3, "title": "Заявка с сайта — горячий клиент" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/leads/42" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "stageId": "IN_PROCESS", "opportunity": 250000, "isManualOpportunity": true, "assignedById": 3, "title": "Заявка с сайта — горячий клиент" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/42', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ stageId: 'IN_PROCESS', opportunity: 250000, isManualOpportunity: true, assignedById: 3, title: 'Заявка с сайта — горячий клиент', }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/leads/42', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ stageId: 'IN_PROCESS', opportunity: 250000, isManualOpportunity: true, assignedById: 3, title: 'Заявка с сайта — горячий клиент', }), }) const { success, data } = await res.json() ``` ### Альтернативная форма — массив объектов с явным `typeId` Если нужно указать несколько значений или явный тип (`HOME`, `MOBILE`): ```json { "phone": [ { "value": "+79161234567", "typeId": "WORK" }, { "value": "+79161112233", "typeId": "MOBILE" } ], "email": [ { "value": "work@company.ru", "typeId": "WORK" }, { "value": "personal@me.ru", "typeId": "HOME" } ] } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | object | Обновлённый объект лида со всеми полями — см. [Поля](/docs/entities/leads/fields) | Обновленный объект лида — см. [Поля лида](/docs/entities/leads/fields). ## Пример ответа ```json { "success": true, "data": { "id": 42, "title": "Заявка с сайта", "stageId": "IN_PROCESS", "assignedById": 1, "createdTime": "2026-04-15T12:00:00+03:00", "updatedTime": "2026-04-15T13:00:00+03:00" } } ``` ## Пример ответа при ошибке 404 — лид не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Лид не найден | | 403 | `ACCESS_DENIED` | Нет доступа | | 400 | `INVALID_MULTIFIELD_SHAPE` | Неверная форма поля `phone` или `email` — нужен `[{ "value", "typeId" }]` | | 400 | `READONLY_FIELD` | Попытка записать read-only поле | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Работа с файлами в полях CRM](/docs/recipes/crm-files) - [Получить лид](/docs/entities/leads/get) - [Поля лида](/docs/entities/leads/fields) - [Статусы](/docs/entities/statuses) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Order Statuses: Aggregate ## Агрегация статусов заказов `POST /v1/order-statuses/aggregate` Подсчёт количества статусов с группировкой по `type` или `notify`. У сущности нет числовых полей, поэтому числовые функции (`sum`, `avg`) не применяются — основной сценарий — `count` с фильтром или группировкой. ## Стандартные поля Все поля статуса категориальные — подходят только для `groupBy` и `filter`: | Поле | Назначение | |------|------------| | `type` | Группировка по типу: `O` (заказа) или `D` (доставки) | | `notify` | Группировка по тому, отправляется ли уведомление | Полный список агрегируемых полей перечислен в таблице выше. ## Поля запроса (тело) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций. Для статусов основной вариант — `count` (без других функций, числовых полей нет). Формат подсчёта — `{ "field": "*", "function": "count" }`. Без параметра — `count` записей с учётом фильтра | | `filter` | object | нет | Фильтрация — те же поля, что в [`GET /v1/order-statuses`](./list.md). [Синтаксис фильтрации](/docs/filtering) | | `groupBy` | string \| string[] | нет | Поле или массив полей для группировки (максимум 5) | | `groupOrderBy` | array | нет | Сортировка групп: `[{ "field": "count", "direction": "desc" }]` | | `groupLimit` | number | нет | Ограничение количества возвращаемых групп (1-1000) | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/order-statuses/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "groupBy": "type" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/order-statuses/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "groupBy": "type" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/order-statuses/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ groupBy: 'type', }), }) const { success, data } = await res.json() console.log('Распределение статусов:', data.groups) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/order-statuses/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ groupBy: 'type', }), }) const { success, data } = await res.json() ``` ## Другие сценарии Подсчёт записей — `count` с полем `"*"`, самый быстрый запрос без выгрузки записей. Без массива `aggregate` результат тот же: ```json { "aggregate": [{ "field": "*", "function": "count" }] } ``` Сколько статусов с включённым уведомлением: ```json { "filter": { "notify": true } } ``` Группировка по обоим осям сразу: ```json { "groupBy": ["type", "notify"] } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Общее количество статусов, соответствующих фильтру | | `data.aggregates` | object | Результаты агрегаций — для статусов остаётся пустым (нет числовых полей в `aggregatable`) | | `data.groups` | array | Группы (только при `groupBy`) | | `data.meta.totalRecords` | number | Общее количество записей | | `data.meta.recordsProcessed` | number | Количество обработанных записей | | `data.meta.truncated` | boolean | `true`, если записей больше 5000 | | `data.meta.groupTotal` | number | Количество групп до `groupLimit` | | `data.meta.groupsTruncated` | boolean | Был ли список групп обрезан `groupLimit` | ## Пример ответа ```json { "success": true, "data": { "count": 9, "aggregates": {}, "groups": [ { "type": "O", "count": 6, "aggregates": {} }, { "type": "D", "count": 3, "aggregates": {} } ], "meta": { "totalRecords": 9, "recordsProcessed": 9, "truncated": false, "groupTotal": 2, "groupsTruncated": false } } } ``` Без `groupBy` поле `data.groups` в ответе отсутствует. ## Пример ответа при ошибке 400 — неизвестное поле в `groupBy`: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "groupBy field 'foo' is not aggregatable on this entity. Available: type, notify." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Неизвестная функция или несуществующее поле — сообщение содержит список допустимых полей | | 400 | `INVALID_PARAMS` | Передано больше 5 полей в `groupBy` | | 400 | `INVALID_PARAMS` | Зарезервированные ключевые слова в `groupBy`: `count`, `aggregates`, `meta`, `groups` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Только `count` имеет смысл.** Поскольку в схеме статуса нет числовых полей в `aggregatable`, функции `sum` / `avg` / `min` / `max` всегда возвращают пустой `aggregates`. Для подсчёта статусов используйте `count` (без `aggregate`) с фильтром или группировкой. **Малый объём данных.** На порталах число статусов измеряется десятками, поэтому `meta.truncated` (срабатывает только при > 5000 записей) для этой сущности не активируется. ## Смотрите также - [Список статусов](./list.md) - [Поиск статусов](./search.md) - [Поля статуса](./fields.md) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Order Statuses: Create ## Создать статус заказа `POST /v1/order-statuses` Создаёт новый статус для заказа или доставки. Символьный код `id` задаёт пользователь — он используется как ссылка в [`orders.statusId`](../orders/fields.md). ## Поля запроса (тело) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` | string | да | Символьный код статуса (1-2 символа). Например: `N`, `IP`, `DT`. Должен быть уникальным независимо от типа | | `type` | string | да | Тип статуса: `O` — статус заказа, `D` — статус доставки | | `sort` | number | нет | Порядок сортировки в списках. Если не передан, сохраняется как `null` | | `notify` | boolean | нет | Отправлять ли уведомление клиенту при переходе в этот статус. Если не передан, сохраняется как `false` | | `color` | string | нет | HEX-код цвета для отображения, например `#FFA500`. Если не передан, сохраняется как `null` | | `xmlId` | string | нет | Внешний идентификатор. Если не передан, генерируется автоматически вида `bx_` | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/order-statuses" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "id": "ZZ", "type": "O" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/order-statuses" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "id": "ZZ", "type": "O" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/order-statuses', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ id: 'ZZ', type: 'O', }), }) const { success, data } = await res.json() console.log('Статус создан:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/order-statuses', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ id: 'ZZ', type: 'O', }), }) const { success, data } = await res.json() ``` ## Поля ответа Возвращается полный объект созданного статуса. Переданные поля сохраняются как есть, опущенные необязательные поля остаются `null` или `false`. | Поле | Тип | Описание | |------|-----|---------| | `id` | string | Символьный код, переданный в запросе | | `type` | string | Тип статуса | | `sort` | number \| null | Порядок сортировки. `null`, если не передан | | `notify` | boolean | Уведомление клиента. `false`, если не передан | | `color` | string \| null | HEX-код цвета. `null`, если не передан | | `xmlId` | string \| null | Внешний идентификатор. Сгенерирован автоматически, если не передан | ## Пример ответа Минимальное создание — переданы только `id` и `type`: ```json { "success": true, "data": { "id": "ZZ", "type": "O", "sort": null, "color": null, "notify": false, "xmlId": "bx_6a3e47867ed3b" } } ``` Необязательные поля `sort`, `color` и `notify` без значения остаются `null` и `false` — значения по умолчанию не подставляются. Поле `xmlId` сгенерировано автоматически. Передайте эти поля в теле запроса, чтобы задать их. ## Пример ответа при ошибке 422 — не переданы обязательные поля: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Required fields: id, type" } } ``` ## Ошибки | HTTP | `error.code` | Маркер в `error.message` | Описание | |------|--------------|--------------------------|---------| | 422 | `BITRIX_ERROR` | `Required fields: id, type` | Не переданы обязательные поля `id` или `type` | | 400 | `BITRIX_ERROR` | `Duplicate entry` | Статус с таким `id` уже существует — `id` должен быть уникальным независимо от типа | | 400 | `BITRIX_ERROR` | — | Длина `id` превышает 2 символа | | 400 | `BITRIX_ERROR` | — | Передано пустое значение `id` | | 403 | `SCOPE_DENIED` | — | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | — | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Уникальность `id` глобальная.** Создать статус заказа и статус доставки с одинаковым `id` нельзя — код уникален независимо от типа. Перед созданием проверьте, что код не занят, через [`GET /v1/order-statuses`](./list.md). ## Смотрите также - [Список статусов](./list.md) - [Получить статус](./get.md) - [Обновить статус](./update.md) - [Поля статуса](./fields.md) - [Обновить заказ](../orders/update.md) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Order Statuses: Delete ## Удалить статус заказа `DELETE /v1/order-statuses/:id` Удаляет статус заказа или доставки по символьному коду. Восстановить удалённый статус через API нельзя — создавайте новый при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | string | да | Символьный код статуса | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/order-statuses/DT" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/order-statuses/DT" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/order-statuses/DT', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Статус удалён') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/order-statuses/DT', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Статус удалён') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — успех проверяется по статусу. ## Пример ответа ```http HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 422 — статус не найден: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "status is not exists" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Статус с таким `id` не найден или уже удалён | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Заказы со ссылкой на удалённый статус продолжают работать.** При удалении статуса заказы с этим `statusId` не меняются — поле `orders.statusId` сохраняет старое значение. В интерфейсе портала такой заказ будет показан с пустым названием статуса. Для миграции — перед удалением статуса выполните [`PATCH /v1/orders/:id`](../orders/update.md) для всех затронутых заказов. **Стандартные статусы удаляются тем же запросом.** Статусы по умолчанию (`N`, `P`, `F`, `D` и другие) для Битрикс24 не системные — удалить их можно тем же `DELETE /v1/order-statuses/:id`, что и пользовательские. Перед удалением убедитесь, что они не используются в существующих заказах. ## Смотрите также - [Список статусов](./list.md) - [Получить статус](./get.md) - [Список заказов в статусе](../orders/list.md) - [Обновить заказ](../orders/update.md) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Order Statuses: Fields ## Поля статуса заказа `GET /v1/order-statuses/fields` Возвращает статическую карту полей статуса: тип каждого поля, флаг только-для-чтения, список агрегируемых полей и доступные batch-операции. Динамически загружаемого описания или отображаемого названия полей здесь нет — это фиксированная схема типов. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/order-statuses/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/order-statuses/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/order-statuses/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { data } = await res.json() console.log('Поля статуса:', Object.keys(data.fields)) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/order-statuses/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | string | Символьный код статуса. Задаётся пользователем при создании | | `type` | string | Тип статуса: `O` — заказа, `D` — доставки | | `sort` | number \| null | Порядок сортировки. В выборках бывает `null` | | `notify` | boolean | Отправлять ли уведомление клиенту | | `color` | string \| null | HEX-код цвета. В выборках бывает `null` | | `xmlId` | string \| null | Внешний идентификатор. В выборках бывает `null` | ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "string", "readonly": false }, "type": { "type": "string", "readonly": false }, "sort": { "type": "number", "readonly": false }, "notify": { "type": "boolean", "readonly": false }, "color": { "type": "string", "readonly": false }, "xmlId": { "type": "string", "readonly": false } }, "aggregatable": ["type", "notify"], "batch": ["create", "update", "delete"] } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'sale' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список статусов](./list.md) - [Создать статус](./create.md) - [Агрегация статусов](./aggregate.md) - [Статусы заказов](../order-statuses.md) - [Entity API](/docs/entity-api) --- # Order Statuses: Get ## Получить статус заказа `GET /v1/order-statuses/:id` Возвращает один статус заказа или доставки по символьному коду. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | string | да | Символьный код статуса (например, `N`, `IP`, `DT`) | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/order-statuses/D" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/order-statuses/D" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/order-statuses/D', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Статус:', data.id, '— тип:', data.type) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/order-statuses/D', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | string | Символьный код статуса | | `type` | string | Тип статуса: `O` — заказа, `D` — доставки | | `sort` | number \| null | Порядок сортировки | | `notify` | boolean | Отправлять ли уведомление клиенту | | `color` | string \| null | HEX-код цвета или `null` | | `xmlId` | string \| null | Внешний идентификатор или `null` | ## Пример ответа ```json { "success": true, "data": { "id": "D", "type": "O", "sort": 140, "notify": true, "color": "#FFBEBD", "xmlId": null } } ``` ## Пример ответа при ошибке 422 — статус не найден: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "status is not exists" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Статус с таким `id` не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Обновить статус](./update.md) - [Удалить статус](./delete.md) - [Список статусов](./list.md) - [Поля статуса](./fields.md) - [Заказы в этом статусе](../orders/list.md) - [Лимиты и оптимизация](/docs/optimization) --- # Order Statuses: List ## Список статусов заказов `GET /v1/order-statuses` Возвращает список статусов заказов и доставки с поддержкой фильтрации. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000) | | `select` | string | — | Выборка полей: `?select=id,type,sort,color` | | `order` | object | — | Сортировка: `?order[sort]=asc` | | `filter` | object | — | Фильтрация по полям статуса.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[type]=O` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/order-statuses?limit=3&order[sort]=asc" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/order-statuses?limit=3&order[sort]=asc" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/order-statuses?limit=3&order[sort]=asc', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Всего статусов: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/order-statuses?limit=3&order[sort]=asc', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив статусов | | `data[].id` | string | Символьный код статуса | | `data[].type` | string | Тип статуса: `O` — заказа, `D` — доставки | | `data[].sort` | number \| null | Порядок сортировки | | `data[].notify` | boolean | Отправлять ли уведомление клиенту | | `data[].color` | string \| null | HEX-код цвета или `null` | | `data[].xmlId` | string \| null | Внешний идентификатор или `null` | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | ## Пример ответа ```json { "success": true, "data": [ { "id": "D", "type": "O", "sort": 140, "notify": true, "color": "#FFBEBD", "xmlId": null }, { "id": "DF", "type": "D", "sort": 400, "notify": true, "color": null, "xmlId": null }, { "id": "DD", "type": "D", "sort": 500, "notify": true, "color": null, "xmlId": null } ], "meta": { "total": 9, "hasMore": true } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'sale' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет в схеме статуса | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Разделение по типу.** По умолчанию ответ включает статусы обоих типов — заказа и доставки. Чтобы получить только статусы заказа, добавьте `filter[type]=O`. Для доставки — `filter[type]=D`. ## Смотрите также - [Поиск статусов](./search.md) - [Получить статус](./get.md) - [Создать статус](./create.md) - [Поля статуса](./fields.md) - [Заказы в этом статусе](../orders/list.md) - [Синтаксис фильтрации](/docs/filtering) - [Entity API](/docs/entity-api) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Order Statuses: Search ## Поиск статусов заказов `POST /v1/order-statuses/search` Поиск статусов с фильтрацией. Аналогичен [`GET /v1/order-statuses`](./list.md), но условия фильтрации передаются в теле запроса — это позволяет задать несколько условий сразу. ## Поля запроса (тело) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям статуса.
[Синтаксис фильтрации](/docs/filtering) | | `limit` | number | `50` | Количество записей (до 5000) | | `select` | string[] | — | Выборка полей: `["id", "type", "sort", "color"]` | | `order` | object | — | Сортировка: `{ "sort": "asc" }` | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/order-statuses/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "type": "O", "notify": true }, "select": ["id", "type", "sort", "color"] }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/order-statuses/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "type": "O", "notify": true }, "select": ["id", "type", "sort", "color"] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/order-statuses/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { type: 'O', notify: true }, select: ['id', 'type', 'sort', 'color'], }), }) const { success, data, meta } = await res.json() console.log('Статусов с уведомлением:', meta.total) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/order-statuses/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { type: 'O', notify: true }, select: ['id', 'type', 'sort', 'color'], }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив статусов | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа ```json { "success": true, "data": [ { "id": "T", "type": "O", "sort": 30, "color": "#ACE9FB" }, { "id": "N", "type": "O", "sort": 100, "color": "#ACE9FB" }, { "id": "S", "type": "O", "sort": 110, "color": "#ACE9FB" }, { "id": "P", "type": "O", "sort": 130, "color": "#ACE9FB" }, { "id": "D", "type": "O", "sort": 140, "color": "#FFBEBD" }, { "id": "F", "type": "O", "sort": 200, "color": "#DBF199" } ], "meta": { "total": 6, "hasMore": false, "durationMs": 300 } } ``` ## Пример ответа при ошибке 400 — фильтр по несуществующему полю: ```json { "success": false, "error": { "code": "UNKNOWN_FILTER_FIELD", "message": "Unknown filter field 'foo' for entity 'order-statuses'. Available: id, type, sort, notify, color, xmlId" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет в схеме статуса | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`select` ограничивает поля в ответе.** Если передан `select`, в каждом элементе `data[]` будут только перечисленные поля. Без `select` возвращаются все поля статуса. ## Смотрите также - [Список статусов](./list.md) - [Получить статус](./get.md) - [Поля статуса](./fields.md) - [Заказы в этом статусе](../orders/list.md) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Order Statuses: Update ## Обновить статус заказа `PATCH /v1/order-statuses/:id` Обновляет параметры существующего статуса. Передавайте только изменяемые поля плоско в корне JSON — без обёртки `fields`. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | string | да | Символьный код статуса | ## Поля для обновления (тело) | Параметр | Тип | Описание | |----------|-----|---------| | `sort` | number | Порядок сортировки | | `notify` | boolean | Отправлять ли уведомление клиенту | | `color` | string | HEX-код цвета (`#FFA500`) | | `xmlId` | string | Внешний идентификатор | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/order-statuses/T" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "sort": 35, "color": "#2ECC71" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/order-statuses/T" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "sort": 35, "color": "#2ECC71" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/order-statuses/T', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ sort: 35, color: '#2ECC71', }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/order-statuses/T', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ sort: 35, color: '#2ECC71', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | object | Обновлённый объект статуса со всеми полями | ## Пример ответа ```json { "success": true, "data": { "id": "T", "type": "O", "sort": 35, "notify": true, "color": "#2ECC71", "xmlId": null } } ``` ## Пример ответа при ошибке 422 — статус не найден: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "status is not exists" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Статус с таким `id` не найден | | 400 | `BITRIX_ERROR` | Некорректное значение поля | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Поле `type` подтягивается автоматически.** Вайбкод перед обновлением статуса получает текущее значение `type` через `GET /v1/order-statuses/:id` и автоматически добавляет его в запрос, если оно не передано. Это позволяет обновлять одно поле через `PATCH`, не указывая тип каждый раз. **Поле `id` не редактируется.** Изменить символьный код статуса нельзя — `PATCH` принимает остальные поля, но не сам `id`. Чтобы переименовать статус, удалите старый и создайте новый с нужным `id`. Внимание: заказы со ссылкой на старый `id` останутся с этой ссылкой и продолжат работать. ## Смотрите также - [Получить статус](./get.md) - [Список статусов](./list.md) - [Удалить статус](./delete.md) - [Поля статуса](./fields.md) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Orders: Aggregate ## Агрегация заказов `POST /v1/orders/aggregate` Подсчёт количества заказов и числовые агрегации (`sum`, `avg`, `min`, `max`) по полю `price`. Поддерживает фильтрацию и группировку по `statusId`, `payed`, `canceled`, `personTypeId`, `responsibleId`, `userId`. ## Стандартные поля | Поле | Назначение | |------|------------| | `price` | Единственное числовое поле — подходит для `sum` / `avg` / `min` / `max` | | `statusId` | Категориальное — используется в `groupBy` (статусы заказов) | | `payed`, `canceled` | Логические — используются в `groupBy` (оплачен / отменён) | | `personTypeId`, `responsibleId`, `userId` | Идентификаторы — используются в `groupBy` (по типу плательщика, ответственному, покупателю) | Полный список агрегируемых полей — массив `aggregatable` в [`GET /v1/orders/fields`](./fields.md). ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций: `[{ "field": "price", "function": "sum" }]`. Функции: `count`, `sum`, `avg`, `min`, `max`. Для `count` поле — `"*"`. Без параметра — только `count` (один запрос в Битрикс24, записи не выгружаются) | | `filter` | object | нет | Фильтрация — те же поля, что в [`GET /v1/orders`](./list.md). [Синтаксис фильтрации](/docs/filtering) | | `groupBy` | string \| string[] | нет | Поле или массив полей для группировки (максимум 5). Допустимые значения — из массива `aggregatable` | | `groupOrderBy` | array | нет | Сортировка групп: `[{ "field": "price:sum", "direction": "desc" }]`. Поля: `count`, имя dim из `groupBy`, или `:` | | `groupLimit` | number | нет | Ограничение количества возвращаемых групп (1-1000) | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/orders/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "price", "function": "sum" }, { "field": "price", "function": "avg" } ], "groupBy": "statusId" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/orders/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "price", "function": "sum" }, { "field": "price", "function": "avg" } ], "groupBy": "statusId" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/orders/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [ { field: 'price', function: 'sum' }, { field: 'price', function: 'avg' }, ], groupBy: 'statusId', }), }) const { success, data } = await res.json() // data.groups — массив групп по statusId console.log(data.groups) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/orders/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [{ field: 'price', function: 'sum' }], groupBy: 'statusId', }), }) const { success, data } = await res.json() ``` ## Другие сценарии Подсчёт записей — `count` с полем `"*"`, самый быстрый запрос без выгрузки записей. Без массива `aggregate` результат тот же: ```json { "aggregate": [{ "field": "*", "function": "count" }] } ``` Сумма по всем заказам без группировки: ```json { "aggregate": [{ "field": "price", "function": "sum" }] } ``` Топ-3 статуса по сумме оплат с сортировкой: ```json { "aggregate": [{ "field": "price", "function": "sum" }], "groupBy": "statusId", "groupOrderBy": [{ "field": "price:sum", "direction": "desc" }], "groupLimit": 3 } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Общее количество заказов, соответствующих фильтру | | `data.aggregates` | object | Результаты агрегаций: `{ "price": { "sum": ..., "avg": ... } }` | | `data.groups` | array | Группы (присутствует только при `groupBy`). Каждый элемент: поля группировки + `count` + `aggregates` | | `data.meta.totalRecords` | number | Общее количество записей, обработанных для агрегации | | `data.meta.recordsProcessed` | number | Количество обработанных записей (до 5000) | | `data.meta.truncated` | boolean | `true`, если записей больше 5000 — агрегация по первым 5000 | | `data.meta.groupTotal` | number | Количество групп до применения `groupLimit` (только при `groupBy`) | | `data.meta.groupsTruncated` | boolean | Был ли список групп обрезан `groupLimit` | ## Пример ответа ```json { "success": true, "data": { "count": 194, "aggregates": { "price": { "sum": 2890284.0999999996 } }, "groups": [ { "statusId": "N", "count": 181, "aggregates": { "price": { "sum": 2876316.6299999994 } } }, { "statusId": "T", "count": 8, "aggregates": { "price": { "sum": 2998.5 } } }, { "statusId": "P", "count": 6, "aggregates": { "price": { "sum": 9958.97 } } }, { "statusId": "F", "count": 1, "aggregates": { "price": { "sum": 1010 } } }, { "statusId": "S", "count": 1, "aggregates": { "price": { "sum": 0 } } } ], "meta": { "totalRecords": 194, "recordsProcessed": 194, "truncated": false, "groupTotal": 5, "groupsTruncated": false } } } ``` Без `groupBy` поле `data.groups` в ответе отсутствует. ## Пример ответа при ошибке 400 — поле в `groupBy` не агрегируется: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "groupBy field 'foo' is not aggregatable on this entity. Available: price, statusId, payed, canceled, personTypeId, responsibleId, userId." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Неизвестная функция или несуществующее поле в `aggregate` / `groupBy` — сообщение содержит список допустимых полей | | 400 | `INVALID_PARAMS` | Передано больше 5 полей в `groupBy` | | 400 | `INVALID_PARAMS` | Зарезервированные ключевые слова в `groupBy`: `count`, `aggregates`, `meta`, `groups` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`count` против числовых функций.** `count` считается одним запросом в Битрикс24 — записи не выгружаются, время ответа не зависит от количества заказов. `sum` / `avg` / `min` / `max` подгружают записи постранично (максимум 5000) и считают на стороне Вайбкод. При более чем 5000 записях `meta.truncated` будет `true`, и агрегация выполняется по первым 5000. **Логические поля в группировке.** `groupBy: "payed"` или `groupBy: "canceled"` возвращает группы со значениями `true` / `false`. ## Смотрите также - [Список заказов](./list.md) - [Поиск заказов](./search.md) - [Поля заказа](./fields.md) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Orders: Create ## Создать заказ `POST /v1/orders` Создаёт новый заказ интернет-магазина. Тело запроса плоское — без обёртки `fields`. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `lid` | string | да | Идентификатор сайта-источника. Для облачных порталов всегда `"s1"` | | `personTypeId` | number | да | Идентификатор типа плательщика. На каждом портале свой набор типов (юр. лицо, физ. лицо и т. п.). ID можно увидеть в существующих заказах через [`GET /v1/orders`](./list.md) или [`POST /v1/orders/aggregate`](./aggregate.md) с `groupBy: "personTypeId"` | | `currency` | string | да | Валюта заказа. Список: [`GET /v1/currencies`](/docs/entities/currencies) | | `price` | number | нет | Общая сумма заказа | | `statusId` | string | нет | Статус заказа. По умолчанию — `"N"` (новый). Список: [`GET /v1/order-statuses?filter[type]=O`](../order-statuses/list.md) | | `userId` | number | нет | Идентификатор пользователя Битрикс24 — покупателя в интернет-магазине. Источник: [`GET /v1/users`](/docs/entities/users). Если не передать — Битрикс24 проставит пользователя по умолчанию | | `companyId` | number | нет | Идентификатор CRM-компании, связанной с заказом. Источник: [`GET /v1/companies`](/docs/entities/companies) | | `responsibleId` | number | нет | Ответственный сотрудник. Источник: [`GET /v1/users`](/docs/entities/users) | | `comments` | string | нет | Комментарий менеджера к заказу | | `userDescription` | string | нет | Комментарий покупателя к заказу | | `xmlId` | string | нет | Внешний идентификатор для синхронизации с внешними системами | | `canceled` | boolean | нет | Отменён ли заказ | | `reasonCanceled` | string | нет | Причина отмены | | `discountValue` | number | нет | Значение скидки | Полный список полей — [`GET /v1/orders/fields`](./fields.md). ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/orders" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "lid": "s1", "personTypeId": 5, "currency": "RUB", "price": 12500, "statusId": "N", "userId": 1, "comments": "Заказ из мобильного приложения" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/orders" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "lid": "s1", "personTypeId": 5, "currency": "RUB", "price": 12500, "statusId": "N", "userId": 1, "comments": "Заказ из мобильного приложения" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/orders', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ lid: 's1', personTypeId: 5, currency: 'RUB', price: 12500, statusId: 'N', userId: 1, comments: 'Заказ из мобильного приложения', }), }) const { success, data } = await res.json() console.log('Order ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/orders', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ lid: 's1', personTypeId: 5, currency: 'RUB', price: 12500, statusId: 'N', userId: 1, comments: 'Заказ из мобильного приложения', }), }) const { success, data } = await res.json() ``` ## Поля ответа Возвращается полный объект созданного заказа со всеми полями. | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор созданного заказа | | `accountNumber` | string | Порядковый номер заказа на портале (генерируется автоматически) | | `dateInsert` | datetime | Дата создания | | `dateStatus` | datetime | Дата установки текущего статуса | Остальные поля — см. [Поля заказа](./fields.md). URL заказа в Битрикс24 строится из `id`: ``` https://.bitrix24.ru/shop/orders/details// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": { "id": 859, "accountNumber": "450", "lid": "s1", "personTypeId": 5, "currency": "RUB", "price": 12500, "discountValue": 0, "taxValue": 0, "statusId": "N", "dateInsert": "2026-05-13T11:42:18.000Z", "dateUpdate": "2026-05-13T11:42:18.000Z", "dateStatus": "2026-05-13T11:42:18.000Z", "payed": false, "canceled": false, "marked": false, "responsibleId": 1, "userId": 1, "companyId": null, "clients": [ { "entityTypeId": 3, "entityId": 2471, "isPrimary": true, "roleId": 0, "sort": 0 } ], "comments": "Заказ из мобильного приложения", "xmlId": "", "externalOrder": false } } ``` ## Пример ответа при ошибке 422 — не переданы обязательные поля: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Required fields: personTypeId, currency, lid" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Не переданы обязательные поля — сообщение содержит их список (`Required fields: ...`) | | 400 | `READONLY_FIELD` | Передано поле только для чтения — `accountNumber`, `payed`, даты оплаты и статуса и другие | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Ссылки на справочники не проверяются.** Существование `statusId`, `userId`, `personTypeId`, `companyId` при создании не проверяется — несуществующие значения принимаются без ошибки. Заказ создаётся с переданными значениями, целостность ссылок остаётся на стороне приложения. **`statusId` усекается до 2 символов.** Значение длиннее двух символов сохраняется обрезанным без ошибки: `statusId: "ZZZ"` сохранится как `"ZZ"`. Используйте только реальные двухсимвольные коды статусов из [`GET /v1/order-statuses`](../order-statuses/list.md). **Поля только для создания.** `price`, `marked` и `reasonMarked` применяются при создании заказа, а на обновлении [`PATCH /v1/orders/:id`](./update.md) отклоняются с `400 READONLY_FIELD` — метод обновления Битрикс24 их не сохраняет. Чтобы изменить сумму после создания, меняйте позиции корзины через [`/v1/basket-items`](../basket-items.md). **`payed` нельзя установить.** Поле «оплачен» управляется подсистемой оплат — при создании и обновлении оно игнорируется и возвращает `false`. Попытка передать `payed` отклоняется с `400 READONLY_FIELD`. Оплату регистрируйте через [`POST /v1/payments`](../payments/create.md). **Номер счёта генерируется автоматически.** Поле `accountNumber` присваивается при создании. Передавать его в запросе нельзя — попытка отклоняется с `400 READONLY_FIELD`. **Позиции корзины и оплаты добавляются отдельно.** Заказ — это контейнер. После `POST /v1/orders` для добавления товаров вызовите [`POST /v1/basket-items`](../basket-items/create.md) с `orderId`, для регистрации оплаты — [`POST /v1/payments`](../payments/create.md). ## Смотрите также - [Список заказов](./list.md) - [Получить заказ](./get.md) - [Обновить заказ](./update.md) - [Добавить позицию корзины](../basket-items/create.md) - [Создать оплату](../payments/create.md) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Orders: Delete ## Удалить заказ `DELETE /v1/orders/:id` Удаляет заказ по идентификатору вместе со связанными позициями корзины и оплатами. Восстановить удалённый заказ через API нельзя — создавайте новый при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор заказа | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/orders/859" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/orders/859" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/orders/859', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Заказ удалён') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/orders/859', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Заказ удалён') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — успех проверяется по статусу. ## Пример ответа ```http HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 422 — заказ не найден: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "order is not exists" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Заказ с таким ID не найден или уже удалён | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Каскадное удаление.** Удаление заказа автоматически удаляет связанные позиции корзины и оплаты — отдельно вызывать `DELETE /v1/basket-items/:id` или `DELETE /v1/payments/:id` не нужно. **Альтернатива — отмена вместо удаления.** Чтобы сохранить историю и связи, лучше отменить заказ через [`PATCH /v1/orders/:id`](./update.md) с `{"canceled": true, "reasonCanceled": "..."}` — заказ останется в выборках с `filter[canceled]=true`. ## Смотрите также - [Обновить заказ](./update.md) - [Список заказов](./list.md) - [Получить заказ](./get.md) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Orders: Fields ## Поля заказа `GET /v1/orders/fields` Возвращает схему полей заказа: типы, флаги только-для-чтения, список агрегируемых полей. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/orders/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/orders/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/orders/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { data } = await res.json() console.log('Поля заказа:', Object.keys(data.fields)) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/orders/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор заказа (только чтение) | | `accountNumber` | string | Порядковый номер заказа на портале. Только чтение — присваивается автоматически, запись отклоняется с `400 READONLY_FIELD` | | `lid` | string | Идентификатор сайта-источника (всегда `"s1"` для облачных порталов) | | `personTypeId` | number | Идентификатор типа плательщика | | `currency` | string | Валюта заказа. Список: [`GET /v1/currencies`](/docs/entities/currencies) | | `price` | number | Общая сумма заказа. Принимается только при создании: на обновлении запись отклоняется с `400 READONLY_FIELD`, потому что Битрикс24 пересчитывает сумму из позиций корзины. В ответе `/fields` помечено `readonlyOnUpdate` | | `discountValue` | number | Значение скидки | | `taxValue` | number | Сумма налога | | `statusId` | string | Текущий статус заказа. Источник: [`GET /v1/order-statuses?filter[type]=O`](../order-statuses/list.md) | | `userId` | number | Идентификатор пользователя Битрикс24 — покупателя в интернет-магазине. Источник: [`GET /v1/users`](/docs/entities/users) | | `responsibleId` | number | Ответственный сотрудник. Источник: [`GET /v1/users`](/docs/entities/users) | | `payed` | boolean | Оплачен ли заказ полностью. Только чтение — управляется подсистемой оплат. Запись отклоняется с `400 READONLY_FIELD` | | `canceled` | boolean | Отменён ли заказ | | `marked` | boolean | Отмечен ли заказ как проблемный. Принимается только при создании: на обновлении запись отклоняется с `400 READONLY_FIELD`. В ответе `/fields` помечено `readonlyOnUpdate` | | `deducted` | boolean | Списан ли товар со склада | | `reasonCanceled` | string \| null | Причина отмены. `null`, если заказ не отменён | | `reasonMarked` | string \| null | Причина пометки. `null`, если пометки нет. Принимается только при создании: на обновлении запись отклоняется с `400 READONLY_FIELD`. В ответе `/fields` помечено `readonlyOnUpdate` | | `additionalInfo` | string \| null | Дополнительная информация. `null`, если не задана | | `comments` | string \| null | Комментарий менеджера к заказу. `null`, если не задан | | `userDescription` | string \| null | Комментарий покупателя к заказу. `null`, если не задан | | `orderTopic` | string \| null | Тема заказа. `null`, если не задана | | `xmlId` | string | Внешний идентификатор для синхронизации | | `id1c` | string \| null | Идентификатор в 1С. `null`, если заказ не синхронизирован с 1С | | `version1c` | string \| null | Версия в 1С. `null`, если заказ не синхронизирован с 1С | | `updated1c` | boolean | Обновлён ли заказ через 1С | | `externalOrder` | boolean | Создан ли заказ во внешней системе | | `recountFlag` | boolean | Флаг автоматического пересчёта | | `affiliateId` | number \| null | Идентификатор партнёра партнёрской программы. `null`, если не задан | | `lockedBy` | number \| null | Идентификатор пользователя, заблокировавшего заказ (актуально для коробочных порталов). `null`, если заказ не заблокирован | | `dateLock` | datetime \| null | Время блокировки. `null`, если заказ не заблокирован | | `recurringId` | number \| null | Идентификатор подписки (если заказ создан из повторяющегося шаблона). `null`, если заказ не из подписки | | `dateInsert` | datetime | Дата создания (только чтение) | | `dateUpdate` | datetime | Дата последнего изменения (только чтение) | | `dateCanceled` | datetime \| null | Дата отмены (только чтение). `null`, если заказ не отменён | | `dateStatus` | datetime | Дата установки текущего статуса (только чтение) | | `empCanceledId` | number \| null | Сотрудник, отменивший заказ (только чтение). `null`, если заказ не отменён | | `empMarkedId` | number \| null | Сотрудник, поставивший пометку (только чтение). `null`, если пометки нет | | `empStatusId` | number \| null | Сотрудник, последний раз менявший статус (только чтение). `null`, если статус не менялся | ### Дополнительные поля и вложенные массивы Эти поля тоже входят в схему `GET /v1/orders/fields`. `companyId` доступен для чтения и записи и по нему можно фильтровать, остальные — только для чтения. Массивы `clients`, `payments`, `basketItems`, `propertyValues` возвращает только [`GET /v1/orders/:id`](./get.md) — в списочном ответе [`GET /v1/orders`](./list.md) их нет. Логические поля внутри вложенных объектов приходят как `true`/`false`, даты — в UTC формате `…Z`. | Поле | Тип | Описание | |------|-----|---------| | `companyId` | number \| null | Идентификатор связанной CRM-компании. `null`, если компания не задана. Доступен для записи и фильтрации. Список: [`GET /v1/companies`](/docs/entities/companies) | | `dateMarked` | datetime \| null | Дата последней пометки заказа (только чтение) | | `personTypeXmlId` | string \| null | Внешний идентификатор типа плательщика (только чтение) | | `statusXmlId` | string \| null | Внешний идентификатор статуса (только чтение) | | `version` | number | Внутренний номер версии записи (только чтение) | | `clients` | array | CRM-привязки заказа, только чтение. Каждый элемент: `{entityTypeId, entityId, isPrimary, roleId, sort}`, где `isPrimary` — `true`/`false`. `entityTypeId` равен `3` — контакт ([`GET /v1/contacts`](/docs/entities/contacts)), `4` — компания ([`GET /v1/companies`](/docs/entities/companies)) | | `payments` | array \| null | Оплаты заказа, только чтение. Поля оплаты — [Оплаты](../payments.md). `null`, если оплат нет | | `basketItems` | array | Позиции корзины, только чтение. Поля позиции — [Позиции корзины](../basket-items.md) | | `propertyValues` | array | Значения свойств заказа — ФИО, e-mail, телефон, адрес доставки, только чтение. Набор зависит от настройки портала | | `requisiteLink` | object | Связь с реквизитами получателя (requisiteId/bankDetailId/mcRequisiteId/mcBankDetailId); `[]` если не задана; только чтение | ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true }, "accountNumber": { "type": "string", "readonly": true }, "price": { "type": "number", "readonly": false }, "currency": { "type": "string", "readonly": false }, "statusId": { "type": "string", "readonly": false }, "userId": { "type": "number", "readonly": false }, "dateInsert": { "type": "datetime", "readonly": true }, "dateUpdate": { "type": "datetime", "readonly": true }, "payed": { "type": "boolean", "readonly": true }, "canceled": { "type": "boolean", "readonly": false } }, "aggregatable": ["price", "statusId", "payed", "canceled", "personTypeId", "responsibleId", "userId"], "batch": ["create", "update", "delete"] } } ``` Показаны самые важные поля. Полный набор описан в таблице выше — этот же набор возвращается живым вызовом `GET /v1/orders/fields`. ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'sale' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список заказов](./list.md) - [Создать заказ](./create.md) - [Агрегация заказов](./aggregate.md) - [Entity API](/docs/entity-api) - [Лимиты и оптимизация](/docs/optimization) --- # Orders: Get ## Получить заказ `GET /v1/orders/:id` Возвращает один заказ по идентификатору со всеми полями. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор заказа | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/orders/845" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/orders/845" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/orders/845', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Заказ:', data.accountNumber, '—', data.price, data.currency) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/orders/845', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа Объект заказа со всеми полями — см. [Поля заказа](./fields.md). Дополнительно ответ содержит вложенные массивы: | Поле | Описание | |------|---------| | `basketItems[]` | Полные объекты [позиций корзины](../basket-items.md) этого заказа | | `payments[]` | Полные объекты [оплат](../payments.md) этого заказа | | `propertyValues[]` | Значения свойств заказа: ФИО, e-mail, телефон, адрес доставки и другие. Набор зависит от настройки портала | | `clients[]` | CRM-привязки к контактам и компаниям. Каждый элемент: `{entityTypeId, entityId, isPrimary, roleId, sort}` | | `requisiteLink` | Связь с реквизитами получателя | | `tradeBindings[]` | Привязки к внешним торговым площадкам | Массивы `clients`, `payments`, `basketItems`, `propertyValues` возвращает только `GET /v1/orders/:id` — в списке [`GET /v1/orders`](./list.md) их нет. Все четыре только для чтения. Логические поля внутри вложенных объектов приходят как `true`/`false` — `clients[].isPrimary`, `payments[].paid`, `basketItems[].vatIncluded` и другие, даты — в UTC формате `…Z`. ## Пример ответа ```json { "success": true, "data": { "id": 845, "accountNumber": "443", "lid": "s1", "personTypeId": 5, "currency": "RUB", "price": 100, "discountValue": 0, "taxValue": 0, "statusId": "N", "dateInsert": "2026-04-21T06:48:16.000Z", "dateUpdate": "2026-04-21T06:48:16.000Z", "dateStatus": "2026-04-21T06:48:16.000Z", "payed": false, "canceled": false, "marked": false, "deducted": false, "responsibleId": 1, "userId": 1, "companyId": 15, "clients": [ { "entityTypeId": 3, "entityId": 2471, "isPrimary": true, "roleId": 0, "sort": 0 }, { "entityTypeId": 4, "entityId": 15, "isPrimary": true, "roleId": 0, "sort": 0 } ], "basketItems": [ { "id": 187, "productId": 1119, "name": "Спортивный Костюм Розовый Вихрь", "price": 12, "currency": "RUB", "quantity": 1, "vatRate": 0, "vatIncluded": true } ], "payments": [ { "id": 117, "paySystemId": 11, "paySystemName": "Наличные", "sum": 100, "currency": "RUB", "paid": true, "datePaid": "2026-04-21T06:48:16.000Z" } ], "propertyValues": [ { "id": 9311, "orderPropsId": 41, "code": "EMAIL", "name": "E-Mail", "value": "buyer@example.com" } ], "comments": "", "xmlId": "", "externalOrder": false } } ``` ## Пример ответа при ошибке 422 — заказ не найден: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "order is not exists" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Заказ с таким ID не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Поля заказа](./fields.md) - [Обновить заказ](./update.md) - [Удалить заказ](./delete.md) - [Список заказов](./list.md) - [Позиции корзины заказа](../basket-items.md) - [Оплаты заказа](../payments.md) - [Лимиты и оптимизация](/docs/optimization) --- # Orders: List ## Список заказов `GET /v1/orders` Возвращает список заказов интернет-магазина с поддержкой фильтрации и автоматической пагинации. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` ответ собирается из нескольких последовательных чтений по 50 записей | | `offset` | number | `0` | Пропустить N записей — построчно: `offset=7` начинает выборку с 8-й записи. При `offset ≥ 2500` рекомендуется `limit ≤ 500`. Для глубокой навигации надёжнее курсор — `order[id]=asc` и `filter[>id]` со значением `id` последней записи предыдущего ответа. Поля `meta.nextAfterId` у заказов нет, идентификатор берётся из последнего элемента `data` | | `select` | string | — | Выборка полей: `?select=id,price,currency,statusId` | | `order` | object | — | Сортировка: `?order[id]=desc` | | `filter` | object | — | Фильтрация по полям `GET /v1/orders/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[statusId]=N` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/orders?limit=10&filter[statusId]=N&order[id]=desc" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/orders?limit=10&filter[statusId]=N&order[id]=desc" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/orders?limit=10&filter[statusId]=N&order[id]=desc', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} заказов`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/orders?limit=10&filter[statusId]=N&order[id]=desc', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив заказов (каждый содержит все поля — см. [Поля заказа](./fields.md)) | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | URL любого заказа из массива `data` — его `id`: ``` https://.bitrix24.ru/shop/orders/details// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 845, "accountNumber": "443", "price": 100, "currency": "RUB", "statusId": "N", "userId": 1, "personTypeId": 5, "lid": "s1", "payed": false, "canceled": false, "responsibleId": 1, "dateInsert": "2026-04-21T06:48:16.000Z", "dateUpdate": "2026-04-21T06:48:16.000Z" }, { "id": 841, "accountNumber": "441", "price": 100.5, "currency": "RUB", "statusId": "N", "userId": 9, "personTypeId": 5, "lid": "s1", "payed": false, "canceled": false, "responsibleId": 1, "dateInsert": "2026-04-04T20:02:28.000Z", "dateUpdate": "2026-04-04T20:02:28.000Z" } ], "meta": { "total": 194, "hasMore": true } } ``` Показаны основные поля. Полный список — [Поля заказа](./fields.md). ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'sale' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет в схеме. Список полей: [`GET /v1/orders/fields`](./fields.md) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Автоматическая пагинация:** при `limit > 50` Вайбкод автоматически запрашивает несколько страниц у Битрикс24 и возвращает все записи в одном ответе. `meta.total` отражает общее количество записей, удовлетворяющих фильтру. **Когда использовать `search` вместо `list`:** [`POST /v1/orders/search`](./search.md) передаёт параметры в теле запроса, а не в строке запроса — подходит для сложных фильтров с множеством условий. ## Смотрите также - [Поиск заказов](./search.md) - [Получить заказ](./get.md) - [Создать заказ](./create.md) - [Поля заказа](./fields.md) - [Синтаксис фильтрации](/docs/filtering) - [Entity API](/docs/entity-api) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Orders: Search ## Поиск заказов `POST /v1/orders/search` Поиск заказов с фильтрацией, сортировкой и автоматической пагинацией. Аналогичен [`GET /v1/orders`](./list.md), но параметры передаются в теле POST-запроса — подходит для сложных запросов с большим количеством условий. ## Поля запроса (body) | Поле | Тип | По умолч. | Описание | |------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям `GET /v1/orders/fields`.
[Синтаксис фильтрации](/docs/filtering) | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки» | | `select` | string[] | — | Выборка полей: `["id", "price", "currency", "statusId"]` | | `order` | object | — | Сортировка: `{ "id": "desc" }` | | `autoWindow` | boolean | `true` | Разбивать выборку по недельным окнам при фильтре по диапазону дат шире 14 дней. `false` отключает разбиение | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/orders/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "statusId": "N", "payed": false }, "limit": 10, "select": ["id", "price", "currency", "statusId", "dateInsert"] }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/orders/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "statusId": "N", "payed": false }, "limit": 10, "select": ["id", "price", "currency", "statusId", "dateInsert"] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/orders/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { statusId: 'N', payed: false }, limit: 10, select: ['id', 'price', 'currency', 'statusId', 'dateInsert'], }), }) const { success, data, meta } = await res.json() console.log('Найдено:', meta.total) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/orders/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { statusId: 'N', payed: false }, limit: 10, select: ['id', 'price', 'currency', 'statusId', 'dateInsert'], }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив заказов (поля — см. [Поля заказа](./fields.md)) | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временны́м окнам | | `meta.windowCount` | number | Число окон. Приходит при `autoWindowed: true` | | `meta.batchWaves` | number | Число волн параллельных запросов. Приходит при `autoWindowed: true` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. URL любого заказа из массива `data` — его `id`: ``` https://.bitrix24.ru/shop/orders/details// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 845, "price": 100, "currency": "RUB", "statusId": "N", "dateInsert": "2026-04-21T06:48:16.000Z" }, { "id": 841, "price": 100.5, "currency": "RUB", "statusId": "N", "dateInsert": "2026-04-04T20:02:28.000Z" } ], "meta": { "total": 181, "hasMore": true, "durationMs": 211 } } ``` С фильтром по диапазону дат шире 14 дней в `meta` дополнительно приходят `autoWindowed`, `windowCount` и `batchWaves`: ```json { "success": true, "data": [ /* ... */ ], "meta": { "total": 37, "hasMore": true, "autoWindowed": true, "windowCount": 131, "batchWaves": 3, "durationMs": 1299 } } ``` ## Пример ответа при ошибке 400 — фильтр по несуществующему полю: ```json { "success": false, "error": { "code": "UNKNOWN_FILTER_FIELD", "message": "Unknown filter field 'foo' for entity 'orders'. Available: id, accountNumber, price, currency, statusId, userId, ..." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет в схеме. Список полей: [`GET /v1/orders/fields`](./fields.md) | | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Разбиение по временны́м окнам.** Фильтр по диапазону дат шире 14 дней автоматически разбивается на недельные окна, которые выполняются параллельными волнами — так выборка обходит потолок в 5000 записей на один вызов. В `meta` тогда приходят `autoWindowed: true`, число окон `windowCount` и число волн `batchWaves`. Отключает разбиение параметр `autoWindow: false`. При активном разбиении `offset` больше нуля отклоняется с `UNSTABLE_OFFSET_PAGINATION`. **`select` ограничивает поля в ответе.** Если передан `select`, в каждом элементе `data[]` будут только перечисленные поля. Без `select` возвращаются все поля заказа. ## Смотрите также - [Список заказов](./list.md) - [Получить заказ](./get.md) - [Поля заказа](./fields.md) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Orders: Update ## Обновить заказ `PATCH /v1/orders/:id` Обновляет поля существующего заказа. Передавайте только изменяемые поля плоско в корне JSON — без обёртки `fields`. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор заказа | ## Поля запроса (body) | Поле | Тип | Описание | |------|-----|---------| | `statusId` | string | Новый статус заказа. Список: [`GET /v1/order-statuses?filter[type]=O`](../order-statuses/list.md). Усекается до 2 символов без ошибки | | `discountValue` | number | Значение скидки | | `canceled` | boolean | Отменён ли заказ | | `reasonCanceled` | string | Причина отмены | | `comments` | string | Комментарий менеджера | | `userDescription` | string | Комментарий покупателя | | `responsibleId` | number | Ответственный сотрудник | | `userId` | number | Пользователь Битрикс24 — покупатель. Существование не проверяется | | `companyId` | number | Идентификатор CRM-компании заказа. Источник: [`GET /v1/companies`](/docs/entities/companies). Приходит `null`, если компания не задана | | `xmlId` | string | Внешний идентификатор | Полный список редактируемых полей — [`GET /v1/orders/fields`](./fields.md) (поля без флага `readonly`). **`price`, `marked` и `reasonMarked` на обновлении отклоняются с `400 READONLY_FIELD`.** Их принимает только [создание](./create.md): метод обновления Битрикс24 эти поля не сохраняет. Прежде запрос возвращал `200`, а значение молча терялось — для `price` с потерей данных, потому что сумма пересчитывается из позиций корзины и при пустой корзине становится `0`. Чтобы изменить сумму после создания, меняйте [позиции корзины](../basket-items/create.md). `payed` доступен только для чтения и на создании тоже — управляется подсистемой оплат. ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/orders/845" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "statusId": "F", "comments": "Закрыт после полной оплаты" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/orders/845" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "statusId": "F", "comments": "Закрыт после полной оплаты" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/orders/845', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ statusId: 'F', comments: 'Закрыт после полной оплаты', }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/orders/845', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ statusId: 'F', comments: 'Закрыт после полной оплаты', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | object | Обновлённый объект заказа со всеми полями (см. [Поля заказа](./fields.md)) | ## Пример ответа ```json { "success": true, "data": { "id": 845, "accountNumber": "443", "statusId": "F", "price": 100, "currency": "RUB", "payed": true, "canceled": false, "comments": "Закрыт после полной оплаты", "dateInsert": "2026-04-21T06:48:16.000Z", "dateUpdate": "2026-05-13T11:45:32.000Z", "dateStatus": "2026-05-13T11:45:32.000Z", "userId": 1, "companyId": 15, "clients": [ { "entityTypeId": 3, "entityId": 2471, "isPrimary": true, "roleId": 0, "sort": 0 }, { "entityTypeId": 4, "entityId": 15, "isPrimary": true, "roleId": 0, "sort": 0 } ], "responsibleId": 1 } } ``` ## Пример ответа при ошибке 422 — заказ не найден: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "order is not exists" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Заказ с таким ID не найден | | 400 | `BITRIX_ERROR` | Некорректное значение поля — например, неизвестный `statusId` | | 400 | `READONLY_FIELD` | Передано поле только для чтения — например `accountNumber`. Номер заказа присваивается автоматически. Сюда же попадают `price`, `marked` и `reasonMarked`: они принимаются только при создании | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Дата `dateStatus` обновляется автоматически.** При изменении `statusId` поле `dateStatus` получает текущее время — не передавайте его в запросе. **Поля `accountNumber`, `dateInsert`, `personTypeXmlId`, `statusXmlId` и другие системные — только для чтения.** Попытка передать их на обновлении отклоняется с `400 READONLY_FIELD`. ## Смотрите также - [Получить заказ](./get.md) - [Список заказов](./list.md) - [Удалить заказ](./delete.md) - [Поля заказа](./fields.md) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Pages: Aggregate ## Агрегация страниц `POST /v1/pages/aggregate` Подсчёт количества страниц с учётом фильтра и группировка по категориальным полям. Поддерживает функцию `count` и группировку `groupBy`. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций. Для страниц осмысленна `{ "field": "*", "function": "count" }` — числовых полей для `sum`/`avg`/`min`/`max` у сущности нет. Без параметра возвращается `count` записей с учётом фильтра | | `groupBy` | string \| array | нет | Поле или поля для группировки. Допустимы только поля из `aggregatable`: `siteId`, `active`, `deleted`, `public`, `folderId`, `tplId`, `createdById`, `modifiedById`. До 5 полей | | `filter` | object | нет | Фильтрация по полям страницы.
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "siteId": 12 }` | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/pages/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "groupBy": "siteId" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/pages/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "groupBy": "siteId" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/pages/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ groupBy: 'siteId', }), }) const { success, data } = await res.json() console.log('Страниц по сайтам:', data.groups) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/pages/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ groupBy: 'siteId', }), }) const { success, data } = await res.json() ``` ## Другие сценарии Общее количество страниц в портале — без выгрузки записей: ```json {} ``` Количество страниц одного сайта: ```json { "filter": { "siteId": 12 } } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Количество страниц, соответствующих фильтру | | `data.aggregates` | object | Результаты числовых агрегаций. Для страниц остаётся пустым — нет числовых полей | | `data.groups` | array | Присутствует при `groupBy`. Каждый элемент — значение измерения плюс `count` записей в группе | | `data.meta.totalRecords` | number | Общее количество записей | | `data.meta.recordsProcessed` | number | Сколько записей обработано | | `data.meta.truncated` | boolean | Был ли результат ограничен (`true` при более 5000 записей) | | `data.meta.groupTotal` | number | Присутствует при `groupBy` — количество групп | | `data.meta.groupsTruncated` | boolean | Присутствует при `groupBy`. `true`, если число групп превысило лимит и список групп усечён | ## Пример ответа Группировка по сайту (`groupBy: "siteId"`): ```json { "success": true, "data": { "count": 84, "aggregates": {}, "groups": [ { "siteId": 12, "count": 9, "aggregates": {} }, { "siteId": 14, "count": 6, "aggregates": {} }, { "siteId": 27, "count": 11, "aggregates": {} } ], "meta": { "totalRecords": 84, "recordsProcessed": 84, "truncated": false, "groupTotal": 5, "groupsTruncated": false } } } ``` Простой подсчёт без группировки (`{}`): ```json { "success": true, "data": { "count": 84, "aggregates": {}, "meta": { "totalRecords": 84, "recordsProcessed": 0, "truncated": false } } } ``` ## Пример ответа при ошибке 400 — поле вне списка `aggregatable`: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "groupBy field 'title' is not aggregatable on this entity. Available: siteId, active, deleted, public, folderId, tplId, createdById, modifiedById." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Поле `groupBy` вне списка `aggregatable` или неизвестная функция агрегации | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `landing` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Группировка считается по выборке.** При более 5000 записей (`meta.truncated: true`) счётчики групп основаны на выборке из 5000 записей, а верхний `count` остаётся точным общим числом по фильтру. **Видимость по правам пользователя.** В подсчёт попадают только страницы, к которым у владельца API-ключа есть право «просмотр». Если ожидается ненулевой результат, но `count` равен нулю — проверьте права пользователя, под которым выпущен ключ. ## Смотрите также - [Список страниц](/docs/entities/pages/list) - [Поиск страниц](/docs/entities/pages/search) - [Поля страницы](/docs/entities/pages/fields) - [Синтаксис фильтрации](/docs/filtering) --- # Pages: Create ## Создать страницу `POST /v1/pages` Создаёт новую страницу на указанном сайте. Поля передаются плоско в корне JSON — без обёртки `fields`. Минимум для создания: `title` + `siteId`. Новая страница создаётся неактивной — `active: false`. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `title` | string | да | Название страницы, до 255 символов | | `siteId` | number | да | Идентификатор сайта. Источник: [`GET /v1/sites`](/docs/entities/sites/list) | | `code` | string | нет | Символьный код страницы в URL. Не должен содержать `/`. Если оставить пустым или не передать — генерируется из `title`. Если код уже занят на сайте — добавляется числовой суффикс | | `description` | string | нет | Произвольное описание страницы | | `public` | string | нет | Публичность — `Y` / `N` | | `sitemap` | string | нет | Включить в карту сайта — `Y` / `N` | | `xmlId` | string | нет | Внешний код | | `folderId` | number | нет | ID папки-раздела сайта | | `tplId` | number | нет | ID шаблона | > Полный перечень полей — [`GET /v1/pages/fields`](./fields.md): эндпоинт возвращает карту всех полей с типом, признаком `readonly` и подписью. Записывать можно поля, у которых `readonly` отсутствует. Перечисленные выше дополнительные поля применяются при создании наравне с `title`/`siteId`/`code`/`description`. **Публикация — отдельный вызов.** Поле `active` в теле создания не принимается: запрос с ним отклоняется целиком с `400 READONLY_FIELD`, страница не создаётся. Опубликовать созданную страницу — `POST /v1/pages/:id/publication`, снять с публикации — `POST /v1/pages/:id/unpublish`. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/pages" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Весенняя акция", "code": "spring-sale", "siteId": 3, "description": "Лендинг сезонной акции на скидки" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/pages" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Весенняя акция", "code": "spring-sale", "siteId": 3, "description": "Лендинг сезонной акции на скидки" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/pages', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Весенняя акция', code: 'spring-sale', siteId: 3, description: 'Лендинг сезонной акции на скидки', }), }) const { success, data } = await res.json() console.log('Page ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/pages', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Весенняя акция', code: 'spring-sale', siteId: 3, description: 'Лендинг сезонной акции на скидки', }), }) const { success, data } = await res.json() ``` ## Поля ответа Возвращается полный объект созданной страницы. | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор созданной страницы | | `title` | string | Название страницы | | `code` | string | Фактический символьный код (с авто-суффиксом, если код запроса был занят) | | `siteId` | number | Идентификатор сайта | | `active` | boolean | Всегда `false` для только что созданной страницы | | `description` | string \| null | Описание страницы | | `createdById` | number | Идентификатор создавшего сотрудника | | `dateCreate` | datetime | Дата создания. Строка в формате локали портала, не ISO 8601 | | `dateModify` | datetime | Дата последнего изменения | > **Формат дат.** `dateCreate` и `dateModify` — строки в формате локали портала, **не** ISO 8601 (`30.12.2021 12:30:52` на RU-локали, `12/30/2021 12:30:52 pm` на EN-локали). Формат одинаков в списке и в карточке; `new Date()` на таком значении полагаться нельзя. Подробнее: [Справочник полей](/docs/entities/pages/fields). URL страницы в Битрикс24 строится из `id` и `siteId`: ``` https://.bitrix24.ru/sites/site//view// ``` `` — ID сайта, которому принадлежит страница (поле `siteId` в ответе). `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": { "id": 2295, "title": "Весенняя акция", "code": "spring-sale", "siteId": 3, "active": false, "description": "Лендинг сезонной акции на скидки", "createdById": 1, "dateCreate": "08.05.2026 11:49:33", "dateModify": "08.05.2026 11:49:33" } } ``` ## Пример ответа при ошибке 422 — не передано обязательное поле `title`: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Не заполнено обязательное поле «Название страницы»" } } ``` ## Ошибки | HTTP | `error.code` | Маркер в `error.message` | Описание | |------|--------------|--------------------------|---------| | 400 | `READONLY_FIELD` | — | В теле передано поле только для чтения — например `active`. Страница не создаётся | | 422 | `BITRIX_ERROR` | `Не заполнено обязательное поле` | Пропущено `title` или `siteId` | | 422 | `BITRIX_ERROR` | `Слеш запрещен в адресе лендинга` | В `code` передан символ `/` — слеши в коде запрещены | | 422 | `BITRIX_ERROR` | `Адрес страницы не может быть пустым` | В `code` передана пустая строка без указания, что создаётся папка | | 422 | `BITRIX_ERROR` | `Недопустимый адрес страницы` | В `code` передано значение в формате `__`, например `code_12_34` | | 404 | `ENTITY_NOT_FOUND` | `Сайт не найден` | В `siteId` передан несуществующий идентификатор сайта | | 403 | `BITRIX_ACCESS_DENIED` | — | У пользователя нет права «редактирование» для указанного сайта | | 403 | `SCOPE_DENIED` | — | API-ключ не имеет скоупа `landing` | | 401 | `TOKEN_MISSING` | — | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список страниц](/docs/entities/pages/list) - [Получить страницу](/docs/entities/pages/get) - [Обновить страницу](/docs/entities/pages/update) - [Удалить страницу](/docs/entities/pages/delete) - [Сайты](/docs/entities/sites) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Pages: Delete ## Удалить страницу `DELETE /v1/pages/:id` Удаляет страницу по идентификатору. Восстановить удалённую страницу через API нельзя — создавайте новую при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор страницы | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/pages/2295" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/pages/2295" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/pages/2295', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Страница удалена') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/pages/2295', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Страница удалена') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — успех проверяется по статусу. ## Пример ответа ```http HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — страница не найдена или уже удалена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Лендинг не найден." } } ``` ## Ошибки | HTTP | `error.code` | Описание | |------|--------------|---------| | 404 | `ENTITY_NOT_FOUND` | Страница с таким ID не найдена или уже удалена | | 403 | `BITRIX_ACCESS_DENIED` | У пользователя нет права на удаление этой страницы | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `landing` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Удаление освобождает код страницы.** После удаления символьный код снова свободен — новую страницу с тем же `code` на том же сайте можно создать сразу. ## Смотрите также - [Список страниц](/docs/entities/pages/list) - [Получить страницу](/docs/entities/pages/get) - [Удалить сайт](/docs/entities/sites/delete) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Pages: Fields ## Поля страницы `GET /v1/pages/fields` Возвращает карту всех полей страницы с типом, подписью и признаком только для чтения, а у полей, которые могут прийти пустыми, — с признаком `nullable`. Поля без признака только для чтения доступны для записи при создании и обновлении. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/pages/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/pages/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/pages/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data.fields).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/pages/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа Объект `data` содержит карту `fields` (имя поля → `{ type, readonly, label }`, у части полей есть ещё `description`, а у полей, которые могут прийти пустыми, — `nullable`), список `batch` с операциями массового режима, список доступных `include` и набор `aggregatable` полей для группировки в [агрегации](./aggregate.md). | Поле | Битрикс24 | Тип | RO | Описание | |------|----------|-----|:--:|---------| | `id` | `ID` | number | да | Идентификатор страницы | | `title` | `TITLE` | string | | Название, до 255 символов | | `code` | `CODE` | string | | Символьный код в URL. Без `/`, авто-генерация из `title` | | `siteId` | `SITE_ID` | number | | Сайт-владелец. Источник: `GET /v1/sites` | | `active` | `ACTIVE` | boolean | да | Опубликована ли страница. Битрикс24 не принимает поле ни на создании, ни на обновлении, а новая страница всегда создаётся неактивной. Публикация — `POST /v1/pages/:id/publication`, снятие с публикации — `POST /v1/pages/:id/unpublish` | | `description` | `DESCRIPTION` | string \| null | | Описание. `null`, если не задано | | `xmlId` | `XML_ID` | string \| null | | Внешний код. `null`, если не задан | | `deleted` | `DELETED` | string | да | Признак корзины: `"Y"` / `"N"` | | `public` | `PUBLIC` | string | | Публичность: `"Y"` / `"N"` | | `sys` | `SYS` | string | да | Системная страница Битрикс24: `"Y"` / `"N"` | | `views` | `VIEWS` | number | да | Счётчик просмотров | | `tplId` | `TPL_ID` | number \| null | | Идентификатор шаблона. `null`, если шаблон не используется | | `tplCode` | `TPL_CODE` | string \| null | да | Символьный код шаблона. `null`, если шаблон не используется | | `sitemap` | `SITEMAP` | string | | Включать в карту сайта: `"Y"` / `"N"` | | `folder` | `FOLDER` | string | | Является ли страница папкой-разделом: `"Y"` / `"N"` | | `folderId` | `FOLDER_ID` | number \| null | | Идентификатор папки-раздела сайта. `null`, если страница лежит в корне сайта | | `searchContent` | `SEARCH_CONTENT` | string \| null | да | Индексируемое содержимое страницы для поиска по сайту. `null`, пока страница не проиндексирована | | `version` | `VERSION` | number | да | Версия внутренней структуры страницы | | `historyStep` | `HISTORY_STEP` | number | да | Служебное поле истории изменений | | `modifiedById` | `MODIFIED_BY_ID` | number | да | Последний редактор. Поиск: `GET /v1/users` | | `domainId` | `DOMAIN_ID` | number | да | Идентификатор домена сайта | | `initiatorAppCode` | `INITIATOR_APP_CODE` | string \| null | да | Код приложения, создавшего страницу. `null`, если страницу создали в интерфейсе Битрикс24 | | `rule` | `RULE` | string \| null | да | Служебное поле Битрикс24. Как правило, `null` | | `createdById` | `CREATED_BY_ID` | number | да | Создатель. Поиск: `GET /v1/users` | | `dateCreate` | `DATE_CREATE` | datetime | да | Дата создания. Строка в формате локали портала, не ISO 8601 — см. блок про формат ниже | | `dateModify` | `DATE_MODIFY` | datetime | да | Дата последнего изменения. Формат тот же, что у `dateCreate` | | `datePublic` | `DATE_PUBLIC` | datetime \| null | да | Дата публикации, формат тот же, что у `dateCreate`. Приходит `null`, если у Битрикс24 нет даты публикации по странице, — это обычный случай даже для опубликованной страницы. Факт публикации определяйте по `active` или `public` | ## Поля, которые могут быть пустыми У поля, которое Битрикс24 не всегда заполняет, в ответе эндпоинта стоит `"nullable": true`, а в таблице выше тип записан как `… | null`. Таких полей девять: `description`, `xmlId`, `tplId`, `tplCode`, `folderId`, `searchContent`, `initiatorAppCode`, `rule`, `datePublic`. Значение приходит как `null` — не как пустая строка и не как `0`, — поэтому проверяйте его перед разбором. У остальных полей значение есть всегда. ## Формат дат **Даты — строки в формате локали портала, НЕ ISO 8601.** `dateCreate`, `dateModify` и `datePublic` Битрикс24 отдаёт строкой, и **конкретный шаблон зависит от региональных настроек портала**: на RU-локали это `ДД.ММ.ГГГГ ЧЧ:ММ:СС` (`30.12.2021 12:30:52`), на EN-локали — `MM/DD/YYYY hh:mm:ss am/pm` (`12/30/2021 12:30:52 pm`). Вайбкод отдаёт значение как есть, без приведения к ISO, **одинаково в списке и в карточке** — расхождения между `GET /v1/pages` и `GET /v1/pages/:id` нет. `new Date(value)` вернёт `Invalid Date` либо тихо перепутает день и месяц: не разбирайте дату по фиксированному шаблону и не доверяйте `new Date()`. Тот же формат нужен и в фильтре — см. [Поиск страниц](/docs/entities/pages/search). ## Доступные include Эндпоинт возвращает список доступных include: `site` — сайт-владелец страницы. Подробнее: [Связанные данные](/docs/includes). ## Пример ответа Каждое поле, помимо `type` и `readonly`, содержит `label` (короткое название) и `description` (пояснение) на русском языке. У поля, которое может прийти пустым, дополнительно стоит `nullable`. В примере ниже `description` показан только у `active` — у остальных полей он опущен для краткости. ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "ID страницы" }, "title": { "type": "string", "readonly": false, "label": "Название" }, "siteId": { "type": "number", "readonly": false, "label": "ID сайта" }, "active": { "type": "boolean", "readonly": true, "label": "Активна", "description": "Опубликована ли страница. Только для чтения: Битрикс24 не принимает поле ни на создании, ни на обновлении, а новая страница всегда создаётся неактивной. Публикация через POST /v1/pages/:id/publication и снятие с публикации через POST /v1/pages/:id/unpublish." }, "xmlId": { "type": "string", "readonly": false, "nullable": true, "label": "Внешний идентификатор" }, "datePublic": { "type": "datetime", "readonly": true, "nullable": true, "label": "Дата публикации" } }, "relations": { "site": { "type": "one", "entity": "site", "includable": true } }, "aggregatable": ["siteId", "active", "deleted", "public", "folderId", "tplId", "createdById", "modifiedById"], "batch": ["create", "update", "delete"], "include": ["site"] } } ``` Показаны 6 из 27 полей. Полный список — в таблице выше. ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'landing' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `landing` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать страницу](/docs/entities/pages/create) - [Обновить страницу](/docs/entities/pages/update) - [Агрегация страниц](/docs/entities/pages/aggregate) - [Страницы](/docs/entities/pages) - [Entity API](/docs/entity-api) --- # Pages: Get ## Получить страницу `GET /v1/pages/:id` Возвращает одну страницу по идентификатору. Удалённые страницы этим эндпоинтом не возвращаются — на запрос вернётся `404 ENTITY_NOT_FOUND`. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор страницы | | `scope` (query) | string | нет | Внутренняя область лендингов: `KNOWLEDGE` / `GROUP` / `MAINPAGE`. Указывайте, если страница принадлежит соответствующей области. Иначе возвращается `404 ENTITY_NOT_FOUND`. Пример: `GET /v1/pages/9?scope=KNOWLEDGE` | | `select` (query) | string | нет | Выборка полей: `?select=id,title`. Поле `id` возвращается всегда | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/pages/9" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/pages/9" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/pages/9', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Страница:', data.title, '— сайт:', data.siteId) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/pages/9', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор страницы | | `title` | string | Название страницы | | `code` | string | Символьный код страницы | | `siteId` | number | Идентификатор сайта | | `active` | boolean | Активна ли страница | | `description` | string \| null | Произвольное описание | | `createdById` | number | Идентификатор создавшего сотрудника | | `dateCreate` | datetime | Дата создания. Строка в формате локали портала, не ISO 8601 — см. блок ниже | | `dateModify` | datetime | Дата последнего изменения. Тот же формат | > **Формат дат — локаль-зависимый, НЕ ISO 8601.** Битрикс24 возвращает `dateCreate`/`dateModify` строкой в локальном формате, и **конкретный шаблон зависит от региональных настроек портала**: на RU-локали это `ДД.ММ.ГГГГ ЧЧ:ММ:СС` (`30.12.2021 12:30:52`), на EN-локали — `MM/DD/YYYY hh:mm:ss am/pm` (`04/22/2020 02:39:17 pm`). Вайбкод отдаёт значение Битрикс24 как есть, без приведения к ISO, и **одинаково в карточке и в списке** — расхождения между `GET /v1/pages/:id` и `GET /v1/pages` нет. `new Date(value)` вернёт `Invalid Date` либо тихо перепутает день и месяц — **не разбирайте дату по фиксированному шаблону и не доверяйте `new Date()`**. Ориентируйтесь на региональные настройки конкретного портала. ## Пример ответа ```json { "success": true, "data": { "id": 9, "title": "Тест переноса страниц", "code": "change1", "siteId": 3, "active": true, "description": null, "createdById": 1, "dateCreate": "30.12.2021 12:30:52", "dateModify": "30.12.2021 12:30:53" } } ``` ## Пример ответа при ошибке 404 — страница не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "landingPage 999999999 not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Страница с таким ID не найдена, удалена или недоступна пользователю | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `landing` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список страниц](/docs/entities/pages/list) - [Обновить страницу](/docs/entities/pages/update) - [Удалить страницу](/docs/entities/pages/delete) - [Лимиты и оптимизация](/docs/optimization) --- # Pages: List ## Список страниц `GET /v1/pages` Возвращает список страниц лендингов и интернет-магазинов с поддержкой фильтрации и автопагинации. По умолчанию возвращаются только не удалённые страницы. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей | | `select` | string | — | Выборка полей: `?select=id,title,code,siteId,active`. Без `select` ответ содержит полный набор полей страницы в camelCase (как в карточке) | | `filter` | object | — | Фильтрация по ключевым полям страницы.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[siteId]=3`. Булево `active` принимается как `true`/`false`, `1`/`0` или `Y`/`N` | | `scope` | string | — | Внутренняя область лендингов. Допустимые значения: `KNOWLEDGE` (страницы базы знаний), `GROUP` (страницы рабочих групп), `MAINPAGE` (главные страницы). Без параметра возвращаются страницы обычных сайтов-лендингов. Принимается как `?scope=KNOWLEDGE` или `?filter[scope]=KNOWLEDGE` — обе формы дают одинаковый запрос к Битрикс24 | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/pages?filter[siteId]=3&limit=10&select=id,title,code,siteId,active,dateCreate,dateModify" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/pages?filter[siteId]=3&limit=10&select=id,title,code,siteId,active,dateCreate,dateModify" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const params = new URLSearchParams({ 'filter[siteId]': '3', limit: '10', select: 'id,title,code,siteId,active,dateCreate,dateModify', }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/pages?${params}`, { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} страниц`) ``` ### JavaScript — OAuth-приложение ```javascript const params = new URLSearchParams({ 'filter[siteId]': '3', limit: '10', select: 'id,title,code,siteId,active,dateCreate,dateModify', }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/pages?${params}`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив страниц | | `data[].id` | number | Идентификатор страницы | | `data[].title` | string | Название страницы | | `data[].code` | string | Символьный код страницы | | `data[].siteId` | number | Идентификатор сайта | | `data[].active` | boolean | Активна ли страница | | `data[].description` | string \| null | Произвольное описание | | `data[].createdById` | number | Идентификатор создавшего сотрудника | | `data[].dateCreate` | datetime | Дата создания. Строка в формате локали портала, не ISO 8601 | | `data[].dateModify` | datetime | Дата последнего изменения. Тот же формат | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | > **Формат дат.** `dateCreate` и `dateModify` — строки в формате локали портала, **не** ISO 8601 (`30.12.2021 12:30:52` на RU-локали, `12/30/2021 12:30:52 pm` на EN-локали). Формат одинаков в списке и в карточке; `new Date()` на таком значении полагаться нельзя. Подробнее: [Справочник полей](/docs/entities/pages/fields). URL любой страницы из массива `data` строится из её `id` и `siteId`: ``` https://.bitrix24.ru/sites/site//view// ``` `` — ID сайта, которому принадлежит страница (поле `siteId` каждого элемента). `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 9, "title": "Тест переноса страниц", "code": "change1", "siteId": 3, "active": true, "description": null, "createdById": 1, "dateCreate": "26.05.2020 17:24:02", "dateModify": "10.10.2022 15:25:30" }, { "id": 7, "title": "Test page", "code": "test", "siteId": 3, "active": true, "description": null, "createdById": 1, "dateCreate": "25.05.2020 17:34:17", "dateModify": "10.10.2022 15:25:30" } ], "meta": { "total": 13, "hasMore": true } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'landing' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку — текст в `error.message` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `landing` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Постраничный переход через `offset` поддерживается.** Вайбкод возвращает запрошенное окно `[offset, offset + limit)`. Значение `meta.total` — точное число записей под фильтром, а `meta.hasMore` показывает, есть ли записи за пределами окна. **Сортировка.** Поддерживается через `?order[поле]=asc|desc` или короткую форму `?sort=-поле` (по убыванию). Без параметра выборка идёт по возрастанию `id`. **База знаний и другие внутренние области.** Параметр `scope` переключает источник: `KNOWLEDGE` — страницы базы знаний, `GROUP` — страницы рабочих групп, `MAINPAGE` — главные страницы. Без параметра возвращаются страницы обычных сайтов-лендингов (источник по умолчанию). Пример: `GET /v1/pages?scope=KNOWLEDGE` возвращает страницы базы знаний. ## Смотрите также - [Получить страницу](/docs/entities/pages/get) - [Поиск страниц](/docs/entities/pages/search) - [Создать страницу](/docs/entities/pages/create) - [Обновить страницу](/docs/entities/pages/update) - [Удалить страницу](/docs/entities/pages/delete) - [Сайты](/docs/entities/sites) - [Синтаксис фильтрации](/docs/filtering) - [Entity API](/docs/entity-api) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Pages: Search ## Поиск страниц `POST /v1/pages/search` Возвращает список страниц по фильтру в теле запроса. По сравнению с [`GET /v1/pages`](./list.md) удобнее для сложных условий: параметры передаются в JSON, можно использовать вложенные операторы (`>=`, `<=`, `!`, `in`) в стиле MongoDB. ## Поля запроса (body) | Поле | Тип | По умолч. | Описание | |------|-----|-----------|---------| | `filter` | object | — | Фильтр по ключевым полям страницы.
[Синтаксис фильтрации](/docs/filtering). Пример: `{"filter": {"siteId": 3}}` | | `select` | string[] | — | Список полей для возврата. Без `select` ответ содержит полный набор полей страницы в camelCase (как в карточке) | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей | | `scope` | string | — | Внутренняя область лендингов: `KNOWLEDGE` / `GROUP` / `MAINPAGE`. Без параметра возвращаются страницы обычных сайтов-лендингов. Принимается на верхнем уровне тела (`"scope": "KNOWLEDGE"`) или внутри `filter.scope` — обе формы дают одинаковый запрос к Битрикс24 | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/pages/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "siteId": 3 }, "select": ["id", "title", "code", "siteId", "active", "dateModify"], "limit": 10 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/pages/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "siteId": 3 }, "select": ["id", "title", "code", "siteId", "active", "dateModify"], "limit": 10 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/pages/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { siteId: 3 }, select: ['id', 'title', 'code', 'siteId', 'active', 'dateModify'], limit: 10, }), }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} страниц за ${meta.durationMs} мс`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/pages/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { siteId: 3 }, select: ['id', 'title', 'code', 'siteId', 'active', 'dateModify'], limit: 10, }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив найденных страниц | | `data[].id` | number | Идентификатор страницы | | `data[].title` | string | Название страницы | | `data[].code` | string | Символьный код страницы | | `data[].siteId` | number | Идентификатор сайта | | `data[].active` | boolean | Активна ли страница | | `data[].description` | string \| null | Произвольное описание | | `data[].createdById` | number | Идентификатор создавшего сотрудника | | `data[].dateCreate` | datetime | Дата создания. Строка в формате локали портала, не ISO 8601 | | `data[].dateModify` | datetime | Дата последнего изменения. Тот же формат | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Время выполнения запроса (мс) | URL любой страницы из массива `data` строится из её `id` и `siteId`: ``` https://.bitrix24.ru/sites/site//view// ``` `` — ID сайта, которому принадлежит страница (поле `siteId` каждого элемента). `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 3, "title": "Смена названия", "code": "promo-page", "siteId": 3, "active": true, "description": null, "createdById": 1, "dateCreate": "22.04.2020 14:39:17", "dateModify": "06.05.2024 15:43:27" }, { "id": 7, "title": "Test page", "code": "test", "siteId": 3, "active": true, "description": null, "createdById": 1, "dateCreate": "25.05.2020 17:34:17", "dateModify": "10.10.2022 15:25:30" } ], "meta": { "total": 13, "hasMore": true, "durationMs": 171 } } ``` ## Пример ответа при ошибке 422 — несуществующее поле в фильтре: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Unknown field definition `nonsense` (nonsense) for \\Bitrix\\Landing\\Internals\\Landing Entity." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Передан неизвестный филд в `filter` или иной параметр, не поддерживаемый Битрикс24 | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `landing` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Когда выбирать `search`, а когда `list`.** Оба эндпоинта возвращают одинаковый набор страниц по фильтру. Используйте `POST /v1/pages/search`, когда фильтр сложнее равенства (например, `id in [3, 7, 9]`) — JSON-тело удобнее экранирует вложенные операторы. Для простых `filter[field]=value` достаточно `GET /v1/pages`. **Формат дат в фильтре — формат локали портала, и чужой формат молча даёт пустой список.** Дату в фильтре передавайте в том же виде, в каком портал отдаёт её в ответе: **не** в ISO 8601, а в формате своей локали — `ДД.ММ.ГГГГ ЧЧ:ММ:СС` (`06.06.2026 00:00:00`) на RU-локали, `MM/DD/YYYY hh:mm:ss` (`06/06/2026 00:00:00`) на EN-локали. Значение в формате другой локали или в ISO Битрикс24 **не распознаёт и возвращает пустой список с кодом 200** — ошибки не будет, поэтому подмену легко не заметить. Единственный надёжный способ узнать формат конкретного портала — прочитать `dateModify` любой страницы (`GET /v1/pages?limit=1`) и передавать дату так же. Один и тот же формат используется в фильтре, в списке и в карточке — см. [Справочник полей](/docs/entities/pages/fields). **`meta.durationMs`.** В отличие от list, search всегда возвращает длительность запроса в миллисекундах — полезно при отладке производительности. **Постраничный переход через `offset` поддерживается.** Вайбкод возвращает запрошенное окно `[offset, offset + limit)`. Значение `meta.total` — точное число записей под фильтром, а `meta.hasMore` показывает, есть ли записи за пределами окна. ## Смотрите также - [Список страниц](/docs/entities/pages/list) - [Получить страницу](/docs/entities/pages/get) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Pages: Update ## Обновить страницу `PATCH /v1/pages/:id` Обновляет поля существующей страницы. Передавайте только изменяемые поля плоско в корне JSON — без обёртки `fields`. Не переданные поля сохраняют текущие значения. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор страницы | ## Поля для обновления (body) | Поле | Тип | Описание | |------|-----|---------| | `title` | string | Название страницы, до 255 символов | | `code` | string | Символьный код страницы. Не должен содержать `/`. Если код уже занят на сайте — добавляется числовой суффикс | | `description` | string | Произвольное описание | | `siteId` | number | ID сайта-владельца. Список: [`GET /v1/sites`](/docs/entities/sites/list) | | `public` | string | Публичность — `Y` / `N` | | `sitemap` | string | Включать в карту сайта — `Y` / `N` | | `xmlId` | string | Внешний код | | `folderId` | number | ID папки-раздела сайта | | `tplId` | number | ID шаблона | **Поле `active` в теле не принимается.** Запрос с ним отклоняется целиком — ответ `400 READONLY_FIELD`, и остальные поля тела не применяются. Публикация и снятие с публикации выполняются отдельными вызовами: `POST /v1/pages/:id/publication` и `POST /v1/pages/:id/unpublish`. ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/pages/2295" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Весенняя акция — обновлено", "description": "Скидки до 50%" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/pages/2295" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Весенняя акция — обновлено", "description": "Скидки до 50%" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/pages/2295', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Весенняя акция — обновлено', description: 'Скидки до 50%', }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/pages/2295', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Весенняя акция — обновлено', description: 'Скидки до 50%', }), }) const { success, data } = await res.json() ``` ## Поля ответа Возвращается полный объект обновлённой страницы. | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор страницы | | `title` | string | Название страницы | | `code` | string | Символьный код страницы | | `siteId` | number | Идентификатор сайта | | `active` | boolean | Активна ли страница | | `description` | string \| null | Описание страницы | | `createdById` | number | Идентификатор создавшего сотрудника | | `dateCreate` | datetime | Дата создания. Строка в формате локали портала, не ISO 8601 | | `dateModify` | datetime | Дата последнего изменения (после обновления) | > **Формат дат.** `dateCreate` и `dateModify` — строки в формате локали портала, **не** ISO 8601 (`30.12.2021 12:30:52` на RU-локали, `12/30/2021 12:30:52 pm` на EN-локали). Формат одинаков в списке и в карточке; `new Date()` на таком значении полагаться нельзя. Подробнее: [Справочник полей](/docs/entities/pages/fields). ## Пример ответа ```json { "success": true, "data": { "id": 2295, "title": "Весенняя акция — обновлено", "code": "spring-sale", "siteId": 3, "active": false, "description": "Скидки до 50%", "createdById": 1, "dateCreate": "08.05.2026 11:49:33", "dateModify": "08.05.2026 12:14:08" } } ``` ## Пример ответа при ошибке 422 — слеш в `code`: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Слеш запрещен в адресе лендинга." } } ``` ## Ошибки | HTTP | `error.code` | Маркер в `error.message` | Описание | |------|--------------|--------------------------|---------| | 400 | `READONLY_FIELD` | — | В теле передано поле только для чтения — например `active`. Тело не применяется целиком | | 401 | `TOKEN_MISSING` | — | API-ключ не имеет настроенных токенов | | 403 | `BITRIX_ACCESS_DENIED` | — | У пользователя нет права на изменение этой страницы | | 403 | `SCOPE_DENIED` | — | API-ключ не имеет скоупа `landing` | | 404 | `ENTITY_NOT_FOUND` | — | Страница с таким `id` не найдена или удалена | | 422 | `BITRIX_ERROR` | `Слеш запрещен в адресе лендинга` | В `code` передан символ `/` | | 422 | `BITRIX_ERROR` | `Адрес страницы не может быть пустым` | В `code` передана пустая строка | | 422 | `BITRIX_ERROR` | `Недопустимый адрес страницы` | В `code` передано значение в формате `__` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить страницу](/docs/entities/pages/get) - [Список страниц](/docs/entities/pages/list) - [Создать страницу](/docs/entities/pages/create) - [Удалить страницу](/docs/entities/pages/delete) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Payments: Aggregate ## Агрегация оплат `POST /v1/payments/aggregate` Подсчёт количества оплат и числовые агрегации (`sum`, `avg`, `min`, `max`) по полю `sum`. Поддерживает фильтрацию и группировку по `paySystemId`, `orderId`, `currency`, `paid`, `responsibleId`. ## Стандартные поля | Поле | Назначение | |------|------------| | `sum` | Единственное числовое поле — подходит для `sum` / `avg` / `min` / `max` (название поля и функции совпадают, но это разные сущности) | | `paySystemId`, `orderId`, `responsibleId` | Идентификаторы — используются в `groupBy` (по платёжной системе, заказу, ответственному) | | `currency` | Категориальное — используется в `groupBy` (по валюте) | | `paid` | Логическое — используется в `groupBy` (оплачено / не оплачено) | Полный список агрегируемых полей перечислен в таблице выше. ## Поля запроса (тело) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций: `[{ "field": "sum", "function": "sum" }]`. Функции: `count`, `sum`, `avg`, `min`, `max`. Для `count` поле — `"*"`. Без параметра — только `count` (один запрос в Битрикс24, записи не выгружаются) | | `filter` | object | нет | Фильтрация — те же поля, что в [`GET /v1/payments`](./list.md). [Синтаксис фильтрации](/docs/filtering) | | `groupBy` | string \| string[] | нет | Поле или массив полей для группировки (максимум 5) | | `groupOrderBy` | array | нет | Сортировка групп: `[{ "field": "sum:sum", "direction": "desc" }]` | | `groupLimit` | number | нет | Ограничение количества возвращаемых групп (1-1000) | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/payments/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [{ "field": "sum", "function": "sum" }], "groupBy": "paySystemId" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/payments/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [{ "field": "sum", "function": "sum" }], "groupBy": "paySystemId" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/payments/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [{ field: 'sum', function: 'sum' }], groupBy: 'paySystemId', }), }) const { success, data } = await res.json() console.log(data.groups) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/payments/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [{ field: 'sum', function: 'sum' }], groupBy: 'paySystemId', }), }) const { success, data } = await res.json() ``` ## Другие сценарии Подсчёт записей — `count` с полем `"*"`, самый быстрый запрос без выгрузки записей. Без массива `aggregate` результат тот же: ```json { "aggregate": [{ "field": "*", "function": "count" }] } ``` Сумма всех принятых оплат: ```json { "aggregate": [{ "field": "sum", "function": "sum" }], "filter": { "paid": true } } ``` Топ-3 платёжных систем по сумме с сортировкой: ```json { "aggregate": [{ "field": "sum", "function": "sum" }], "groupBy": "paySystemId", "groupOrderBy": [{ "field": "sum:sum", "direction": "desc" }], "groupLimit": 3 } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Общее количество оплат, соответствующих фильтру | | `data.aggregates` | object | Результаты агрегаций: `{ "sum": { "sum": ..., "avg": ... } }` | | `data.groups` | array | Группы (только при `groupBy`) | | `data.meta.totalRecords` | number | Общее количество записей | | `data.meta.recordsProcessed` | number | Количество обработанных записей (до 5000) | | `data.meta.truncated` | boolean | `true`, если записей больше 5000 | | `data.meta.groupTotal` | number | Количество групп до `groupLimit` | | `data.meta.groupsTruncated` | boolean | Был ли список групп обрезан `groupLimit` | ## Пример ответа ```json { "success": true, "data": { "count": 99, "aggregates": { "sum": { "sum": 8475.87 } }, "groups": [ { "paySystemId": 11, "count": 87, "aggregates": { "sum": { "sum": 5870.5 } } }, { "paySystemId": 6, "count": 8, "aggregates": { "sum": { "sum": 2025.37 } } }, { "paySystemId": 25, "count": 4, "aggregates": { "sum": { "sum": 580 } } } ], "meta": { "totalRecords": 99, "recordsProcessed": 99, "truncated": false, "groupTotal": 3, "groupsTruncated": false } } } ``` Без `groupBy` поле `data.groups` в ответе отсутствует. ## Пример ответа при ошибке 400 — поле в `groupBy` вне списка агрегируемых: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "groupBy field 'foo' is not aggregatable on this entity. Available: sum, currency, paid, paySystemId, orderId, responsibleId." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Неизвестная функция агрегации | | 400 | `INVALID_PARAMS` | Несуществующее числовое поле в `aggregate[].field` — сообщение `Field 'foo' not found. Available numeric fields: …` | | 400 | `INVALID_PARAMS` | Поле в `groupBy` вне списка агрегируемых — сообщение `groupBy field 'foo' is not aggregatable on this entity. Available: …` | | 400 | `INVALID_PARAMS` | Передано больше 5 полей в `groupBy` | | 400 | `INVALID_PARAMS` | Зарезервированные ключевые слова в `groupBy`: `count`, `aggregates`, `meta`, `groups` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`count` против числовых функций.** `count` считается одним запросом в Битрикс24 — записи не выгружаются, ответ возвращается быстро на любом объёме. `sum` / `avg` / `min` / `max` подгружают записи постранично (максимум 5000) и считают на стороне Вайбкод. При более чем 5000 записях `meta.truncated` будет `true`. **Группировка по `currency` важна на мультивалютных порталах.** Сумма всех оплат в `data.aggregates.sum.sum` без `groupBy: "currency"` смешивает разные валюты — реальный смысл получается только при разделении. ## Смотрите также - [Поля оплаты](./fields.md) - [Список оплат](./list.md) - [Поиск оплат](./search.md) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Payments: Create ## Создать оплату `POST /v1/payments` Регистрирует новую оплату для существующего заказа. Тело запроса плоское — без обёртки `fields`. ## Поля запроса (тело) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `orderId` | number | да | Идентификатор заказа. Источник: [`GET /v1/orders`](../orders/list.md) | | `paySystemId` | number | да | Идентификатор платёжной системы. На каждом портале свой набор систем. Узнать ID можно из существующих оплат через [`GET /v1/payments`](./list.md) или [`POST /v1/payments/aggregate`](./aggregate.md) с `groupBy: "paySystemId"` | | `sum` | number | нет | Сумма оплаты. Если не передать — Битрикс24 берёт остаток от суммы заказа | | `currency` | string | нет | Валюта оплаты. По умолчанию — валюта заказа. Список: [`GET /v1/currencies`](/docs/entities/currencies) | | `paid` | boolean | нет | Помечена ли оплата как поступившая. По умолчанию `false` | | `datePaid` | datetime | нет | Дата отметки оплаты (в формате ISO 8601) | | `dateBill` | datetime | нет | Дата выставления счёта | | `datePayBefore` | datetime | нет | Срок оплаты. В ответах возвращается только дата — время всегда полночь по времени портала | | `responsibleId` | number | нет | Ответственный сотрудник. Источник: [`GET /v1/users`](/docs/entities/users) | | `comments` | string | нет | Комментарий к оплате | | `xmlId` | string | нет | Внешний идентификатор (например, ID транзакции платёжного шлюза) | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/payments" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "orderId": 19, "paySystemId": 11, "sum": 1500, "currency": "RUB", "paid": true, "comments": "Оплата через платёжный шлюз", "xmlId": "txn_abc123" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/payments" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "orderId": 19, "paySystemId": 11, "sum": 1500, "currency": "RUB", "paid": true, "comments": "Оплата через платёжный шлюз", "xmlId": "txn_abc123" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/payments', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ orderId: 19, paySystemId: 11, sum: 1500, currency: 'RUB', paid: true, comments: 'Оплата через платёжный шлюз', xmlId: 'txn_abc123', }), }) const { success, data } = await res.json() console.log('Payment ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/payments', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ orderId: 19, paySystemId: 11, sum: 1500, currency: 'RUB', paid: true, comments: 'Оплата через платёжный шлюз', xmlId: 'txn_abc123', }), }) const { success, data } = await res.json() ``` ## Поля ответа Возвращается полный объект созданной оплаты. | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор созданной оплаты | | `accountNumber` | string | Порядковый номер оплаты на портале (генерируется автоматически) | | `paySystemName` | string | Название платёжной системы (заполняется из карточки платёжной системы) | Остальные поля совпадают с переданными в запросе + `datePaid` / `dateBill` могут быть проставлены автоматически. ## Пример ответа ```json { "success": true, "data": { "id": 217, "accountNumber": "98/2", "orderId": 19, "paySystemId": 11, "paySystemName": "Наличные", "sum": 1500, "currency": "RUB", "paid": true, "datePaid": "2026-05-13T11:50:24.000Z", "dateBill": "2026-05-13T11:50:24.000Z", "responsibleId": 1, "comments": "Оплата через платёжный шлюз", "xmlId": "txn_abc123", "isReturn": "N", "marked": false } } ``` ## Пример ответа при ошибке 422 — не переданы обязательные поля: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Required fields: orderId, paySystemId" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Не переданы обязательные поля — сообщение содержит их список (`Required fields: orderId, paySystemId`) | | 422 | `BITRIX_ERROR` | Несуществующий `orderId` или `paySystemId` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Номер оплаты генерируется автоматически.** Поле `accountNumber` присваивается Битрикс24 при создании в формате `/` (например, `19/1`) и не может быть передано в запросе. **Несколько оплат на один заказ.** У одного заказа может быть несколько оплат — например, частичная предоплата и доплата при доставке. Каждая регистрируется отдельным `POST /v1/payments` с тем же `orderId` и разными `paySystemId` или `sum`. **Статус заказа не обновляется автоматически.** После регистрации оплаты статус заказа (`orders.payed`, `orders.statusId`) остаётся прежним — обновите его отдельным вызовом [`PATCH /v1/orders/:id`](../orders/update.md). ## Смотрите также - [Поля оплаты](./fields.md) - [Список оплат](./list.md) - [Получить оплату](./get.md) - [Обновить оплату](./update.md) - [Обновить заказ](../orders/update.md) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Payments: Delete ## Удалить оплату `DELETE /v1/payments/:id` Удаляет оплату по идентификатору. Восстановить удалённую оплату через API нельзя — создавайте новую при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор оплаты | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/payments/217" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/payments/217" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/payments/217', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Оплата удалена') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/payments/217', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Оплата удалена') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — успех проверяется по статусу. ## Пример ответа ```http HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 422 — оплата не найдена: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "payment is not exists" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Оплата с таким ID не найдена или уже удалена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Заказ не удаляется.** Удаление оплаты не затрагивает родительский заказ — заказ остаётся, поле `sumPaid` пересчитывается автоматически. **Альтернатива — пометка возврата.** Чтобы сохранить запись о платеже, используйте [`PATCH /v1/payments/:id`](./update.md) с `{"isReturn": "Y", "comments": "..."}` — оплата останется в выборках с `filter[isReturn]=Y`. ## Смотрите также - [Поля оплаты](./fields.md) - [Обновить оплату](./update.md) - [Список оплат](./list.md) - [Получить оплату](./get.md) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Payments: Fields ## Поля оплаты `GET /v1/payments/fields` Возвращает схему полей оплаты: типы, флаги только-для-чтения, список агрегируемых полей. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/payments/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/payments/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/payments/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { data } = await res.json() console.log('Поля оплаты:', Object.keys(data.fields)) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/payments/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор оплаты (только чтение) | | `orderId` | number | Идентификатор заказа. Источник: [`GET /v1/orders`](../orders/list.md) | | `paySystemId` | number | Идентификатор платёжной системы. Узнать ID можно из существующих оплат: [`GET /v1/payments`](./list.md) или [`POST /v1/payments/aggregate`](./aggregate.md) с `groupBy: "paySystemId"` | | `paySystemName` | string | Название платёжной системы (только чтение, заполняется из карточки платёжной системы) | | `paySystemIsCash` | boolean | Принимает ли платёжная система наличные (только чтение) | | `paySystemXmlId` | string | Внешний идентификатор платёжной системы для синхронизации (только чтение) | | `sum` | number | Сумма оплаты | | `currency` | string | Валюта оплаты. Список: [`GET /v1/currencies`](/docs/entities/currencies) | | `paid` | boolean | Помечена ли оплата как поступившая | | `datePaid` | datetime \| null | Дата отметки оплаты. `null`, если оплата не отмечена | | `empPaidId` | number \| null | Сотрудник, отметивший оплату (только чтение). Источник: [`GET /v1/users`](/docs/entities/users) | | `comments` | string \| null | Комментарий к оплате. `null`, если не задан | | `accountNumber` | string | Порядковый номер оплаты на портале (только чтение) | | `dateBill` | datetime | Дата выставления счёта | | `datePayBefore` | datetime \| null | Срок оплаты — только дата. Время в ответе всегда полночь по времени портала, отдельного значения не имеет. Битрикс24 помечает поле устаревшим: оно ещё хранится и отдаётся, но новой интеграции опираться на него не стоит. `null`, если не задан | | `xmlId` | string | Внешний идентификатор для синхронизации | | `responsibleId` | number \| null | Ответственный сотрудник. Источник: [`GET /v1/users`](/docs/entities/users). `null`, если не назначен | | `empResponsibleId` | number \| null | Сотрудник, ответственный за оплату (только чтение). Источник: [`GET /v1/users`](/docs/entities/users) | | `dateResponsibleId` | datetime \| null | Дата назначения ответственного сотрудника (только чтение). `null`, если ответственный не назначен | | `isReturn` | string | Признак возврата: `"N"` обычная оплата, `"Y"` возврат, `"P"` частичный возврат | | `marked` | boolean | Помечена ли оплата как проблемная | | `reasonMarked` | string \| null | Причина пометки. `null`, если пометки нет | | `empMarkedId` | number \| null | Сотрудник, поставивший пометку (только чтение). Источник: [`GET /v1/users`](/docs/entities/users) | | `dateMarked` | datetime \| null | Дата пометки оплаты как проблемной (только чтение). `null`, если пометки нет | | `psStatus` | string \| null | Флаг статуса платёжной системы: `"Y"` — подтвердила оплату, `"N"` — не подтвердила. Не текст статуса. `null`, если оплата не проводилась через платёжную систему | | `psStatusCode` | string \| null | Код статуса от платёжной системы | | `psStatusDescription` | string \| null | Описание статуса от платёжной системы | | `psStatusMessage` | string \| null | Сообщение от платёжной системы | | `psSum` | number \| null | Сумма оплаты по данным платёжного шлюза | | `psCurrency` | string \| null | Валюта оплаты по данным платёжного шлюза | | `psResponseDate` | datetime \| null | Дата ответа платёжного шлюза | | `psInvoiceId` | string \| null | Идентификатор счёта на стороне платёжного шлюза | | `payVoucherNum` | string \| null | Номер платёжного поручения. `null`, если поручения нет | | `payVoucherDate` | datetime \| null | Дата платёжного поручения. `null`, если поручения нет | | `payReturnNum` | string \| null | Номер документа возврата. `null`, если возврата не было | | `payReturnDate` | datetime \| null | Дата возврата. `null`, если возврата не было | | `payReturnComment` | string \| null | Комментарий к возврату. `null`, если возврата не было | | `empReturnId` | number \| null | Сотрудник, оформивший возврат (только чтение). Источник: [`GET /v1/users`](/docs/entities/users) | | `priceCod` | number | Сумма наложенного платежа. `0`, если наложенный платёж не задан | | `companyId` | number \| null | Компания-плательщик из CRM. Источник: [`GET /v1/companies`](/docs/entities/companies). Битрикс24 принимает поле при создании и обновлении, но не использует его, поэтому значение не влияет на оплату. `null`, если не задана | | `externalPayment` | boolean | Оплата создана во внешней системе | | `id1c` | string \| null | Идентификатор оплаты в 1С. `null`, если оплата не синхронизирована с 1С | | `version1c` | string \| null | Версия оплаты в 1С. `null`, если оплата не синхронизирована с 1С | | `updated1c` | boolean | Обновлена ли оплата через 1С | Массив `aggregatable` перечисляет поля, доступные для числовых функций и `groupBy` в [`POST /v1/payments/aggregate`](./aggregate.md): `sum`, `currency`, `paid`, `paySystemId`, `orderId`, `responsibleId`. Массив `batch` — операции для [`POST /v1/batch`](/docs/batch): `create`, `update`, `delete`. ## Пример ответа Каждое поле, помимо `type` и `readonly`, содержит `label` (короткое название) и `description` (пояснение) на русском языке. В примере ниже они опущены для краткости. ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true }, "orderId": { "type": "number", "readonly": false }, "paySystemId": { "type": "number", "readonly": false }, "paySystemName": { "type": "string", "readonly": true }, "paySystemIsCash": { "type": "boolean", "readonly": true }, "paySystemXmlId": { "type": "string", "readonly": true }, "sum": { "type": "number", "readonly": false }, "currency": { "type": "string", "readonly": false }, "paid": { "type": "boolean", "readonly": false }, "datePaid": { "type": "datetime", "readonly": false }, "empPaidId": { "type": "number", "readonly": true }, "comments": { "type": "string", "readonly": false }, "accountNumber": { "type": "string", "readonly": true }, "dateBill": { "type": "datetime", "readonly": false }, "datePayBefore": { "type": "datetime", "readonly": false }, "xmlId": { "type": "string", "readonly": false }, "responsibleId": { "type": "number", "readonly": false }, "empResponsibleId": { "type": "number", "readonly": true }, "dateResponsibleId": { "type": "datetime", "readonly": true }, "isReturn": { "type": "string", "readonly": false }, "marked": { "type": "boolean", "readonly": false }, "reasonMarked": { "type": "string", "readonly": false }, "empMarkedId": { "type": "number", "readonly": true }, "dateMarked": { "type": "datetime", "readonly": true }, "psStatus": { "type": "string", "readonly": false }, "psStatusCode": { "type": "string", "readonly": false }, "psStatusDescription": { "type": "string", "readonly": false }, "psStatusMessage": { "type": "string", "readonly": false }, "psSum": { "type": "number", "readonly": false }, "psCurrency": { "type": "string", "readonly": false }, "psResponseDate": { "type": "datetime", "readonly": false }, "psInvoiceId": { "type": "string", "readonly": false }, "payVoucherNum": { "type": "string", "readonly": false }, "payVoucherDate": { "type": "datetime", "readonly": false }, "payReturnNum": { "type": "string", "readonly": false }, "payReturnDate": { "type": "datetime", "readonly": false }, "payReturnComment": { "type": "string", "readonly": false }, "empReturnId": { "type": "number", "readonly": true }, "priceCod": { "type": "number", "readonly": false }, "companyId": { "type": "number", "readonly": false }, "externalPayment": { "type": "boolean", "readonly": false }, "id1c": { "type": "string", "readonly": false }, "version1c": { "type": "string", "readonly": false }, "updated1c": { "type": "boolean", "readonly": false } }, "aggregatable": ["sum", "currency", "paid", "paySystemId", "orderId", "responsibleId"], "batch": ["create", "update", "delete"] } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'sale' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать оплату](./create.md) - [Обновить оплату](./update.md) - [Список оплат](./list.md) - [Агрегация оплат](./aggregate.md) - [Заказы](../orders.md) - [Entity API](/docs/entity-api) --- # Payments: Get ## Получить оплату `GET /v1/payments/:id` Возвращает одну оплату по идентификатору со всеми полями. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор оплаты | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/payments/17" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/payments/17" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/payments/17', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Оплата:', data.sum, data.currency, '—', data.paySystemName) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/payments/17', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор оплаты | | `accountNumber` | string | Порядковый номер оплаты на портале | | `orderId` | number | Идентификатор заказа | | `paySystemId` | number | Идентификатор платёжной системы | | `paySystemName` | string | Название платёжной системы | | `paySystemIsCash` | boolean | Принимает ли платёжная система наличные (только чтение) | | `paySystemXmlId` | string | Внешний идентификатор платёжной системы (только чтение) | | `sum` | number | Сумма оплаты | | `currency` | string | Валюта оплаты | | `paid` | boolean | Помечена ли оплата как поступившая | | `datePaid` | datetime \| null | Дата отметки оплаты. `null`, если оплата не отмечена | | `dateBill` | datetime | Дата выставления счёта | | `datePayBefore` | datetime \| null | Срок оплаты — только дата. Время в ответе всегда полночь по времени портала, отдельного значения не имеет. `null`, если не задан | | `dateMarked` | datetime \| null | Дата пометки оплаты как проблемной (только чтение). `null`, если пометки нет | | `dateResponsibleId` | datetime \| null | Дата назначения ответственного (только чтение). `null`, если ответственный не назначен | | `responsibleId` | number \| null | Ответственный сотрудник. `null`, если не назначен | | `comments` | string \| null | Комментарий к оплате. `null`, если не задан | | `xmlId` | string | Внешний идентификатор | | `isReturn` | string | Признак возврата: `"N"` обычная оплата, `"Y"` возврат, `"P"` частичный возврат | | `marked` | boolean | Помечена ли оплата как проблемная | | `reasonMarked` | string \| null | Причина пометки. `null`, если пометки нет | | `empPaidId` | number \| null | Сотрудник, отметивший оплату (только чтение) | | `empResponsibleId` | number \| null | Сотрудник, ответственный за оплату (только чтение) | | `empMarkedId` | number \| null | Сотрудник, поставивший пометку (только чтение) | | `empReturnId` | number \| null | Сотрудник, оформивший возврат (только чтение) | | `psStatus` | string \| null | Статус оплаты по данным платёжной системы. `null`, если оплата не проводилась через платёжную систему | | `psStatusCode` | string \| null | Код статуса от платёжной системы | | `psStatusDescription` | string \| null | Описание статуса от платёжной системы | | `psStatusMessage` | string \| null | Сообщение от платёжной системы | | `psSum` | number \| null | Сумма оплаты по данным платёжного шлюза | | `psCurrency` | string \| null | Валюта оплаты по данным платёжного шлюза | | `psResponseDate` | datetime \| null | Дата ответа платёжного шлюза | | `psInvoiceId` | string \| null | Идентификатор счёта на стороне платёжного шлюза | | `payVoucherNum` | string \| null | Номер платёжного поручения. `null`, если поручения нет | | `payVoucherDate` | datetime \| null | Дата платёжного поручения. `null`, если поручения нет | | `payReturnNum` | string \| null | Номер документа возврата. `null`, если возврата не было | | `payReturnDate` | datetime \| null | Дата возврата. `null`, если возврата не было | | `payReturnComment` | string \| null | Комментарий к возврату. `null`, если возврата не было | | `priceCod` | number | Сумма наложенного платежа. `0`, если наложенный платёж не задан | | `companyId` | number \| null | Компания-плательщик из CRM. `null`, если не задана | | `externalPayment` | boolean | Оплата создана во внешней системе | | `id1c` | string \| null | Идентификатор оплаты в 1С. `null`, если оплата не синхронизирована с 1С | | `version1c` | string \| null | Версия оплаты в 1С. `null`, если оплата не синхронизирована с 1С | | `updated1c` | boolean | Обновлена ли оплата через 1С | Полный список полей со ссылками на источники идентификаторов — [Поля оплаты](./fields.md). ## Пример ответа ```json { "success": true, "data": { "id": 17, "accountNumber": "19/1", "orderId": 19, "paySystemId": 11, "paySystemName": "Наличные", "paySystemIsCash": true, "paySystemXmlId": "bx_61372545d32ae", "sum": 0, "currency": "RUB", "paid": false, "datePaid": "2020-05-14T20:00:00.000Z", "dateBill": "2020-05-14T20:00:00.000Z", "datePayBefore": null, "dateMarked": null, "dateResponsibleId": "2020-05-15T12:08:16.000Z", "responsibleId": 1, "empPaidId": null, "empResponsibleId": 1, "empMarkedId": null, "empReturnId": null, "comments": null, "reasonMarked": null, "xmlId": "bx_5ebe943aacfa0", "id1c": null, "version1c": null, "updated1c": false, "externalPayment": false, "isReturn": "N", "marked": false, "priceCod": 0, "companyId": null, "payReturnNum": null, "payReturnDate": null, "payReturnComment": null, "payVoucherNum": null, "payVoucherDate": null, "psStatus": null, "psStatusCode": null, "psStatusDescription": null, "psStatusMessage": null, "psSum": null, "psCurrency": null, "psInvoiceId": null, "psResponseDate": null } } ``` ## Пример ответа при ошибке 422 — оплата не найдена: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "payment is not exists" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Оплата с таким ID не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Поля оплаты](./fields.md) - [Обновить оплату](./update.md) - [Удалить оплату](./delete.md) - [Список оплат](./list.md) - [Заказ](../orders/get.md) - [Лимиты и оптимизация](/docs/optimization) --- # Payments: List ## Список оплат `GET /v1/payments` Возвращает список оплат заказов с поддержкой фильтрации и автоматической пагинации. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` Вайбкод автоматически запрашивает несколько страниц у Битрикс24 | | `offset` | number | `0` | Пропустить N записей. При `offset ≥ 2500` рекомендуется `limit ≤ 500` | | `select` | string | — | Выборка полей: `?select=id,orderId,sum,paid` | | `order` | object | — | Сортировка: `?order[id]=desc` | | `filter` | object | — | Фильтрация по ключевым полям оплаты.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[orderId]=19` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/payments?limit=10&filter[paid]=true&order[id]=desc" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/payments?limit=10&filter[paid]=true&order[id]=desc" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/payments?limit=10&filter[paid]=true&order[id]=desc', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} оплат`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/payments?limit=10&filter[paid]=true&order[id]=desc', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив оплат (каждая содержит все поля оплаты) | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | ## Пример ответа ```json { "success": true, "data": [ { "id": 17, "accountNumber": "19/1", "orderId": 19, "paySystemId": 11, "paySystemName": "Наличные", "sum": 0, "currency": "RUB", "paid": false, "datePaid": "2020-05-14T20:00:00.000Z", "dateBill": "2020-05-14T20:00:00.000Z", "responsibleId": 1, "isReturn": "N", "comments": "", "xmlId": "bx_5ebe943aacfa0" }, { "id": 19, "accountNumber": "21/1", "orderId": 21, "paySystemId": 11, "paySystemName": "Наличные", "sum": 0, "currency": "RUB", "paid": false, "datePaid": "2020-05-17T20:00:00.000Z", "dateBill": "2020-05-17T20:00:00.000Z", "responsibleId": 1, "isReturn": "N", "comments": "", "xmlId": "bx_5ec2368b6e74d" } ], "meta": { "total": 99, "hasMore": true } } ``` Показаны основные поля. Полный ответ оплаты — см. [`GET /v1/payments/:id`](./get.md). ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'sale' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет в схеме оплаты | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Автоматическая пагинация:** при `limit > 50` Вайбкод автоматически запрашивает несколько страниц у Битрикс24 и возвращает все записи в одном ответе. **Когда использовать `search` вместо `list`:** [`POST /v1/payments/search`](./search.md) передаёт параметры в теле запроса, а не в строке запроса — подходит для сложных фильтров с множеством условий. **Поле `isReturn` — строка с тремя значениями.** Принимает `"N"` (обычная оплата), `"Y"` (возврат) и `"P"` (частичный возврат) — фильтр по нему работает по этим строковым значениям. ## Смотрите также - [Поля оплаты](./fields.md) - [Поиск оплат](./search.md) - [Получить оплату](./get.md) - [Создать оплату](./create.md) - [Заказ](../orders/get.md) - [Синтаксис фильтрации](/docs/filtering) - [Entity API](/docs/entity-api) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Payments: Search ## Поиск оплат `POST /v1/payments/search` Поиск оплат с фильтрацией и автоматической пагинацией. Аналогичен [`GET /v1/payments`](./list.md), но параметры передаются в теле POST-запроса — подходит для сложных запросов с большим количеством условий. ## Поля запроса (тело) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям оплаты.
[Синтаксис фильтрации](/docs/filtering) | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки» | | `select` | string[] | — | Выборка полей: `["id", "orderId", "sum", "paid"]` | | `order` | object | — | Сортировка: `{ "id": "desc" }` | | `autoWindow` | boolean | `true` | Разбивать выборку по недельным окнам при фильтре по диапазону дат шире 14 дней. `false` отключает разбиение | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/payments/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "orderId": 19, "paid": true }, "limit": 10, "select": ["id", "orderId", "sum", "currency", "paid", "datePaid"] }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/payments/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "orderId": 19, "paid": true }, "limit": 10, "select": ["id", "orderId", "sum", "currency", "paid", "datePaid"] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/payments/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { orderId: 19, paid: true }, limit: 10, select: ['id', 'orderId', 'sum', 'currency', 'paid', 'datePaid'], }), }) const { success, data, meta } = await res.json() console.log('Найдено:', meta.total) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/payments/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { orderId: 19, paid: true }, limit: 10, select: ['id', 'orderId', 'sum', 'currency', 'paid', 'datePaid'], }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив оплат | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временны́м окнам | | `meta.windowCount` | number | Число окон. Приходит при `autoWindowed: true` | | `meta.batchWaves` | number | Число волн параллельных запросов. Приходит при `autoWindowed: true` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа ```json { "success": true, "data": [ { "id": 17, "orderId": 19, "sum": 0, "currency": "RUB", "paid": false, "datePaid": "2020-05-14T20:00:00.000Z" } ], "meta": { "total": 1, "hasMore": false, "durationMs": 132 } } ``` С фильтром по диапазону дат шире 14 дней в `meta` дополнительно приходят `autoWindowed`, `windowCount` и `batchWaves`: ```json { "success": true, "data": [ /* ... */ ], "meta": { "total": 99, "hasMore": true, "autoWindowed": true, "windowCount": 339, "batchWaves": 7, "durationMs": 2618 } } ``` ## Пример ответа при ошибке 400 — фильтр по несуществующему полю: ```json { "success": false, "error": { "code": "UNKNOWN_FILTER_FIELD", "message": "Unknown filter field 'foo' for entity 'payments'. Available: id, orderId, paySystemId, sum, currency, paid, ..." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет в схеме оплаты | | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Разбиение по временны́м окнам.** Фильтр по диапазону дат шире 14 дней автоматически разбивается на недельные окна, которые выполняются параллельными волнами — так выборка обходит потолок в 5000 записей на один вызов. В `meta` тогда приходят `autoWindowed: true`, число окон `windowCount` и число волн `batchWaves`. Отключает разбиение параметр `autoWindow: false`. При активном разбиении `offset` больше нуля отклоняется с `UNSTABLE_OFFSET_PAGINATION`. **`select` ограничивает поля в ответе.** Если передан `select`, в каждом элементе `data[]` будут только перечисленные поля. Без `select` возвращаются все поля оплаты. **Поле `isReturn` — строка.** Принимает `"N"`, `"Y"` и `"P"` — фильтр и обновление работают по этим значениям. ## Смотрите также - [Поля оплаты](./fields.md) - [Список оплат](./list.md) - [Получить оплату](./get.md) - [Заказ](../orders/get.md) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Payments: Update ## Обновить оплату `PATCH /v1/payments/:id` Обновляет поля существующей оплаты. Передавайте только изменяемые поля плоско в корне JSON — без обёртки `fields`. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор оплаты | ## Поля для обновления (тело) | Параметр | Тип | Описание | |----------|-----|---------| | `orderId` | number | Заказ, к которому привязана оплата. Источник: [`GET /v1/orders`](../orders/list.md) | | `sum` | number | Новая сумма оплаты | | `currency` | string | Валюта оплаты | | `paid` | boolean | Помечена ли оплата как поступившая | | `datePaid` | datetime | Дата отметки оплаты | | `dateBill` | datetime | Дата выставления счёта | | `comments` | string | Комментарий к оплате | | `xmlId` | string | Внешний идентификатор | | `responsibleId` | number | Ответственный сотрудник | | `marked` | boolean | Помечена ли оплата как проблемная | | `reasonMarked` | string | Причина пометки | | `isReturn` | string | Признак возврата: `"N"`, `"Y"`, `"P"` | Редактируются все поля оплаты, кроме служебных (`id`, `accountNumber`, `paySystemName`, `empPaidId`, `empResponsibleId`, `empMarkedId`, `empReturnId`). Полный набор доступных полей виден в ответе [`GET /v1/payments/:id`](./get.md). ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/payments/17" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "paid": true, "datePaid": "2026-05-13T12:00:00", "comments": "Подтверждено банком" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/payments/17" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "paid": true, "datePaid": "2026-05-13T12:00:00", "comments": "Подтверждено банком" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/payments/17', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ paid: true, datePaid: '2026-05-13T12:00:00', comments: 'Подтверждено банком', }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/payments/17', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ paid: true, datePaid: '2026-05-13T12:00:00', comments: 'Подтверждено банком', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | object | Обновлённый объект оплаты со всеми полями | ## Пример ответа ```json { "success": true, "data": { "id": 17, "accountNumber": "19/1", "orderId": 19, "paySystemId": 11, "paySystemName": "Наличные", "sum": 0, "currency": "RUB", "paid": true, "datePaid": "2026-05-13T09:00:00.000Z", "dateBill": "2020-05-14T20:00:00.000Z", "responsibleId": 1, "comments": "Подтверждено банком", "xmlId": "bx_5ebe943aacfa0", "isReturn": "N", "marked": false } } ``` ## Пример ответа при ошибке 422 — оплата не найдена: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "payment is not exists" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Оплата с таким ID не найдена | | 400 | `BITRIX_ERROR` | Некорректное значение поля — например, неизвестный `paySystemId` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Поле `paySystemId` подтягивается автоматически.** Вайбкод перед обновлением оплаты получает текущее значение `paySystemId` через `GET /v1/payments/:id` и автоматически добавляет его в запрос, если оно не передано. Это даёт семантику `PATCH` с одним полем — без необходимости каждый раз указывать платёжную систему. **Поля `accountNumber` и `paySystemName` доступны только для чтения.** `accountNumber` присваивается при создании оплаты, `paySystemName` заполняется из карточки платёжной системы по `paySystemId`. Эти значения проставляет Битрикс24, при обновлении они игнорируются. ## Смотрите также - [Поля оплаты](./fields.md) - [Получить оплату](./get.md) - [Список оплат](./list.md) - [Удалить оплату](./delete.md) - [Обновить заказ](../orders/update.md) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Product Sections: Create ## Создать раздел `POST /v1/product-sections` Создаёт новый раздел в каталоге товаров. Поля передаются плоско в корне JSON, без обёртки `fields`. ## Поля запроса (body) | Поле | Битрикс24 | Тип | Обяз. | Описание | |------|----------|-----|:-----:|---------| | `name` | `NAME` | string | да | Название раздела | | `catalogId` | `CATALOG_ID` | number | нет | Идентификатор каталога. Если не передавать — используется каталог товаров CRM портала. Список: `GET /v1/catalogs` | | `sectionId` | `SECTION_ID` | number | нет | Идентификатор родительского раздела для вложенности. У раздела верхнего уровня — `null` | | `code` | `CODE` | string | нет | Символьный код раздела. Если не передавать — формируется из `name` | | `xmlId` | `XML_ID` | string | нет | Внешний идентификатор | | `sort` | `SORT` | number | RO | Порядок сортировки. Битрикс24 переданное значение не сохраняет, поэтому поле отклоняется с `400 READONLY_FIELD` — менять порядок можно в интерфейсе Битрикс24 | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/product-sections" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Одежда", "catalogId": 25 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/product-sections" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Одежда", "catalogId": 25 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/product-sections', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Одежда', catalogId: 25, }), }) const { success, data } = await res.json() console.log('ID раздела:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/product-sections', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Одежда', catalogId: 25, }), }) const { success, data } = await res.json() ``` ## Поля ответа Возвращается полный объект созданного раздела. | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор созданного раздела | | `name` | string | Название раздела | | `catalogId` | number | Идентификатор каталога | | `sectionId` | number | Идентификатор родительского раздела или `null` | | `xmlId` | string | Внешний идентификатор или `null` | | `code` | string | Символьный код раздела | ## Пример ответа ```json { "success": true, "data": { "id": 197, "name": "Одежда", "catalogId": 25, "sectionId": null, "xmlId": null, "code": "odezhda" } } ``` ## Пример ответа при ошибке 422 — не передано название раздела: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Не указано название раздела." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 422 | `BITRIX_ERROR` | Не передано поле `name` — сообщение «Не указано название раздела.» | | 400 | `READONLY_FIELD` | В теле передано поле, доступное только для чтения, — `id` или `sort` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `crm` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список разделов](/docs/entities/product-sections/list) - [Обновить раздел](/docs/entities/product-sections/update) - [Удалить раздел](/docs/entities/product-sections/delete) - [Каталоги](/docs/entities/catalogs) - [Batch](/docs/batch) --- # Product Sections: Delete ## Удалить раздел `DELETE /v1/product-sections/:id` Удаляет раздел каталога товаров по идентификатору. Восстановить удалённый раздел через API нельзя — создавайте новый при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор раздела | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/product-sections/197" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/product-sections/197" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/product-sections/197', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Раздел удалён') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/product-sections/197', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Раздел удалён') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом. Признак успеха — код ответа, не содержимое. ## Пример ответа ```http HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — раздел не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Product section is not found." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 404 | `ENTITY_NOT_FOUND` | Раздела с указанным `id` не существует | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `crm` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список разделов](/docs/entities/product-sections/list) - [Получить раздел](/docs/entities/product-sections/get) - [Создать раздел](/docs/entities/product-sections/create) - [Batch](/docs/batch) --- # Product Sections: Fields ## Поля раздела `GET /v1/product-sections/fields` Возвращает справочник полей раздела товаров с типами и признаком «только для чтения», а также список операций, доступных в [пакетном запросе](/docs/batch). ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/product-sections/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/product-sections/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/product-sections/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() console.log('Всего полей:', Object.keys(data.fields).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/product-sections/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа `data.fields` — объект, ключ которого совпадает с именем поля, а значение содержит `type` (тип поля), `readonly` (`true` — поле нельзя передать при создании и обновлении), `label` (человекочитаемое название поля на русском языке) и — у поля, значение которого Битрикс24 не возвращает никогда — `notReturned: true` вместе с описанием `description`. `data.batch` — список операций, которые принимает [пакетный запрос](/docs/batch). | Поле | Битрикс24 | Тип | RO | Описание | |------|----------|-----|:--:|---------| | `id` | `ID` | number | да | Идентификатор раздела | | `name` | `NAME` | string | | Название раздела | | `catalogId` | `CATALOG_ID` | number | | Идентификатор каталога. Список: `GET /v1/catalogs` | | `sectionId` | `SECTION_ID` | number | | Идентификатор родительского раздела для вложенности. У корневого раздела — `null` | | `xmlId` | `XML_ID` | string | | Внешний идентификатор для синхронизации | | `sort` | `SORT` | number | да | Порядок сортировки, меньше — выше. Значение не сохраняется на запись и не приходит на чтение (`notReturned: true`) — годится только для упорядочивания | | `code` | `CODE` | string | | Символьный код раздела | | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.fields.<имя>.type` | string | Тип поля: `number`, `string` | | `data.fields.<имя>.readonly` | boolean | `true` — поле заполняется системой и не принимается при создании и обновлении | | `data.fields.<имя>.label` | string | Человекочитаемое название поля на русском языке | | `data.fields.<имя>.description` | string | Расширенное описание поля, если оно есть | | `data.fields.<имя>.notReturned` | boolean | `true` — значения этого поля Битрикс24 не возвращает ни в одном ответе. Ключ приходит только у таких полей | | `data.batch` | string[] | Операции раздела, доступные в [пакетном запросе](/docs/batch): `create`, `update`, `delete` | Поле `sort` **не принимается на запись и не возвращается на чтение**. Проверено на живом портале: значение, переданное при создании или обновлении, Битрикс24 не сохраняет (на обновление он при этом отвечает «успех»), и ни один ответ — `list`, `get`, `search`, отклик создания — его не содержит, даже если запросить поле явно в `select`. Поэтому попытка передать `sort` в `POST` или `PATCH` теперь отклоняется с `400 READONLY_FIELD` вместо молчаливого «успеха», а в справочнике полей у него стоит `notReturned: true`. **Упорядочивание по нему работает** — `?sort=sort&order=asc` и `order=desc` дают разный порядок; фильтровать по нему нельзя. Менять порядок разделов можно в интерфейсе Битрикс24. Остальные поля — `id`, `name`, `catalogId`, `sectionId`, `xmlId`, `code` — фильтруются точным равенством (и `$in`); операторы дают `400 UNSUPPORTED_FILTER`. Поля `sectionId`, `xmlId` и `code` приходят со значением `null`, если не заданы. Если `code` не передать при создании, он формируется из `name`. ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true }, "name": { "type": "string", "readonly": false }, "catalogId": { "type": "number", "readonly": false }, "sectionId": { "type": "number", "readonly": false }, "xmlId": { "type": "string", "readonly": false }, "sort": { "type": "number", "readonly": true, "notReturned": true, "label": "Порядок сортировки", "description": "Порядок сортировки раздела среди соседних. Битрикс24 не сохраняет значение, переданное при создании или изменении, и не возвращает его при чтении, поэтому на запись поле отклоняется с 400 READONLY_FIELD, а значение не приходит никогда — поле объявлено, чтобы вызывающий мог его найти и прочитать причину. Упорядочивание по нему при этом работает: передайте ?sort=sort&order=asc|desc, и Битрикс24 отсортирует по хранимому столбцу. Изменить порядок можно в интерфейсе Битрикс24." }, "code": { "type": "string", "readonly": false } }, "batch": ["create", "update", "delete"] } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать раздел](/docs/entities/product-sections/create) - [Список разделов](/docs/entities/product-sections/list) - [Разделы товаров](/docs/entities/product-sections) - [Entity API](/docs/entity-api) --- # Product Sections: Get ## Получить раздел `GET /v1/product-sections/:id` Возвращает один раздел каталога товаров по идентификатору. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор раздела | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/product-sections/31" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/product-sections/31" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/product-sections/31', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Раздел:', data.name) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/product-sections/31', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Идентификатор раздела | | `data.name` | string | Название раздела | | `data.catalogId` | number | ID каталога, к которому относится раздел | | `data.sectionId` | number | ID родительского раздела. У раздела верхнего уровня — `null` | | `data.xmlId` | string | Внешний идентификатор | | `data.code` | string | Символьный код раздела | ## Пример ответа ```json { "success": true, "data": { "id": 31, "name": "Одежда", "catalogId": 25, "sectionId": null, "xmlId": "666", "code": "clothes" } } ``` ## Пример ответа при ошибке 404 — раздел не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Product section is not found." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Раздела с таким `id` не существует | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `crm` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список разделов](/docs/entities/product-sections/list) - [Обновить раздел](/docs/entities/product-sections/update) - [Удалить раздел](/docs/entities/product-sections/delete) - [Поля раздела](/docs/entities/product-sections/fields) - [Разделы каталога](/docs/entities/catalog-sections) --- # Product Sections: List ## Список разделов `GET /v1/product-sections` Возвращает разделы каталога товаров с поддержкой фильтрации и авто-пагинации. Это те же разделы, что доступны через [`GET /v1/catalog-sections`](/docs/entities/catalog-sections) — с тем же `id`. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей до 5000. При `limit > 50` Вайбкод автоматически запрашивает несколько страниц у Битрикс24 | | `offset` | number | `0` | Смещение от начала выборки | | `select` | string | — | Выборка полей: `?select=id,name,sectionId` | | `filter` | object | — | Только точное равенство и `$in` (IN-множество) по полям `id`, `name`, `xmlId`, `code`, `catalogId`, `sectionId`. Операторы (`>`, `>=`, `<`, `<=`, `!`, `%`, `$ne`, `$contains`, `$nin`) и фильтрация по `sort` не поддерживаются — вернётся `400 UNSUPPORTED_FILTER`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[catalogId]=25` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/product-sections?filter[catalogId]=25&limit=10" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/product-sections?filter[catalogId]=25&limit=10" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/product-sections?filter[catalogId]=25&limit=10', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} разделов`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/product-sections?filter[catalogId]=25&limit=10', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив разделов | | `data[].id` | number | Идентификатор раздела | | `data[].name` | string | Название раздела | | `data[].catalogId` | number | ID каталога, к которому относится раздел | | `data[].sectionId` | number | ID родительского раздела. У раздела верхнего уровня — `null` | | `data[].code` | string | Символьный код раздела | | `data[].xmlId` | string | Внешний идентификатор | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | Поле `sort` в список не входит и по нему нельзя фильтровать (в сортировке `order`/`sort` — можно). Полный набор полей раздела — [`GET /v1/product-sections/fields`](./fields.md). ## Пример ответа ```json { "success": true, "data": [ { "id": 31, "catalogId": 25, "sectionId": null, "name": "Одежда", "code": "clothes", "xmlId": "666" }, { "id": 45, "catalogId": 25, "sectionId": null, "name": "Зимняя коллекция", "code": "winter", "xmlId": null } ], "meta": { "total": 36, "hasMore": true } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSUPPORTED_FILTER` | Оператор или неподдерживаемое поле в фильтре. Фильтруйте точным равенством или `$in` по `id`, `name`, `xmlId`, `code`, `catalogId`, `sectionId` | | 400 | `INVALID_FILTER` | Ошибка в синтаксисе фильтра | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `crm` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Только точное равенство.** Фильтр применяется точным равенством (и `$in`-множеством) по `id`, `name`, `xmlId`, `code`, `catalogId`, `sectionId`. Операторы (`>`, `<`, `!`, `%`), `$ne`/`$contains`/`$nin` и фильтрация по `sort` дают `400 UNSUPPORTED_FILTER` — так вы сразу видите, что фильтр не применился, а не получаете весь список без фильтра. **Разделы одного родителя.** Чтобы получить вложенные разделы внутри конкретного раздела, фильтруйте точным равенством по `filter[sectionId]` с идентификатором родителя. **Без фильтра возвращаются разделы всех каталогов портала.** Чтобы ограничить выборку одним каталогом, передавайте `filter[catalogId]`. Список каталогов — `GET /v1/catalogs`. ## Смотрите также - [Получить раздел](/docs/entities/product-sections/get) - [Создать раздел](/docs/entities/product-sections/create) - [Поиск разделов](/docs/entities/product-sections/search) - [Поля раздела](/docs/entities/product-sections/fields) - [Разделы каталога](/docs/entities/catalog-sections) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Product Sections: Search ## Поиск разделов `POST /v1/product-sections/search` Поиск разделов товаров с фильтрацией и авто-пагинацией. Аналогичен `GET /v1/product-sections` с фильтрами, но через POST — удобнее для сложных запросов с большим количеством условий. ## Поля запроса (body) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Только точное равенство и `$in` (IN-множество) по полям `id`, `name`, `xmlId`, `code`, `catalogId`, `sectionId`. Операторы (`>`, `<`, `!`, `%`, `$ne`, `$contains`, `$nin`) и фильтрация по `sort` не поддерживаются — вернётся `400 UNSUPPORTED_FILTER`.
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "filter": { "catalogId": 25 } }` | | `limit` | number | `50` | Количество записей (до 5000) | | `select` | string[] | — | Выборка полей: `["id", "name", "catalogId"]` | | `order` | object | — | Сортировка по полю: `{ "sort": "asc" }` | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/product-sections/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "catalogId": 25 }, "limit": 10, "select": ["id", "name", "catalogId", "code"] }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/product-sections/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "catalogId": 25 }, "limit": 10, "select": ["id", "name", "catalogId", "code"] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/product-sections/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { catalogId: 25 }, limit: 10, select: ['id', 'name', 'catalogId', 'code'], }), }) const { success, data, meta } = await res.json() console.log('Найдено:', meta.total) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/product-sections/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { catalogId: 25 }, limit: 10, select: ['id', 'name', 'catalogId', 'code'], }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив разделов | | `data[].id` | number | Идентификатор раздела | | `data[].name` | string | Название раздела | | `data[].catalogId` | number | Идентификатор каталога | | `data[].sectionId` | number | Идентификатор родительского раздела. У корневого раздела — `null` | | `data[].code` | string | Символьный код раздела | | `data[].xmlId` | string | Внешний идентификатор | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа ```json { "success": true, "data": [ { "id": 31, "catalogId": 25, "sectionId": null, "name": "Одежда", "code": "clothes", "xmlId": "666" }, { "id": 45, "catalogId": 25, "sectionId": null, "name": "Раздел для фильтра", "code": "razdel-dlya-filtra", "xmlId": null } ], "meta": { "total": 37, "hasMore": true, "durationMs": 285 } } ``` ## Пример ответа при ошибке 400 — оператор или неподдерживаемое поле в фильтре: ```json { "success": false, "error": { "code": "UNSUPPORTED_FILTER", "message": "UNSUPPORTED_FILTER: operators are not supported on 'product-sections' (near 'name'). Its Bitrix24 method (crm.productsection.list) filters by exact match only — operators are silently ignored by Bitrix24. Use exact match (field: value) or $in (field: {$in: [...]}) on: id, name, xmlId, code, catalogId, sectionId." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSUPPORTED_FILTER` | Оператор или неподдерживаемое поле в фильтре. Фильтруйте точным равенством или `$in` по `id`, `name`, `xmlId`, `code`, `catalogId`, `sectionId` | | 400 | `INVALID_FILTER` | Ошибка при разборе фильтра | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Авто-пагинация.** При `limit > 50` запрос разбивается на несколько обращений к серверу. Максимум — 5000 записей за вызов. Если под фильтр попадает больше, в `meta.hasMore` придёт `true`. **Только точное равенство в фильтре.** Метод фильтрует точным равенством (и `$in`) по `id`, `name`, `xmlId`, `code`, `catalogId`, `sectionId`. Операторы, `$ne`/`$contains`/`$nin` и фильтрация по `sort` дают `400 UNSUPPORTED_FILTER`. Сортировка (`order`) по `sort` и другим полям работает. ## Смотрите также - [Список разделов](/docs/entities/product-sections/list) - [Получить раздел](/docs/entities/product-sections/get) - [Поля раздела](/docs/entities/product-sections/fields) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) --- # Product Sections: Update ## Обновить раздел `PATCH /v1/product-sections/:id` Обновляет существующий раздел каталога товаров. В теле передаются только изменяемые поля. Поля передаются плоско в корне JSON, без обёртки `fields`. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор раздела | ## Поля запроса (body) | Поле | Битрикс24 | Тип | Обяз. | Описание | |------|----------|-----|:-----:|---------| | `name` | `NAME` | string | нет | Название раздела | | `catalogId` | `CATALOG_ID` | number | нет | Идентификатор каталога. Список: `GET /v1/catalogs` | | `sectionId` | `SECTION_ID` | number | нет | Идентификатор родительского раздела для вложенности. У раздела верхнего уровня — `null` | | `code` | `CODE` | string | нет | Символьный код раздела | | `xmlId` | `XML_ID` | string | нет | Внешний идентификатор | | `sort` | `SORT` | number | RO | Порядок сортировки. Битрикс24 переданное значение не сохраняет (и при этом отвечает «успех»), поэтому поле отклоняется с `400 READONLY_FIELD` — менять порядок можно в интерфейсе Битрикс24 | | `id` | `ID` | number | RO | Идентификатор раздела. Заполняется системой | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/product-sections/197" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Верхняя одежда" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/product-sections/197" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Верхняя одежда" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/product-sections/197', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Верхняя одежда', }), }) const { success, data } = await res.json() console.log('Обновлённое название:', data.name) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/product-sections/197', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Верхняя одежда', }), }) const { success, data } = await res.json() ``` ## Поля ответа Возвращается полный объект раздела после обновления. | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор раздела | | `name` | string | Название раздела | | `catalogId` | number | Идентификатор каталога | | `sectionId` | number | Идентификатор родительского раздела или `null` | | `xmlId` | string | Внешний идентификатор или `null` | | `code` | string | Символьный код раздела | ## Пример ответа ```json { "success": true, "data": { "id": 197, "name": "Верхняя одежда", "catalogId": 25, "sectionId": null, "xmlId": null, "code": "odezhda" } } ``` ## Пример ответа при ошибке 404 — раздел не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Product section is not found." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 404 | `ENTITY_NOT_FOUND` | Раздела с указанным `id` не существует | | 400 | `READONLY_FIELD` | В теле передано поле, доступное только для чтения, — `id` или `sort` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `crm` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить раздел](/docs/entities/product-sections/get) - [Создать раздел](/docs/entities/product-sections/create) - [Удалить раздел](/docs/entities/product-sections/delete) - [Каталоги](/docs/entities/catalogs) - [Batch](/docs/batch) --- # Products: Aggregate ## Агрегация товаров `POST /v1/products/aggregate` Подсчёт количества и числовые агрегации — сумма, среднее, минимум, максимум — по товарам каталога с фильтрацией и группировкой через `groupBy`. **Стандартные поля.** Для группировки и подсчёта доступны: - `price` — цена. Числовое агрегирование имеет смысл - `sectionId` — раздел каталога. Для `groupBy` - `catalogId` — идентификатор каталога. Для `groupBy` - `active` — активность. Для `groupBy` **Пользовательские свойства.** Свойства каталога вида `PROPERTY_` в агрегации не участвуют — для числовых функций используйте `price`, для разбиения по группам — `sectionId`, `catalogId` или `active`. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Агрегации: `[{ "field": "price", "function": "sum" }]`. Функции: `sum`, `avg`, `min`, `max`, `count`. Для `count` поле — `"*"`. Без параметра — только `count` | | `filter` | object | нет | Фильтрация по полям товара.
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "active": true }` | | `groupBy` | string \| string[] | нет | Поле или массив полей для группировки (до 5). Значения — `price`, `sectionId`, `catalogId`, `active` | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/products/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "price", "function": "sum" }, { "field": "price", "function": "avg" } ], "groupBy": "sectionId" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/products/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "price", "function": "sum" }, { "field": "price", "function": "avg" } ], "groupBy": "sectionId" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/products/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [ { field: 'price', function: 'sum' }, { field: 'price', function: 'avg' }, ], groupBy: 'sectionId', }), }) const { success, data } = await res.json() console.log(data.groups) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/products/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [ { field: 'price', function: 'sum' }, { field: 'price', function: 'avg' }, ], groupBy: 'sectionId', }), }) const { success, data } = await res.json() ``` Для группировки по нескольким полям передайте массив: `"groupBy": ["sectionId", "active"]` (максимум 5 полей). ## Другие сценарии Подсчёт записей — `count` с полем `"*"`, самый быстрый запрос без выгрузки записей. Без массива `aggregate` результат тот же: ```json { "aggregate": [{ "field": "*", "function": "count" }] } ``` Сумма и среднее цены по всему каталогу, без разбиения по группам: ```json { "aggregate": [ { "field": "price", "function": "sum" }, { "field": "price", "function": "avg" } ] } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Общее количество товаров, соответствующих фильтру | | `data.aggregates` | object | Результаты агрегаций: `{ "price": { "sum": 0, "avg": 0 } }` | | `data.groups` | array | Группы — присутствуют только при `groupBy`. Каждый элемент: поля группировки + `count` + `aggregates` | | `data.meta.totalRecords` | number | Общее количество записей | | `data.meta.recordsProcessed` | number | Количество обработанных записей (до 5000) | | `data.meta.truncated` | boolean | `true`, если записей больше 5000 — агрегация по первым 5000 | | `data.meta.groupTotal` | number | Количество групп. Присутствует только при `groupBy` | | `data.meta.groupsTruncated` | boolean | `true`, если число групп было ограничено. Присутствует только при `groupBy` | ## Пример ответа ```json { "success": true, "data": { "count": 19, "aggregates": { "price": { "sum": 68680, "avg": 5283.076923076923 } }, "groups": [ { "sectionId": null, "count": 15, "aggregates": { "price": { "sum": 2662, "avg": 295.77777777777777 } } }, { "sectionId": 19, "count": 2, "aggregates": { "price": { "sum": 20, "avg": 10 } } }, { "sectionId": 85, "count": 2, "aggregates": { "price": { "sum": 65998, "avg": 32999 } } } ], "meta": { "totalRecords": 19, "recordsProcessed": 19, "truncated": false, "groupTotal": 3, "groupsTruncated": false } } } ``` Без `groupBy` поле `data.groups` в ответе отсутствует. ## Пример ответа при ошибке 400 — числовая функция по нечисловому полю: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "Field 'name' is not numeric (type: string). Only number fields support sum." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Неизвестная функция агрегации | | 400 | `INVALID_PARAMS` | Числовая функция по нечисловому полю — сообщение называет тип поля | | 400 | `INVALID_PARAMS` | Несуществующее поле — сообщение перечисляет допустимые числовые поля | | 400 | `INVALID_PARAMS` | Поле `groupBy` вне списка `price`, `sectionId`, `catalogId`, `active` | | 400 | `INVALID_PARAMS` | Передано более 5 полей в `groupBy` | | 403 | `SCOPE_DENIED` | API-ключу не хватает скоупа `crm` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`count` обходится одним запросом, числовые функции — нет.** `count` подсчитывается за один вызов независимо от объёма выборки. Функции `sum`, `avg`, `min`, `max` загружают записи постранично — до 5000 — и считают значения на стороне сервера. Если под фильтр попадает больше 5000 записей, `meta.truncated` равен `true`, а агрегаты и группы строятся по первым 5000. Для точного счётчика на больших выборках используйте `count` или сужайте фильтр. ## Смотрите также - [Список товаров](/docs/entities/products/list) - [Поиск товаров](/docs/entities/products/search) - [Поля товара](/docs/entities/products/fields) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Products: Create ## Создать товар `POST /v1/products` Создаёт товар CRM-каталога. Поля передаются плоско в корне JSON — без обёртки `fields`. В ответ приходит полный объект созданного товара. ## Поля запроса (body) | Поле | Битрикс24 | Тип | Обяз. | Описание | |------|----------|-----|:-----:|---------| | `name` | `NAME` | string | да | Название товара | | `price` | `PRICE` | number | нет | Цена товара. Валюту задаёт `currency` | | `currency` | `CURRENCY_ID` | string | нет | Валюта цены. Список: `GET /v1/currencies` | | `active` | `ACTIVE` | boolean | нет | Активен ли товар. По умолчанию `true` | | `sectionId` | `SECTION_ID` | number | нет | Раздел каталога. Список: `GET /v1/product-sections` | | `catalogId` | `CATALOG_ID` | number | нет | Каталог товара. По умолчанию — каталог CRM портала. Список: `GET /v1/catalogs` | | `measure` | `MEASURE` | number | нет | Идентификатор единицы измерения | | `description` | `DESCRIPTION` | string | нет | Описание товара | | `descriptionType` | `DESCRIPTION_TYPE` | string | нет | Формат описания: `text` или `html` | | `vatId` | `VAT_ID` | number | нет | Идентификатор ставки НДС | | `vatIncluded` | `VAT_INCLUDED` | boolean | нет | НДС включён в цену | | `sort` | `SORT` | number | нет | Порядок сортировки | | `xmlId` | `XML_ID` | string | нет | Внешний идентификатор | | `code` | `CODE` | string | нет | Символьный код. Если не передать — формируется из `name` | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/products" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Настольная лампа", "price": 100, "currency": "RUB" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/products" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Настольная лампа", "price": 100, "currency": "RUB" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/products', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Настольная лампа', price: 100, currency: 'RUB', }), }) const { success, data } = await res.json() console.log('ID товара:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/products', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Настольная лампа', price: 100, currency: 'RUB', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект созданного товара: базовые поля — см. [Поля товара](./fields.md), плюс пользовательские свойства `PROPERTY_` | URL карточки созданного товара в магазине портала строится из `catalogId` и `id`: ``` https://<портал>.bitrix24.ru/shop/catalog//product// ``` `<портал>` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа Показаны основные поля. В ответ также входят свойства каталога вида `PROPERTY_` — см. [Получить товар](./get.md). ```json { "success": true, "data": { "id": 7027, "name": "Настольная лампа", "code": "nastolnaya_lampa", "active": true, "previewPicture": null, "detailPicture": null, "sort": 500, "xmlId": "7027", "updatedAt": "2026-06-16T08:48:18.000Z", "createdAt": "2026-06-16T08:48:18.000Z", "modifyBy": 1, "createdBy": 1, "catalogId": 25, "sectionId": null, "description": null, "descriptionType": "text", "price": 100, "currency": "RUB", "vatId": null, "vatIncluded": false, "measure": null } } ``` ## Пример ответа при ошибке 422 — не передано название товара: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Не введено название.

" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Не передано поле `name` — сообщение «Не введено название.» | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список товаров](/docs/entities/products/list) - [Получить товар](/docs/entities/products/get) - [Обновить товар](/docs/entities/products/update) - [Удалить товар](/docs/entities/products/delete) - [Поля товара](/docs/entities/products/fields) - [Товары каталога](/docs/entities/catalog-products) - [Batch](/docs/batch) --- # Products: Delete ## Удалить товар `DELETE /v1/products/:id` Удаляет товар CRM-каталога по идентификатору. Восстановить удалённый товар через API нельзя — при необходимости создайте новый. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор товара. Список: [`GET /v1/products`](./list.md) | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/products/7027" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/products/7027" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/products/7027', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Товар удалён') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/products/7027', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Товар удалён') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом. Признак успеха — код ответа, не содержимое. ## Пример ответа ```http HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — товар не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Product is not found." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Товар с таким `id` не найден или уже удалён | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Деактивация вместо удаления.** Чтобы скрыть товар из каталога без удаления, обновите его полем `active`: [`PATCH /v1/products/:id`](./update.md) с телом `{"active": false}`. Товар останется в каталоге и его можно вернуть обратным обновлением. ## Смотрите также - [Список товаров](/docs/entities/products/list) - [Получить товар](/docs/entities/products/get) - [Создать товар](/docs/entities/products/create) - [Обновить товар](/docs/entities/products/update) - [Товары каталога](/docs/entities/catalog-products) - [Batch](/docs/batch) --- # Products: Fields ## Поля товара `GET /v1/products/fields` Возвращает схему полей товара: 21 стандартное поле и пользовательские свойства каталога вида `PROPERTY_`, настроенные на портале. Для каждого поля указаны подпись, тип и признак «только для чтения»; там, где есть что добавить, — описание, а у полей с фиксированным набором значений — словарь `enum`. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/products/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/products/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/products/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() console.log('Всего полей:', Object.keys(data.fields).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/products/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Стандартные поля Каждое поле описано объектом `{ type, readonly }` и возвращается в camelCase в ответах `list`, `get`, `search`, `create`, `update`. | Поле | Битрикс24 | Тип | RO | Описание | |------|----------|-----|:--:|---------| | `id` | `ID` | number | да | Идентификатор товара | | `name` | `NAME` | string | | Название товара | | `active` | `ACTIVE` | boolean | | Активен ли товар | | `price` | `PRICE` | number | | Цена товара | | `currency` | `CURRENCY_ID` | string | | Валюта цены. Список: `GET /v1/currencies` | | `sectionId` | `SECTION_ID` | number | | Раздел каталога. Список: `GET /v1/product-sections` | | `catalogId` | `CATALOG_ID` | number | | Идентификатор каталога. Список: `GET /v1/catalogs` | | `measure` | `MEASURE` | number | | Идентификатор единицы измерения | | `description` | `DESCRIPTION` | string | | Описание товара | | `descriptionType` | `DESCRIPTION_TYPE` | string | | Формат описания — `text` или `html` | | `sort` | `SORT` | number | | Порядок сортировки. Меньшее значение — выше | | `code` | `CODE` | string | | Символьный код товара | | `xmlId` | `XML_ID` | string | | Внешний идентификатор для синхронизации | | `vatId` | `VAT_ID` | number | | Идентификатор ставки НДС | | `vatIncluded` | `VAT_INCLUDED` | boolean | | Включён ли НДС в цену | | `previewPicture` | `PREVIEW_PICTURE` | object | да | Изображение для списка | | `detailPicture` | `DETAIL_PICTURE` | object | да | Изображение для карточки | | `createdBy` | `CREATED_BY` | number | да | Идентификатор создателя. Список: `GET /v1/users` | | `modifyBy` | `MODIFIED_BY` | number | да | Идентификатор последнего редактора. Список: `GET /v1/users` | | `createdAt` | `DATE_CREATE` | datetime | да | Дата создания | | `updatedAt` | `TIMESTAMP_X` | datetime | да | Дата последнего изменения | ## Пользовательские свойства Свойства каталога приходят дополнительными ключами вида `PROPERTY_` с типом `product_property`. Каждое описано объектом `{ type, readonly, label }`, где `label` — название свойства на языке портала. Набор свойств зависит от настроек каталога: один портал может вернуть «Артикул», «Производитель», «Цвет», другой — собственный список. Значения этих свойств возвращаются в ответе [`GET /v1/products/:id`](/docs/entities/products/get). ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.fields` | object | Карта полей. Ключ — имя поля, значение — `{ type, readonly, label }`; у части полей дополнительно `description`, а у полей с фиксированным набором значений — `enum` | ## Пример ответа Показана часть полей. Реальное количество свойств `PROPERTY_` зависит от настроек каталога на портале. ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "Идентификатор товара" }, "name": { "type": "string", "readonly": false, "label": "Название товара" }, "active": { "type": "boolean", "readonly": false, "label": "Активность", "description": "Активен ли товар." }, "price": { "type": "number", "readonly": false, "label": "Цена товара" }, "currency": { "type": "string", "readonly": false, "label": "Валюта цены", "description": "Валюта цены. Список доступных значений: GET /v1/currencies." }, "descriptionType": { "type": "string", "readonly": false, "label": "Формат описания", "description": "Формат поля description: обычный текст или HTML-разметка.", "enum": [ { "value": "text", "label": "Plain text", "labelRu": "Текст" }, { "value": "html", "label": "HTML", "labelRu": "HTML" } ] }, "vatIncluded": { "type": "boolean", "readonly": false, "label": "НДС включён в цену", "description": "Включён ли НДС в цену товара." }, "createdAt": { "type": "datetime", "readonly": true, "label": "Дата создания" }, "PROPERTY_301": { "type": "product_property", "readonly": false, "label": "Артикул" }, "PROPERTY_303": { "type": "product_property", "readonly": false, "label": "Производитель" }, "PROPERTY_307": { "type": "product_property", "readonly": false, "label": "Цвет" } } } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключу не хватает скоупа `crm` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Тот же товар в каталоге имеет больше полей.** Товар с тем же `id` доступен через [`GET /v1/catalog-products`](/docs/entities/catalog-products), где у него шире набор полей — остатки, склад и вариации. **Дескриптор `PROPERTY_` несёт только название свойства — вариантов списка в нём нет.** Объект описания устроен ровно как `{ type: "product_property", readonly, label }`: ни `items`, ни `values`, ни какого-либо перечня допустимых значений. Поэтому по этому эндпоинту можно узнать, что свойство `301` называется «Артикул», но развернуть ID выбранного варианта в его текст — нечем. Куда идти за значениями: | Задача | Вызов | |---|---| | Читаемый текст свойства у **одного** товара | [`GET /v1/catalog-products/:id`](/docs/entities/catalog-products/get) — текст приходит готовым в `propertyNNN.valueEnum` | | **Все** варианты списочного свойства (выпадашка, фильтр, экспорт) | [`GET /v1/catalog-product-property-enums?filter[propertyId]=NNN&limit=1000`](/docs/entities/catalog-product-property-enums/list) | | Тип свойства (`propertyType`, `listType`, `multiple`) | [`GET /v1/catalog-product-properties/:id`](/docs/entities/catalog-product-properties/get) | Здесь `NNN` — число из ключа `PROPERTY_`: это одно и то же значение, `id` свойства каталога. Обоим каталожным вызовам нужен скоуп `catalog` — ключ со скоупом только `crm` получит `403 SCOPE_DENIED`. ## Смотрите также - [Получить товар](/docs/entities/products/get) - [Список товаров](/docs/entities/products/list) - [Агрегация товаров](/docs/entities/products/aggregate) - [Entity API](/docs/entity-api) - [Товары каталога](/docs/entities/catalog-products) - [Свойства товаров каталога](/docs/entities/catalog-product-properties) - [Значения списочных свойств](/docs/entities/catalog-product-property-enums) --- # Products: Get ## Получить товар `GET /v1/products/:id` Возвращает один товар CRM-каталога по идентификатору. В ответ входят базовые поля товара и пользовательские свойства `PROPERTY_`, настроенные для каталога на портале. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор товара. Список: [`GET /v1/products`](./list.md) | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/products/6967" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/products/6967" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/products/6967', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Товар:', data.name, '—', data.price, data.currency) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/products/6967', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект товара: базовые поля — см. [Поля товара](./fields.md), плюс пользовательские свойства `PROPERTY_` | Базовые поля совпадают с элементом массива в [`GET /v1/products`](./list.md). Дополнительно приходят свойства вида `PROPERTY_` — по одному ключу на каждое свойство каталога. Если значение не заполнено, ключ возвращается со значением `null`. ## Пример ответа ```json { "success": true, "data": { "id": 6967, "name": "Головной товар", "code": "product_sku", "active": true, "previewPicture": null, "detailPicture": null, "sort": 100, "xmlId": "6967", "updatedAt": "2025-05-12T09:05:27.000Z", "createdAt": "2025-05-12T09:03:15.000Z", "modifyBy": 1, "createdBy": 1, "catalogId": 25, "sectionId": null, "description": null, "descriptionType": "text", "price": 100, "currency": "RUB", "vatId": null, "vatIncluded": false, "measure": null, "PROPERTY_309": null, "PROPERTY_295": null, "PROPERTY_297": null } } ``` ## Пример ответа при ошибке 404 — товар не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Product is not found." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Товар с таким `id` не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Набор свойств одинаков в пределах каталога.** Состав ключей `PROPERTY_` определяется настройками каталога на портале — у всех товаров одного каталога он совпадает. **Заполненное списочное свойство приходит только идентификатором, без текста.** Это семейство (`crm.product.*`) отдаёт в `PROPERTY_` объект `{ "valueId": "...", "value": "..." }`, где `value` — ID выбранного элемента перечисления, а не его название. Читаемый текст здесь взять неоткуда, и `/v1/products/fields` его тоже не содержит — дескриптор свойства несёт только имя. Два пути дальше: - за читаемым текстом **одного** товара — [`GET /v1/catalog-products/:id`](/docs/entities/catalog-products/get): каталожное семейство возвращает готовый текст в `propertyNNN.valueEnum`; - за **всеми** вариантами свойства (выпадашка, фильтр, экспорт) — [`GET /v1/catalog-product-property-enums?filter[propertyId]=NNN&limit=1000`](/docs/entities/catalog-product-property-enums/list). Оба вызова требуют скоупа `catalog` — у ключа со скоупом только `crm` они вернут `403 SCOPE_DENIED`. **Пустое значение `PROPERTY_` означает одно из двух.** Различаются они одним перекрёстным вызовом [`GET /v1/catalog-products/:id`](/docs/entities/catalog-products/get): - **свойство не заполнено у этого товара** — каталожный эндпоинт тоже вернёт пусто, либо синтезированное `"N"` для свойства-галочки (`listType: "C"`); - **свойство обслуживается только каталожным семейством** (например, строковое свойство с пользовательским типом `directory`) — тогда каталожный эндпоинт значение вернёт, а `/v1/products` отдаёт `null`. **Торговые предложения через этот эндпоинт не видны.** `crm.product.*` работает с товарами CRM-каталога; предложения (офферы) лежат в отдельном каталоге и читаются через [`GET /v1/catalog-products`](/docs/entities/catalog-products). ## Смотрите также - [Список товаров](/docs/entities/products/list) - [Обновить товар](/docs/entities/products/update) - [Удалить товар](/docs/entities/products/delete) - [Поля товара](/docs/entities/products/fields) - [Товары](/docs/entities/products) - [Товары каталога](/docs/entities/catalog-products) - [Значения списочных свойств](/docs/entities/catalog-product-property-enums) --- # Products: List ## Список товаров `GET /v1/products` Возвращает список товаров CRM-каталога с поддержкой фильтрации, сортировки и авто-пагинации. Элемент списка содержит базовые поля товара без пользовательских свойств `PROPERTY_` — они приходят в [`GET /v1/products/:id`](./get.md). ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` запрос автоматически собирается из нескольких страниц на стороне сервера | | `offset` | number | `0` | Смещение от начала выборки | | `select` | string | — | Выборка полей: `?select=id,name,price,active` | | `order` | object | — | Сортировка по полям `id`, `name`, `sort`. Пример: `?order[sort]=desc`, `?order[name]=asc`. Поля `price` и `currency` сортировку не поддерживают | | `filter` | object | — | Только точное равенство и `$in` (IN-множество) по полям `id`, `name`, `code`, `xmlId`, `active`, `sectionId`, `sort`. Операторы (`>`, `>=`, `<`, `<=`, `!`, `%`, `$ne`, `$contains`, `$nin`) и фильтрация по другим полям (`price`, `currency`) не поддерживаются — вернётся `400 UNSUPPORTED_FILTER`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[active]=true` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/products?filter[active]=true&order[sort]=desc&limit=10" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/products?filter[active]=true&order[sort]=desc&limit=10" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const params = new URLSearchParams({ 'filter[active]': 'true', 'order[sort]': 'desc', limit: '10', }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/products?${params}`, { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Товаров: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const params = new URLSearchParams({ 'filter[active]': 'true', 'order[sort]': 'desc', limit: '10', }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/products?${params}`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив товаров. Состав полей элемента — см. [Поля товара](./fields.md) | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | URL карточки любого товара из массива `data` в магазине портала строится из `catalogId` и `id`: ``` https://<портал>.bitrix24.ru/shop/catalog//product// ``` `<портал>` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 6967, "name": "Головной товар", "code": "product_sku", "active": true, "previewPicture": null, "detailPicture": null, "sort": 100, "xmlId": "6967", "updatedAt": "2025-05-12T09:05:27.000Z", "createdAt": "2025-05-12T09:03:15.000Z", "modifyBy": 1, "createdBy": 1, "catalogId": 25, "sectionId": null, "description": null, "descriptionType": "text", "price": 100, "currency": "RUB", "vatId": null, "vatIncluded": false, "measure": null }, { "id": 533, "name": "тест", "code": "test", "active": true, "previewPicture": null, "detailPicture": null, "sort": 500, "xmlId": "533", "updatedAt": "2023-08-21T09:12:18.000Z", "createdAt": "2021-07-20T11:01:36.000Z", "modifyBy": 29, "createdBy": 99, "catalogId": 25, "sectionId": 19, "description": null, "descriptionType": "html", "price": 10, "currency": "RUB", "vatId": 1, "vatIncluded": false, "measure": 9 } ], "meta": { "total": 19, "hasMore": true } } ``` ## Пример ответа при ошибке 400 — оператор или неподдерживаемое поле в фильтре: ```json { "success": false, "error": { "code": "UNSUPPORTED_FILTER", "message": "UNSUPPORTED_FILTER: 'price' is not filterable on 'products'. Its Bitrix24 method (crm.product.list) filters by exact match only. Filterable: id, name, code, xmlId, active, sectionId, sort." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSUPPORTED_FILTER` | Оператор или неподдерживаемое поле в фильтре. Фильтруйте точным равенством или `$in` по `id`, `name`, `code`, `xmlId`, `active`, `sectionId`, `sort` | | 400 | `INVALID_FILTER` | Ошибка в синтаксисе фильтра | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить товар](/docs/entities/products/get) - [Создать товар](/docs/entities/products/create) - [Поля товара](/docs/entities/products/fields) - [Товары](/docs/entities/products) - [Товары каталога](/docs/entities/catalog-products) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) --- # Products: Search ## Поиск товаров `POST /v1/products/search` Поиск товаров каталога с фильтрами и авто-пагинацией. Параметры передаются в теле запроса — это удобнее для составных фильтров из нескольких условий и для программной сборки запросов. Для списков до 5000 записей подойдёт и [`GET /v1/products`](/docs/entities/products/list) с фильтром в query-параметрах. ## Поля запроса (body) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Только точное равенство и `$in` (IN-множество) по полям `id`, `name`, `code`, `xmlId`, `active`, `sectionId`, `sort`. Операторы (`>`, `>=`, `<`, `<=`, `!`, `%`, `$ne`, `$contains`, `$nin`) и фильтрация по другим полям (`price`, `currency`) не поддерживаются — вернётся `400 UNSUPPORTED_FILTER`.
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "sectionId": 19, "active": true }` | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей | | `order` | object | — | Сортировка по полям `id`, `name`, `sort`: `{ "sort": "desc" }`. Поля `price` и `currency` сортировку не поддерживают | | `select` | string[] | — | Выборка полей: `["id", "name", "price"]` | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/products/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "active": true }, "limit": 20, "order": { "sort": "desc" } }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/products/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "active": true }, "limit": 20, "order": { "sort": "desc" } }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/products/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { active: true }, limit: 20, order: { sort: 'desc' }, }), }) const { success, data, meta } = await res.json() console.log('Найдено:', meta.total) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/products/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { active: true }, limit: 20, order: { sort: 'desc' }, }), }) const { success, data, meta } = await res.json() ``` ### Другие сценарии Товары одного раздела каталога: ```json { "filter": { "sectionId": 19 } } ``` Несколько товаров по идентификаторам через `$in`: ```json { "filter": { "id": { "$in": [6967, 533] } } } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив товаров (все поля — см. [Поля товара](/docs/entities/products/fields)) | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. URL карточки любого товара из массива `data` строится из `catalogId` и `id`: `https://<портал>.bitrix24.ru/shop/catalog//product//`. `<портал>` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 6967, "name": "Головной товар", "code": "product_sku", "active": true, "sort": 100, "xmlId": "6967", "catalogId": 25, "sectionId": null, "price": 100, "currency": "RUB", "vatId": null, "vatIncluded": false, "createdAt": "2025-05-12T09:03:15.000Z", "updatedAt": "2025-05-12T09:05:27.000Z" }, { "id": 6969, "name": "Услуга", "code": "service", "active": true, "catalogId": 25, "price": 250, "currency": "RUB", "vatId": 1, "vatIncluded": true, "createdAt": "2025-05-12T09:04:01.000Z", "updatedAt": "2025-05-12T09:04:01.000Z" } ], "meta": { "total": 19, "hasMore": true, "durationMs": 2509 } } ``` ## Пример ответа при ошибке 400 — оператор или неподдерживаемое поле в фильтре: ```json { "success": false, "error": { "code": "UNSUPPORTED_FILTER", "message": "UNSUPPORTED_FILTER: operators are not supported on 'products' (near 'price'). Its Bitrix24 method (crm.product.list) filters by exact match only — operators are silently ignored by Bitrix24. Use exact match (field: value) or $in (field: {$in: [...]}) on: id, name, code, xmlId, active, sectionId, sort." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSUPPORTED_FILTER` | Оператор или неподдерживаемое поле в фильтре. Фильтруйте точным равенством или `$in` по `id`, `name`, `code`, `xmlId`, `active`, `sectionId`, `sort` | | 400 | `INVALID_FILTER` | Ошибка при разборе фильтра | | 403 | `SCOPE_DENIED` | API-ключу не хватает скоупа `crm` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Авто-пагинация.** При `limit > 50` запрос автоматически разбивается на несколько вызовов к Битрикс24, максимум — 5000 записей за вызов. Когда под фильтр попадает больше записей, `meta.hasMore` равен `true` — для следующей порции увеличивайте `offset`. **Свойства каталога в ответ не входят.** Массив `data` содержит стандартные поля товара. Чтобы получить значения свойств `PROPERTY_`, запросите товар по идентификатору через [`GET /v1/products/:id`](/docs/entities/products/get). ## Смотрите также - [Список товаров](/docs/entities/products/list) - [Получить товар](/docs/entities/products/get) - [Поля товара](/docs/entities/products/fields) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Products: Update ## Обновить товар `PATCH /v1/products/:id` Обновляет товар CRM-каталога. Передавайте только изменяемые поля плоско в корне JSON — без обёртки `fields`. В ответ приходит полный объект обновлённого товара. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор товара. Список: [`GET /v1/products`](./list.md) | ## Поля запроса (body) | Поле | Битрикс24 | Тип | Обяз. | Описание | |------|----------|-----|:-----:|---------| | `name` | `NAME` | string | нет | Название товара | | `price` | `PRICE` | number | нет | Цена товара. Валюту задаёт `currency` | | `currency` | `CURRENCY_ID` | string | нет | Валюта цены. Список: `GET /v1/currencies` | | `active` | `ACTIVE` | boolean | нет | Активен ли товар | | `sectionId` | `SECTION_ID` | number | нет | Раздел каталога. Список: `GET /v1/product-sections` | | `catalogId` | `CATALOG_ID` | number | нет | Каталог товара. Список: `GET /v1/catalogs` | | `measure` | `MEASURE` | number | нет | Идентификатор единицы измерения | | `description` | `DESCRIPTION` | string | нет | Описание товара | | `descriptionType` | `DESCRIPTION_TYPE` | string | нет | Формат описания: `text` или `html` | | `vatId` | `VAT_ID` | number | нет | Идентификатор ставки НДС | | `vatIncluded` | `VAT_INCLUDED` | boolean | нет | НДС включён в цену | | `sort` | `SORT` | number | нет | Порядок сортировки | | `xmlId` | `XML_ID` | string | нет | Внешний идентификатор | | `code` | `CODE` | string | нет | Символьный код товара | | `createdBy` | `CREATED_BY` | number | RO | Идентификатор создавшего сотрудника | | `modifyBy` | `MODIFIED_BY` | number | RO | Идентификатор изменившего сотрудника | | `createdAt` | `DATE_CREATE` | datetime | RO | Дата создания | | `updatedAt` | `TIMESTAMP_X` | datetime | RO | Дата последнего изменения | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/products/7027" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "price": 150 }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/products/7027" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "price": 150 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/products/7027', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ price: 150, }), }) const { success, data } = await res.json() console.log('Новая цена:', data.price) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/products/7027', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ price: 150, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект обновлённого товара: базовые поля — см. [Поля товара](./fields.md), плюс пользовательские свойства `PROPERTY_` | ## Пример ответа Показаны основные поля. В ответ также входят свойства каталога вида `PROPERTY_` — см. [Получить товар](./get.md). ```json { "success": true, "data": { "id": 7027, "name": "Настольная лампа", "code": "nastolnaya_lampa", "active": true, "previewPicture": null, "detailPicture": null, "sort": 500, "xmlId": "7027", "updatedAt": "2026-06-16T08:48:21.000Z", "createdAt": "2026-06-16T08:48:18.000Z", "modifyBy": 1, "createdBy": 1, "catalogId": 25, "sectionId": null, "description": null, "descriptionType": "text", "price": 150, "currency": "RUB", "vatId": null, "vatIncluded": false, "measure": null } } ``` ## Пример ответа при ошибке 404 — товар не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Product is not found." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Товар с таким `id` не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить товар](/docs/entities/products/get) - [Создать товар](/docs/entities/products/create) - [Удалить товар](/docs/entities/products/delete) - [Поля товара](/docs/entities/products/fields) - [Товары каталога](/docs/entities/catalog-products) - [Batch](/docs/batch) --- # Quotes: Aggregate ## Агрегация предложений `POST /v1/quotes/aggregate` Подсчёт количества, сумма, среднее, минимум и максимум по коммерческим предложениям с фильтрацией и группировкой. **Стандартные поля:** - `amount` — сумма предложения (числовое агрегирование имеет смысл) - `stageId` — стадия (для `groupBy`) - `assignedById` — ответственный (для `groupBy`) **Пользовательские поля (UF):** UF-поля типов `integer`, `double`, `money` — для числовых функций; UF любого типа — для `groupBy`. Полный список UF-полей конкретного портала приходит в тексте ошибки `INVALID_PARAMS`, если передать несуществующее имя. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций. Каждый элемент: `{ "field": "amount", "function": "sum" }`. Функции: `count`, `sum`, `avg`, `min`, `max`. Для `count` поле — `"*"`. Без массива — только `count` | | `filter` | object | нет | Фильтрация по полям `GET /v1/quotes/fields`. [Синтаксис фильтрации](/docs/filtering) | | `groupBy` | string \| string[] | нет | Поле или массив полей для группировки (максимум 5). Допустимые значения — из списка выше | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/quotes/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "amount", "function": "sum" }, { "field": "amount", "function": "avg" } ], "filter": { "assignedById": 1 }, "groupBy": "stageId" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/quotes/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "amount", "function": "sum" }, { "field": "amount", "function": "avg" } ], "filter": { "assignedById": 1 }, "groupBy": "stageId" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [ { field: 'amount', function: 'sum' }, { field: 'amount', function: 'avg' }, ], filter: { assignedById: 1 }, groupBy: 'stageId', }), }) const { success, data } = await res.json() console.log('Всего предложений:', data.count) console.log('По стадиям:', data.groups) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [ { field: 'amount', function: 'sum' }, { field: 'amount', function: 'avg' }, ], filter: { assignedById: 1 }, groupBy: 'stageId', }), }) const { success, data } = await res.json() ``` > Для группировки по нескольким полям передайте массив: `"groupBy": ["stageId", "assignedById"]` (максимум 5). ## Другие сценарии Подсчёт записей — `count` с полем `"*"`, самый быстрый запрос без выгрузки записей. Без массива `aggregate` результат тот же: ```json { "aggregate": [{ "field": "*", "function": "count" }] } ``` Работа с пользовательскими полями (UF) — `sum` по UF + группировка по другому UF: ```json { "aggregate": [{ "field": "UF_CRM_DISCOUNT", "function": "sum" }], "groupBy": "UF_CRM_PRIORITY" } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Общее количество записей под фильтр | | `data.aggregates` | object | Результаты агрегаций: `{ "amount": { "sum": 90000, "avg": 2500 } }` | | `data.groups` | array | Группы (только при `groupBy`). Каждый элемент: поля группировки + `count` + `aggregates` | | `data.meta.totalRecords` | number | Общее количество записей под фильтр | | `data.meta.recordsProcessed` | number | Сколько записей обработано для числовых агрегаций (максимум 5000) | | `data.meta.truncated` | boolean | `true`, если под фильтр попало больше 5000 записей | ## Пример ответа Ответ на основной запрос (агрегации + `groupBy: "stageId"`): ```json { "success": true, "data": { "count": 36, "aggregates": { "amount": { "sum": 90000, "avg": 2500 } }, "groups": [ { "stageId": "DRAFT", "count": 20, "aggregates": { "amount": { "sum": 50000 } } }, { "stageId": "APPROVED", "count": 16, "aggregates": { "amount": { "sum": 40000 } } } ], "meta": { "totalRecords": 36, "recordsProcessed": 36, "truncated": false } } } ``` Без `groupBy` поле `data.groups` в ответе отсутствует. ## Пример ответа при ошибке 400 — неверное имя функции, несуществующее поле или `groupBy` по неаггрегируемому полю: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "Field 'foo' not found. Available numeric fields: amount, stageId, assignedById" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Некорректное имя функции, несуществующее поле, нечисловое поле в `sum`/`avg`/`min`/`max`, `groupBy` по неаггрегируемому полю или больше 5 полей в `groupBy` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`count` vs числовые функции.** `count` считается одним вызовом в Битрикс24 на любом объёме данных. Функции `sum`/`avg`/`min`/`max` подгружают записи постранично (максимум 5000) и считают на стороне Вайбкод — если под фильтр попадает больше 5000 записей, `meta.truncated` будет `true`, агрегация выполнится по первым 5000. Для точных счётчиков на больших выборках используйте `count` или сужайте фильтр. **Money-поля.** UF-поля типа `money` хранятся в формате `"сумма|валюта"` (`"1500|RUB"`) — агрегат извлекает числовую часть автоматически, складывать можно без парсинга. **Фильтрация по UF работает.** В `filter` можно передавать любые поля — стандартные и пользовательские, любого типа. Например, `{ "filter": { "ufCrm_1234": "value" } }` вернёт количество предложений с этим значением UF. ## Смотрите также - [Список предложений](/docs/entities/quotes/list) - [Поиск предложений](/docs/entities/quotes/search) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Quotes: Create ## Создать предложение `POST /v1/quotes` Создаёт новое коммерческое предложение в CRM. ## Поля запроса (body) | Параметр | Тип | Описание | |----------|-----|---------| | `title` | string | Название предложения | | `opportunity` | number | Сумма. Чтобы сумма не пересчитывалась из товарных позиций, передайте вместе с `isManualOpportunity: true`. Принимается и camelCase-имя `amount` | | `isManualOpportunity` | boolean | `true` — ручной режим суммы (обязателен, если задаёте `opportunity`/`amount` напрямую). Битрикс24 хранит флаг как `Y`/`N`; булево значение преобразуется автоматически (строка `"Y"` тоже принимается) | | `currencyId` | string | Валюта. Список: `GET /v1/currencies` | | `stageId` | string | Статус: `DRAFT`, `SENT`, `APPROVED`. Список: `GET /v1/statuses?filter[entityId]=QUOTE_STATUS` | | `dealId` | number | ID сделки. Поиск: `GET /v1/deals` | | `contactId` | number | ID контакта. Поиск: `GET /v1/contacts` | | `companyId` | number | ID компании. Поиск: `GET /v1/companies` | | `assignedById` | number | ID ответственного. Список сотрудников: `GET /v1/users` | | `comments` | string | Комментарий | | `begindate` | datetime | Дата начала | | `closedate` | datetime | Дата закрытия | > **Имена полей.** В ответе поля возвращаются в camelCase: `amount`, `currency`, `beginDate`, `closeDate`. На запись принимаются оба варианта — и эти camelCase-имена, и B24-native `opportunity` / `currencyId` / `begindate` / `closedate`: слой API приводит их к нужному имени Битрикс24. Полный список полей: [GET /v1/quotes/fields](/docs/entities/quotes/fields). Пользовательские поля (`ufCrm_*`) также принимаются. ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/quotes \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "КП на серверное оборудование", "opportunity": 150000, "isManualOpportunity": true, "currencyId": "RUB", "stageId": "DRAFT", "dealId": 741, "assignedById": 1 }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/quotes \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "КП на серверное оборудование", "opportunity": 150000, "isManualOpportunity": true, "currencyId": "RUB", "stageId": "DRAFT", "dealId": 741, "assignedById": 1 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'КП на серверное оборудование', opportunity: 150000, isManualOpportunity: true, currencyId: 'RUB', stageId: 'DRAFT', dealId: 741, assignedById: 1, }), }) const { success, data } = await res.json() console.log('Quote ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'КП на серверное оборудование', opportunity: 150000, isManualOpportunity: true, currencyId: 'RUB', stageId: 'DRAFT', dealId: 741, assignedById: 1, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID созданного предложения | | `title` | string | Название | | `amount` | number | Сумма | | `currency` | string | Валюта | | `stageId` | string | Статус | | `dealId` | number | ID сделки | | `assignedById` | number | Ответственный | | `createdBy` | number | Создатель | | `createdTime` | datetime | Дата создания | | `updatedTime` | datetime | Дата изменения | Ответ содержит все поля предложения, включая пользовательские (`ufCrm_*`). Выше показаны основные. URL карточки предложения в Битрикс24 строится из `id`: ``` https://.bitrix24.ru/crm/type/7/details// ``` `7` — `entityTypeId` коммерческого предложения в Битрикс24. `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": { "id": 412, "title": "КП на серверное оборудование", "amount": 150000, "isManualOpportunity": true, "currency": "RUB", "stageId": "DRAFT", "dealId": 741, "contactId": 0, "companyId": 0, "assignedById": 1, "createdBy": 1, "comments": "", "beginDate": "2026-04-15T00:00:00.000Z", "closeDate": "2026-05-15T00:00:00.000Z", "createdTime": "2026-04-15T10:30:00.000Z", "updatedTime": "2026-04-15T10:30:00.000Z" } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 400 | `INVALID_REQUEST` | Некорректные поля | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Работа с файлами в полях CRM](/docs/recipes/crm-files) - [Список предложений](/docs/entities/quotes/list) - [Поля предложения](/docs/entities/quotes/fields) - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Quotes: Delete ## Удалить предложение `DELETE /v1/quotes/:id` Удаляет коммерческое предложение по ID. Восстановить удалённое предложение через API нельзя — создавайте новое при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID предложения | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/quotes/412" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/quotes/412" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/412', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Предложение удалено') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/412', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — предложение не найдено: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Предложение не найдено | | 403 | `ACCESS_DENIED` | Нет доступа к предложению | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список предложений](/docs/entities/quotes/list) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Quotes: Fields ## Поля предложения `GET /v1/quotes/fields` Возвращает полный список доступных полей, включая пользовательские (`ufCrm_*`). ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/quotes/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/quotes/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Битрикс24 | Тип | RO | Описание | |------|----------|-----|:--:|---------| | `id` | `id` | number | да | ID предложения | | `quoteNumber` | `quoteNumber` | string | | № предложения | | `title` | `title` | string | | Название | | `amount` | `opportunity` | number | | Сумма | | `taxValue` | `taxValue` | number | | Сумма налога | | `currency` | `currencyId` | string | | Валюта. Список: `GET /v1/currencies` | | `stageId` | `stageId` | string | | Статус: `DRAFT`, `SENT`, `APPROVED`. Список: `GET /v1/statuses?filter[entityId]=QUOTE_STATUS` | | `isManualOpportunity` | `isManualOpportunity` | boolean | | Ручной режим суммы (`Y`/`N` в Битрикс24, преобразуется в булево) | | `opened` | `opened` | boolean | | Доступно для всех | | `closed` | `closed` | boolean | да | Предложение закрыто | | `dealId` | `dealId` | number | | ID сделки. Поиск: `GET /v1/deals` | | `leadId` | `leadId` | number | | ID лида. Поиск: `GET /v1/leads` | | `contactId` | `contactId` | number | | ID контакта. Поиск: `GET /v1/contacts` | | `contactIds` | `contactIds` | array | | ID контактов предложения. Передавайте полный список — набор привязок заменяется целиком, а не дополняется | | `contacts` | `contacts` | array | да | Контакты предложения | | `companyId` | `companyId` | number | | ID компании. Поиск: `GET /v1/companies` | | `mycompanyId` | `mycompanyId` | number | | Реквизиты вашей компании | | `personTypeId` | `personTypeId` | number | да | Тип плательщика | | `assignedById` | `assignedById` | number | | Ответственный. Список: `GET /v1/users` | | `createdBy` | `createdBy` | number | да | Создатель. Поиск: `GET /v1/users` | | `updatedBy` | `updatedBy` | number | да | Кем обновлено | | `lastActivityBy` | `lastActivityBy` | number | | Автор последней активности | | `comments` | `comments` | string | | Комментарий | | `content` | `content` | string | | Содержание | | `terms` | `terms` | string | | Условия | | `locationId` | `locationId` | string | | Местоположение | | `webformId` | `webformId` | number | | Создано CRM-формой | | `storageTypeId` | `storageTypeId` | number | | Тип хранилища файлов | | `storageElementIds` | `storageElementIds` | array | | ID файлов в хранилище | | `utmSource` | `utmSource` | string | | UTM Source | | `utmMedium` | `utmMedium` | string | | UTM Medium | | `utmCampaign` | `utmCampaign` | string | | UTM Campaign | | `utmContent` | `utmContent` | string | | UTM Content | | `utmTerm` | `utmTerm` | string | | UTM Term | | `beginDate` | `begindate` | datetime | | Дата начала | | `closeDate` | `closedate` | datetime | | Дата закрытия | | `actualDate` | `actualDate` | datetime | | Актуально до | | `lastActivityTime` | `lastActivityTime` | datetime | | Последняя активность | | `lastCommunicationTime` | `lastCommunicationTime` | string | да | Дата последней коммуникации | | `lastCommunicationCallTime` | `lastCommunicationCallTime` | datetime | да | Дата последнего звонка | | `lastCommunicationEmailTime` | `lastCommunicationEmailTime` | datetime | да | Дата последнего e-mail | | `lastCommunicationImolTime` | `lastCommunicationImolTime` | datetime | да | Дата последнего диалога в открытой линии | | `lastCommunicationWebformTime` | `lastCommunicationWebformTime` | datetime | да | Дата последнего заполнения CRM-формы | | `createdTime` | `createdTime` | datetime | да | Дата создания | | `updatedTime` | `updatedTime` | datetime | да | Дата изменения | **Пользовательские поля** (`ufCrm_*`) также возвращаются в ответах и принимаются при создании/обновлении. ## Доступные include Эндпоинт `GET /v1/quotes/fields` возвращает список доступных include: `deal`, `contact`, `company`. Пример использования: [Получить quotes](/docs/entities/quotes/get#связанные-данные). Подробнее об include: [Связанные данные](/docs/includes). ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "ID предложения", "description": "Идентификатор предложения, присваивается Битрикс24." }, "title": { "type": "string", "readonly": false, "label": "Название", "description": "Название предложения, отображается в списке и в карточке." }, "assignedById": { "type": "number", "readonly": false, "label": "Ответственный", "description": "Сотрудник, ответственный за предложение. Список: GET /v1/users." } }, "batch": ["create", "update", "delete"] } } ``` Показаны 3 из множества полей. Полный список в таблице выше. Каждое поле описано объектом `{ type, readonly, label, description }`. `label` — короткая подпись на русском языке, `description` — расширенное описание: назначение поля, где взять список допустимых значений, поведение при записи. У поля `stageId` набор значений настраивается на портале, поэтому вместо словаря в описании указана ссылка на справочник статусов. ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать предложение](/docs/entities/quotes/create) - [Пользовательские поля](/docs/userfields) - [Entity API](/docs/entity-api) - [Лимиты и оптимизация](/docs/optimization) --- # Quotes: Get ## Получить предложение `GET /v1/quotes/:id` Возвращает коммерческое предложение по ID со всеми полями, включая пользовательские (`ufCrm_*`). ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID предложения | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/quotes/412" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/quotes/412" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/412', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Предложение:', data.title, '—', data.amount, data.currency) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/412', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` Подробнее об include: [Связанные данные](/docs/includes). ## Поля ответа Объект предложения со всеми полями — см. [Поля предложения](/docs/entities/quotes/fields). ## Связанные данные Получить связанные сущности вместе с предложением — параметр `include` в GET-запросе: ``` GET /v1/quotes/412?include=deal,contact,company ``` Доступные include: `deal`, `contact`, `company`. Результат в поле `_included`: ```json { "success": true, "data": { "id": 412, "title": "КП на серверное оборудование", "_included": { "deal": { "id": 741, "title": "Поставка оборудования", "amount": 50000 }, "contact": { "id": 71, "name": "Иван Петров" }, "company": { "id": 15, "title": "ООО Ромашка" } } } } ``` Подробнее об include: [Связанные данные](/docs/includes). ## Пример ответа ```json { "success": true, "data": { "id": 412, "title": "КП на серверное оборудование", "amount": 150000, "currency": "RUB", "stageId": "SENT", "dealId": 741, "contactId": 71, "companyId": 15, "assignedById": 29, "createdBy": 1, "comments": "", "beginDate": "2026-04-15T00:00:00.000Z", "closeDate": "2026-05-15T00:00:00.000Z", "createdTime": "2026-04-15T10:30:00.000Z", "updatedTime": "2026-04-15T14:22:00.000Z", "_included": { "deal": { "id": 741, "title": "Поставка оборудования", "amount": 50000 }, "contact": { "id": 71, "name": "Иван Петров" }, "company": { "id": 15, "title": "ООО Ромашка" } } } } ``` ## Пример ответа при ошибке 404 — предложение не найдено: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` Подробнее об include: [Связанные данные](/docs/includes). ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Предложение с таким ID не найдено | | 403 | `ACCESS_DENIED` | Нет доступа к предложению | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Работа с файлами в полях CRM](/docs/recipes/crm-files) - [Обновить предложение](/docs/entities/quotes/update) - [Список предложений](/docs/entities/quotes/list) - [Поля предложения](/docs/entities/quotes/fields) - [Лимиты и оптимизация](/docs/optimization) --- # Quotes: List ## Список предложений `GET /v1/quotes` Возвращает список коммерческих предложений с поддержкой фильтрации, сортировки и авто-пагинации. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` ответ собирается из нескольких последовательных чтений по 50 записей | | `offset` | number | `0` | Пропустить N записей. При `offset > 0` рекомендуется `limit <= 500`. Для обхода всей коллекции дешевле курсор — `order[id]=asc` и `filter[>id]` из `meta.nextAfterId` | | `select` | string | — | Выборка полей: `?select=id,title,amount` | | `order` | object | — | Сортировка: `?order[createdTime]=desc` | | `filter` | object | — | Фильтрация по полям `GET /v1/quotes/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[stageId]=DRAFT` | | `withTotal` | string | — | Нужно ли количество: `true` или `false`. `false` — не заказывать подсчёт. Это единственный способ гарантированно убрать `meta.total` из ответа. Без параметра — настройка ключа, затем платформенное умолчание, и тогда на короткой странице точное количество приходит и без заказа. [Листание и количество](/docs/entity-api#листание-и-количество-записей) | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/quotes?limit=10&order[amount]=desc&filter[stageId]=DRAFT" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/quotes?limit=10&order[amount]=desc&filter[stageId]=DRAFT" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes?limit=10&order[amount]=desc&filter[stageId]=DRAFT', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} предложений`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes?limit=10&order[amount]=desc&filter[stageId]=DRAFT', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив предложений (каждое содержит все поля — см. [Поля](/docs/entities/quotes/fields)) | | `meta.total` | number | Общее количество записей, соответствующих фильтру. Необязательное поле: если количество не заказывалось, его в ответе нет | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.nextAfterId` | string | Идентификатор последней отданной записи. Приходит при сортировке строго по `id` по возрастанию, пока `hasMore` равен `true`. Передайте его обратно как `filter[>id]` — это дешёвая замена растущему `offset` | URL карточки любого предложения из массива `data` — его `id`: ``` https://.bitrix24.ru/crm/type/7/details// ``` `7` — `entityTypeId` коммерческого предложения в Битрикс24. `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 412, "title": "КП на серверное оборудование", "amount": 150000, "currency": "RUB", "stageId": "DRAFT", "dealId": 741, "assignedById": 1, "createdTime": "2026-04-15T10:30:00.000Z", "contactId": 71, "companyId": 15 } ], "meta": { "total": 48, "hasMore": true } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Авто-пагинация:** `limit > 50` выполняется несколькими последовательными чтениями по 50 записей, а ответ приходит одним массивом. Время ответа растёт вместе с `limit` — [Клиентский таймаут](/docs/optimization#клиентский-таймаут). **Ограничение `offset`:** при `offset >= 2500` ответ может прийти с `INTERNAL_ERROR`. Держите `limit <= 500` на больших смещениях, а всю коллекцию обходите курсором `filter[>id]` — он не зависит от глубины. **Когда использовать поиск.** Сложные фильтры с множеством условий передаются в теле запроса, а не в строке запроса. Поиск дополнительно разбивает широкий диапазон дат на окна — [Поиск с разбиением по датам](/docs/optimization#поиск-с-разбиением-по-датам). См. [Поиск предложений](/docs/entities/quotes/search). ## Смотрите также - [Поиск предложений](/docs/entities/quotes/search) - [Создать предложение](/docs/entities/quotes/create) - [Синтаксис фильтрации](/docs/filtering) - [Обзор API](/docs/entity-api) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Quotes: Products Add > Поле, которого нет среди записываемых, больше не отбрасывается молча — запрос отклоняется с `400 INVALID_PARAMS`, и в тексте ошибки перечислены записываемые имена. Поля только для чтения, которые приходят в ответах товарных позиций (`priceAccount`, `ownerId`, `storeId` и другие) по-прежнему принимаются и игнорируются, поэтому объект, прочитанный через GET, можно отправить обратно без чистки. ## Добавить товар в предложение `POST /v1/quotes/:id/products` Добавляет одну товарную позицию в предложение. В отличие от `PUT /v1/quotes/:id/products`, не заменяет существующие позиции. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID предложения | | `productId` | number | нет | ID товара из каталога. Если задан без `productName`, имя подставляется из каталога. Каталог: `GET /v1/products` | | `productName` | string | нет | Название товарной позиции — для произвольной строки без товара из каталога. Укажите хотя бы одно из `productId` / `productName`. | | `price` | number | нет | Цена за единицу | | `quantity` | number | нет | Количество | | `discount` | number | нет | Сумма скидки | | `taxRate` | number | нет | Ставка налога (%) | | `taxIncluded` | boolean | нет | Налог включён в цену | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/quotes/52/products" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "productId": 1, "price": 25000, "quantity": 2 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/quotes/52/products" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "productId": 1, "price": 25000, "quantity": 2 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/52/products', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ productId: 1, price: 25000, quantity: 2 }), }) const { success, data } = await res.json() console.log('ID строки:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/52/products', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ productId: 1, price: 25000, quantity: 2 }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | object | Созданная товарная строка целиком, HTTP-статус `201`. Состав полей — [Поля товаров](/docs/entities/quotes/products-fields) | ## Пример ответа Показаны основные поля. Полный список — [Поля товаров](/docs/entities/quotes/products-fields). ```json { "success": true, "data": { "id": 1465, "productId": 1, "productName": "Серверное оборудование", "price": 25000, "quantity": 2, "discount": 0, "discountTypeId": 2, "taxIncluded": false } } ``` ## Пример ответа при ошибке 404 — предложение не найдено: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Тело содержит имя, которого нет среди записываемых полей — см. [Поля товаров](/docs/entities/quotes/products-fields) | | 404 | `ENTITY_NOT_FOUND` | Предложение не найдено | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Товарные позиции](/docs/entities/quotes/products-get) - [Установить товары](/docs/entities/quotes/products-set) - [Удалить товар](/docs/entities/quotes/products-delete) - [Товары каталога](/docs/entities/products) --- # Quotes: Products Delete ## Удалить товар из предложения `DELETE /v1/quotes/:id/products/:rowId` Удаляет одну товарную позицию из предложения по ID строки. Восстановить удалённую позицию через API нельзя — добавляйте новую при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID предложения | | `rowId` (path) | number | да | ID товарной строки (из ответа add или list) | `rowId` — это ID товарной строки, а не `productId` из каталога товаров. ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/quotes/52/products/1465" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/quotes/52/products/1465" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/52/products/1465', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Товар удалён из предложения') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/52/products/1465', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — предложение не найдено: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Предложение или товарная строка не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Товарные позиции](/docs/entities/quotes/products-get) - [Добавить товар](/docs/entities/quotes/products-add) - [Установить товары](/docs/entities/quotes/products-set) - [Товары каталога](/docs/entities/products) --- # Quotes: Products Fields ## Поля товаров предложения `GET /v1/quotes/:id/products/fields` Возвращает описание полей товарных позиций предложения: названия, типы, доступность для чтения и записи. > **Сумма скидки называется `discount`** — как в данных и при записи. Прежнее имя `discountSum` осталось устаревшим псевдонимом: оно по-прежнему приходит в этом справочнике и принимается при записи, поэтому код, написанный по старому списку полей, продолжает работать. В самих товарных позициях приходит только `discount` — переходите на него. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID предложения | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/quotes/741/products/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/quotes/741/products/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/741/products/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/741/products/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | RO | Обяз. | Описание | |------|-----|:--:|:-----:|---------| | `id` | integer | да | | ID позиции | | `productId` | integer | | да | ID товара. Каталог: `GET /v1/products` | | `productName` | string | | | Название товара | | `price` | double | | | Цена | | `quantity` | double | | | Количество | | `discount` | double | | | Сумма скидки | | `discountSum` | double | | | Устаревший псевдоним `discount` — принимается при записи, в товарных позициях не приходит | | `discountRate` | double | | | Величина скидки (%) | | `discountTypeId` | integer | | | Тип скидки | | `taxRate` | double | | | Налог (%) | | `taxIncluded` | char | | | Налог включён в цену (`Y`/`N`) | | `priceExclusive` | double | да | | Цена без налога со скидкой | | `priceNetto` | double | да | | Цена нетто | | `priceBrutto` | double | да | | Цена брутто | | `measureCode` | integer | | | Код единицы измерения | | `measureName` | string | да | | Единица измерения | | `customized` | char | да | | Изменён (`Y`/`N`) | | `sort` | integer | | | Сортировка | | `type` | integer | да | | Тип | | `storeId` | integer | да | | ID склада | | `ownerId` | integer | да | | ID владельца (предложения) | | `ownerType` | string | да | | Тип владельца | | `priceAccount` | double | да | | Цена в валюте отчёта | | `xmlId` | string | да | | Внешний код позиции | ## Пример ответа ```json { "success": true, "data": { "id": { "type": "integer", "isRequired": false, "isReadOnly": true, "title": "ID", "description": "Row identity. Read-only as an attribute; echo it back in PUT /products items to update a row in place instead of recreating it." }, "ownerId": { "type": "integer", "isRequired": false, "isReadOnly": true, "isImmutable": true, "title": "ID владельца" }, "ownerType": { "type": "string", "isRequired": false, "isReadOnly": true, "isImmutable": true, "title": "Тип владельца" }, "productId": { "type": "integer", "isRequired": true, "isReadOnly": false, "title": "Товар" }, "productName": { "type": "string", "isRequired": false, "isReadOnly": false, "title": "Название товара" }, "price": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Цена" }, "priceExclusive": { "type": "double", "isRequired": false, "isReadOnly": true, "title": "Цена без налога со скидкой" }, "priceNetto": { "type": "double", "isRequired": false, "isReadOnly": true, "title": "PRICE_NETTO" }, "priceBrutto": { "type": "double", "isRequired": false, "isReadOnly": true, "title": "PRICE_BRUTTO" }, "quantity": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Количество" }, "discountTypeId": { "type": "integer", "isRequired": false, "isReadOnly": false, "title": "Тип скидки" }, "discountRate": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Величина скидки" }, "discount": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Сумма скидки" }, "discountSum": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Сумма скидки", "description": "Deprecated alias of `discount`; kept so clients written against the previous field list keep working. Accepted on write, never present in row data — migrate to `discount`." }, "taxRate": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Налог" }, "taxIncluded": { "type": "char", "isRequired": false, "isReadOnly": false, "title": "Налог включен в цену" }, "customized": { "type": "char", "isRequired": false, "isReadOnly": true, "title": "Изменен" }, "measureCode": { "type": "integer", "isRequired": false, "isReadOnly": false, "title": "Код единицы измерения" }, "measureName": { "type": "string", "isRequired": false, "isReadOnly": true, "title": "Единица измерения" }, "sort": { "type": "integer", "isRequired": false, "isReadOnly": false, "title": "Сортировка" }, "type": { "type": "integer", "isRequired": false, "isReadOnly": true, "title": "TYPE" }, "storeId": { "type": "integer", "isRequired": false, "isReadOnly": true, "title": "STORE_ID" }, "priceAccount": { "type": "double", "isRequired": false, "isReadOnly": true }, "xmlId": { "type": "string", "isRequired": false, "isReadOnly": true } } } ``` ## Пример ответа при ошибке 404 — предложение не найдено: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Предложение не найдено | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Товарные позиции](/docs/entities/quotes/products-get) - [Добавить товар](/docs/entities/quotes/products-add) - [Установить товары](/docs/entities/quotes/products-set) - [Поля предложения](/docs/entities/quotes/fields) --- # Quotes: Products Get ## Товарные позиции предложения `GET /v1/quotes/:id/products` Возвращает список товарных позиций, привязанных к предложению. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID предложения | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/quotes/741/products" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/quotes/741/products" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/741/products', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Товаров:', data.length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/741/products', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив товарных позиций | | `data[].productId` | number | ID товара. Каталог: `GET /v1/products` | | `data[].productName` | string | Название товара | | `data[].price` | number | Цена за единицу | | `data[].quantity` | number | Количество | | `data[].discount` | number | Сумма скидки | | `data[].taxRate` | number/null | Ставка налога (%) | | `data[].taxIncluded` | boolean | Налог включён в цену | Показаны основные поля. Полный список (23 поля, включая priceAccount, measureCode и др.): [Поля товаров](/docs/entities/quotes/products-fields). ## Пример ответа ```json { "success": true, "data": [ { "productId": 1, "productName": "Серверное оборудование", "price": 1000, "quantity": 2, "discount": 0, "taxRate": null, "taxIncluded": false } ] } ``` ## Пример ответа при ошибке 404 — предложение не найдено: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Предложение не найдено | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Установить товары](/docs/entities/quotes/products-set) - [Получить предложение](/docs/entities/quotes/get) - [Товары каталога](/docs/entities/products) - [Лимиты и оптимизация](/docs/optimization) --- # Quotes: Products Get Single ## Получить товар из предложения `GET /v1/quotes/:id/products/:rowId` Возвращает одну товарную позицию предложения по ID строки. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID предложения | | `rowId` (path) | number | да | ID товарной строки (из ответа add или list) | `rowId` — это ID товарной строки, а не `productId` из каталога товаров. ## Примеры ### curl — личный ключ ```bash curl -X GET "https://vibecode.bitrix24.tech/v1/quotes/741/products/1471" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X GET "https://vibecode.bitrix24.tech/v1/quotes/741/products/1471" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/741/products/1471', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Цена:', data.price) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/741/products/1471', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.id` | number | ID товарной строки | | `data.productId` | number | ID товара из каталога | | `data.productName` | string | Название товара | | `data.price` | number | Цена за единицу | | `data.quantity` | number | Количество | | `data.discount` | number | Сумма скидки | | `data.discountRate` | number | Процент скидки | | `data.discountTypeId` | number | Тип скидки (1 — сумма, 2 — процент) | | `data.taxRate` | number \| null | Ставка налога (%) | | `data.taxIncluded` | boolean | Налог включён в цену | | `data.priceExclusive` | number | Цена без скидки | | `data.priceNetto` | number | Цена нетто | | `data.priceBrutto` | number | Цена брутто | | `data.priceAccount` | number | Цена в валюте учёта | | `data.measureCode` | number | Код единицы измерения | | `data.measureName` | string | Название единицы измерения | | `data.sort` | number | Сортировка | | `data.ownerId` | number | ID сущности-владельца, которой принадлежит позиция | | `data.ownerType` | string | Код типа владельца (`D` у сделок, `T` у смарт-процессов) | | `data.storeId` | number \| null | ID склада; `null`, если складской учёт выключен | ## Пример ответа ```json { "success": true, "data": { "id": 1471, "productId": 1, "productName": "День добрый!", "price": 5000, "priceAccount": 5000, "priceExclusive": 5000, "priceNetto": 5000, "priceBrutto": 5000, "quantity": 3, "discountTypeId": 2, "discountRate": 0, "discount": 0, "taxRate": null, "taxIncluded": false, "customized": "Y", "measureCode": 796, "measureName": "шт", "sort": 0, "ownerId": 741, "ownerType": "D", "storeId": 3, "xmlId": "sale_basket_995", "type": 1 } } ``` ## Пример ответа при ошибке 404 — предложение или товарная строка не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Предложение или товарная строка не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Товарные позиции](/docs/entities/quotes/products-get) - [Обновить товар](/docs/entities/quotes/products-update) - [Добавить товар](/docs/entities/quotes/products-add) - [Удалить товар](/docs/entities/quotes/products-delete) - [Товары каталога](/docs/entities/products) --- # Quotes: Products Set > Поле, которого нет среди записываемых, больше не отбрасывается молча — запрос отклоняется с `400 INVALID_PARAMS`, и в тексте ошибки перечислены записываемые имена. Поля только для чтения, которые приходят в ответах товарных позиций (`priceAccount`, `ownerId`, `storeId` и другие) по-прежнему принимаются и игнорируются, поэтому объект, прочитанный через GET, можно отправить обратно без чистки. > Сохраняйте `id` у элемента, чтобы обновить существующую строку на месте: без него строка будет создана заново с новым идентификатором. ## Установить товары предложения `PUT /v1/quotes/:id/products` Устанавливает товарные позиции коммерческого предложения. Полностью заменяет текущий список — передайте все нужные позиции. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `items` | array | да | Массив товарных позиций | | `items[].productId` | number | да | ID товара. Каталог: `GET /v1/products` | | `items[].price` | number | да | Цена за единицу | | `items[].quantity` | number | да | Количество | | `items[].discount` | number | нет | Сумма скидки | | `items[].taxRate` | number | нет | Ставка налога (%) | | `items[].taxIncluded` | boolean | нет | Налог включён в цену | ## Примеры ### curl — личный ключ ```bash curl -X PUT "https://vibecode.bitrix24.tech/v1/quotes/412/products" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "items": [ { "productId": 1, "price": 75000, "quantity": 2 }, { "productId": 5, "price": 10000, "quantity": 1, "discount": 1000 } ] }' ``` ### curl — OAuth-приложение ```bash curl -X PUT "https://vibecode.bitrix24.tech/v1/quotes/412/products" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "items": [ { "productId": 1, "price": 75000, "quantity": 2 }, { "productId": 5, "price": 10000, "quantity": 1, "discount": 1000 } ] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/412/products', { method: 'PUT', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ items: [ { productId: 1, price: 75000, quantity: 2 }, { productId: 5, price: 10000, quantity: 1, discount: 1000 }, ], }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/412/products', { method: 'PUT', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ items: [ { productId: 1, price: 75000, quantity: 2 }, { productId: 5, price: 10000, quantity: 1, discount: 1000 }, ], }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив установленных позиций с полями productId, productName, price, quantity, discount, taxRate, taxIncluded | Массив установленных позиций с полями `productId`, `productName`, `price`, `quantity`, `discount`, `taxRate`, `taxIncluded`. ## Пример ответа ```json { "success": true, "data": [ { "productId": 1, "productName": "Серверное оборудование", "price": 75000, "quantity": 2, "discount": 0, "taxRate": null, "taxIncluded": false }, { "productId": 5, "productName": "Установка и настройка", "price": 10000, "quantity": 1, "discount": 1000, "taxRate": null, "taxIncluded": false } ] } ``` ## Пример ответа при ошибке 400 — неверный формат: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "items must be an array" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Тело содержит имя, которого нет среди записываемых полей — см. [Поля товаров](/docs/entities/quotes/products-fields) | | 400 | `INVALID_PARAMS` | `items` не является массивом | | 404 | `ENTITY_NOT_FOUND` | Предложение не найдено | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Полная замена:** PUT заменяет весь список товаров. Чтобы добавить позицию — сначала получите текущие (`GET`), добавьте новую в массив, отправьте всё (`PUT`). ## Смотрите также - [Товарные позиции](/docs/entities/quotes/products-get) - [Получить предложение](/docs/entities/quotes/get) - [Товары каталога](/docs/entities/products) - [Лимиты и оптимизация](/docs/optimization) --- # Quotes: Products Update > Поле, которого нет среди записываемых, больше не отбрасывается молча — запрос отклоняется с `400 INVALID_PARAMS`, и в тексте ошибки перечислены записываемые имена. Поля только для чтения, которые приходят в ответах товарных позиций (`priceAccount`, `ownerId`, `storeId` и другие) по-прежнему принимаются и игнорируются, поэтому объект, прочитанный через GET, можно отправить обратно без чистки. ## Обновить товар предложения `PATCH /v1/quotes/:id/products/:rowId` Обновляет товарную позицию предложения. Передайте только изменяемые поля. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID предложения | | `rowId` (path) | number | да | ID товарной позиции (из ответа list или add, не productId из каталога) | ## Поля запроса (body) | Параметр | Тип | Описание | |----------|-----|---------| | `price` | number | Цена за единицу | | `quantity` | number | Количество | | `productId` | number | ID товара. Каталог: `GET /v1/products` | | `discount` | number | Сумма скидки | | `taxRate` | number | Ставка налога (%) | | `taxIncluded` | boolean | Налог включён в цену | | `sort` | number | Сортировка | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/quotes/741/products/1471" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "price": 9999, "quantity": 10 }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/quotes/741/products/1471" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "price": 9999, "quantity": 10 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/741/products/1471', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ price: 9999, quantity: 10 }), }) const { success, data } = await res.json() console.log('Обновлено:', data.price, 'x', data.quantity) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/741/products/1471', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ price: 9999, quantity: 10 }), }) const { success, data } = await res.json() ``` ## Поля ответа Обновлённый объект товарной позиции: `id`, `productId`, `productName`, `price`, `quantity`, `discount`, `taxRate`, `taxIncluded`. ## Пример ответа ```json { "success": true, "data": { "id": 1471, "productId": 1, "productName": "Серверное оборудование", "price": 9999, "quantity": 10, "discount": 0, "taxRate": null, "taxIncluded": false } } ``` ## Пример ответа при ошибке 404 — позиция не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Тело содержит имя, которого нет среди записываемых полей — см. [Поля товаров](/docs/entities/quotes/products-fields) | | 404 | `ENTITY_NOT_FOUND` | Позиция не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить товар](/docs/entities/quotes/products-get-single) - [Получить товары](/docs/entities/quotes/products-get) - [Добавить товар](/docs/entities/quotes/products-add) - [Лимиты и оптимизация](/docs/optimization) --- # Quotes: Search ## Поиск предложений `POST /v1/quotes/search` Поиск коммерческих предложений с фильтрами и авто-пагинацией. Аналогичен `GET /v1/quotes` с фильтрами, но через POST — удобнее для сложных запросов с большим количеством условий. ## Поля запроса (body) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям `GET /v1/quotes/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[stageId]=DRAFT` | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки» | | `order` | object | — | Сортировка: `{ "createdTime": "desc" }` | | `select` | string[] | — | Выборка полей: `["id", "title", "amount"]` | | `autoWindow` | boolean | `true` | Разбивать выборку по недельным окнам при фильтре по диапазону дат шире 14 дней. `false` отключает разбиение | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/quotes/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "stageId": "DRAFT" }, "limit": 10, "order": { "amount": "desc" } }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/quotes/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "stageId": "DRAFT" }, "limit": 10, "order": { "amount": "desc" } }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { stageId: 'DRAFT' }, limit: 10, order: { amount: 'desc' }, }), }) const { success, data } = await res.json() console.log('Найдено:', data.length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { stageId: 'DRAFT' }, limit: 10, order: { amount: 'desc' }, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив предложений (все поля — см. [Поля](/docs/entities/quotes/fields)) | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.nextAfterId` | string | Идентификатор последней отданной записи. Приходит при сортировке строго по `id` по возрастанию, пока `hasMore` равен `true`. Передайте его обратно в фильтр `>id` — это дешёвая замена растущему `offset` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временны́м окнам | | `meta.windowCount` | number | Число окон. Приходит при `autoWindowed: true` | | `meta.batchWaves` | number | Число волн параллельных запросов. Приходит при `autoWindowed: true` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. URL карточки любого предложения из массива `data` — его `id`: ``` https://.bitrix24.ru/crm/type/7/details// ``` `7` — `entityTypeId` коммерческого предложения в Битрикс24. `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 412, "title": "КП на серверное оборудование", "amount": 150000, "currency": "RUB", "stageId": "DRAFT", "dealId": 741, "assignedById": 29, "createdTime": "2026-04-15T10:30:00.000Z" } ], "meta": { "total": 23, "hasMore": true, "durationMs": 247 } } ``` С фильтром по диапазону дат шире 14 дней в `meta` дополнительно приходят `autoWindowed`, `windowCount` и `batchWaves`: ```json { "success": true, "data": [ /* ... */ ], "meta": { "total": 35, "hasMore": true, "autoWindowed": true, "windowCount": 339, "batchWaves": 7, "durationMs": 9492 } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Разбиение по временны́м окнам.** Фильтр по диапазону дат шире 14 дней автоматически разбивается на недельные окна, которые выполняются параллельными волнами — так выборка обходит потолок в 5000 записей на один вызов. В `meta` тогда приходят `autoWindowed: true`, число окон `windowCount` и число волн `batchWaves`. Отключает разбиение параметр `autoWindow: false`. При активном разбиении `offset` больше нуля отклоняется с `UNSTABLE_OFFSET_PAGINATION`. ## Смотрите также - [Список предложений](/docs/entities/quotes/list) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Quotes: Update ## Обновить предложение `PATCH /v1/quotes/:id` Обновляет поля существующего коммерческого предложения. Передайте только изменяемые поля. Полный список в [справочнике полей](/docs/entities/quotes/fields), включая пользовательские (`ufCrm_*`). ## Часто обновляемые поля | Параметр | Тип | Описание | |----------|-----|---------| | `stageId` | string | Статус: `DRAFT`, `SENT`, `APPROVED`. Список: `GET /v1/statuses?filter[entityId]=QUOTE_STATUS` | | `opportunity` | number | Сумма предложения. Передавайте вместе с `isManualOpportunity: true`, иначе Битрикс24 пересчитает сумму из товарных позиций (флаг хранится как `Y`/`N`, булево преобразуется автоматически) | | `assignedById` | number | Ответственный. Список: `GET /v1/users` | | `title` | string | Название | | `closedate` | datetime | Дата закрытия | > **Имена полей.** В ответе поля возвращаются в camelCase: `amount`, `currency`, `beginDate`, `closeDate`. На запись принимаются оба варианта — и эти camelCase-имена, и B24-native `opportunity` / `currencyId` / `begindate` / `closedate`: слой API приводит их к нужному имени Битрикс24. ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/quotes/412" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "stageId": "APPROVED", "isManualOpportunity": true, "opportunity": 145000 }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/quotes/412" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "stageId": "APPROVED", "isManualOpportunity": true, "opportunity": 145000 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/412', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ stageId: 'APPROVED', isManualOpportunity: true, opportunity: 145000, }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/quotes/412', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ stageId: 'APPROVED', isManualOpportunity: true, opportunity: 145000, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | object | Обновлённый объект предложения со всеми полями — см. [Поля](/docs/entities/quotes/fields) | Обновлённый объект предложения со всеми полями — см. [Поля предложения](/docs/entities/quotes/fields). ## Пример ответа ```json { "success": true, "data": { "id": 412, "title": "КП на серверное оборудование", "amount": 145000, "currency": "RUB", "stageId": "APPROVED", "dealId": 741, "assignedById": 1, "updatedTime": "2026-04-15T15:10:00.000Z" } } ``` ## Пример ответа при ошибке 404 — предложение не найдено: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Предложение не найдено | | 403 | `ACCESS_DENIED` | Нет доступа к предложению | | 400 | `INVALID_REQUEST` | Некорректные поля | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Работа с файлами в полях CRM](/docs/recipes/crm-files) - [Получить предложение](/docs/entities/quotes/get) - [Поля предложения](/docs/entities/quotes/fields) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Requisite Links: Fields ## Поля связи реквизита `GET /v1/requisite-links/fields` Возвращает схему связи реквизита — описание, типы и флаги для всех шести полей. Здесь же справочник значений `entityTypeId` — типов сущности, к которой привязывают реквизит. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/requisite-links/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/requisite-links/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-links/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() console.log('Поля:', Object.keys(data.fields)) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-links/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | RO | Описание | |------|-----|:--:|---------| | `success` | boolean | RO | Всегда `true` при успехе | | `data.fields` | object | RO | Схема связи. Ключи — имена полей в camelCase | | `data.fields.entityTypeId` | object | RO | Тип сущности-владельца. Значения — в справочнике ниже | | `data.fields.entityId` | object | RO | ID сущности-владельца | | `data.fields.requisiteId` | object | RO | ID реквизита клиента, `0` — не привязан | | `data.fields.bankDetailId` | object | RO | ID банковского реквизита клиента, `0` — не привязан | | `data.fields.mcRequisiteId` | object | RO | ID реквизита вашей компании, `0` — не привязан | | `data.fields.mcBankDetailId` | object | RO | ID банковского реквизита вашей компании, `0` — не привязан | Каждый объект-поле содержит `type`, `isRequired`, `isReadOnly`, `isImmutable`, `isMultiple`, `isDynamic` и `title`. ### Справочник типов владельца Значение `entityTypeId` определяет, к какой сущности привязывается реквизит. Одно и то же значение используется в пути, в теле регистрации и в фильтре списка. | `entityTypeId` | Владелец | Где взять `entityId` | |---------------|----------|---------------------| | `2` | Сделка | [`GET /v1/deals`](/docs/entities/deals/list) | | `5` | Счёт старого образца | Отдельного эндпоинта в API Вайбкод нет | | `7` | Предложение | [`GET /v1/quotes`](/docs/entities/quotes/list) | | `31` | Счёт | [`GET /v1/invoices`](/docs/entities/invoices/list) | | Код смарт-процесса | Элемент смарт-процесса | [`GET /v1/items/:entityTypeId`](/docs/entities/items/list) | Коды смарт-процессов различаются от портала к порталу. Действующие коды возвращает [`GET /v1/smart-processes`](/docs/entities/smart-processes/list) — поле `entityTypeId` каждого смарт-процесса. ## Пример ответа ```json { "success": true, "data": { "fields": { "entityTypeId": { "type": "integer", "isRequired": true, "isReadOnly": false, "isImmutable": true, "isMultiple": false, "isDynamic": false, "title": "ID типа сущности" }, "entityId": { "type": "integer", "isRequired": true, "isReadOnly": false, "isImmutable": true, "isMultiple": false, "isDynamic": false, "title": "ID сущности" }, "requisiteId": { "type": "integer", "isRequired": true, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Привязка к реквизитам" }, "bankDetailId": { "type": "integer", "isRequired": true, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Привязка к банковским реквизитам" }, "mcRequisiteId": { "type": "integer", "isRequired": true, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Привязка к реквизитам моей компании" }, "mcBankDetailId": { "type": "integer", "isRequired": true, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Привязка к банковским реквизитам моей компании" } } } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`isRequired: true` относится к ключу, а не к самой привязке.** Флаг означает, что при регистрации связи ключ обязан присутствовать в теле запроса. Значение `0` при этом допустимо и сохраняется: связь, у которой все четыре привязки равны `0`, регистрируется и возвращает `201`. **Схема одна на все типы владельцев.** Набор полей не зависит от `entityTypeId` — у сделки, счёта и элемента смарт-процесса он одинаковый. ## Смотрите также - [Зарегистрировать связь](/docs/entities/requisite-links/register) - [Список связей](/docs/entities/requisite-links/list) - [Entity API](/docs/entity-api) --- # Requisite Links: Get ## Получить связь реквизитов `GET /v1/requisite-links/:entityTypeId/:entityId` Возвращает конкретную связь реквизитов по паре идентификаторов владельца. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `entityTypeId` (path) | number | да | Тип владельца связи. Значения — [Поля связи](/docs/entities/requisite-links/fields) | | `entityId` (path) | number | да | ID владельца. Источник зависит от типа — см. тот же справочник | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/requisite-links/2/3773" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/requisite-links/2/3773" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const entityTypeId = 2 const entityId = 3773 const res = await fetch( `https://vibecode.bitrix24.tech/v1/requisite-links/${entityTypeId}/${entityId}`, { headers: { 'X-Api-Key': 'YOUR_API_KEY' } }, ) const { success, data } = await res.json() console.log('Реквизит клиента:', data.requisiteId) ``` ### JavaScript — OAuth-приложение ```javascript const entityTypeId = 2 const entityId = 3773 const res = await fetch( `https://vibecode.bitrix24.tech/v1/requisite-links/${entityTypeId}/${entityId}`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }, ) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект связи | | `data.entityTypeId` | number | Тип владельца. Значения — [Поля связи](/docs/entities/requisite-links/fields) | | `data.entityId` | number | ID владельца | | `data.requisiteId` | number | ID привязанного реквизита клиента, `0` — не привязан. Источник: [`GET /v1/requisites`](/docs/entities/requisites/list) | | `data.bankDetailId` | number | ID привязанного банковского реквизита клиента, `0` — не привязан. Источник: [`GET /v1/bank-details`](/docs/entities/bank-details/list) | | `data.mcRequisiteId` | number | ID реквизита вашей компании, `0` — не привязан | | `data.mcBankDetailId` | number | ID банковского реквизита вашей компании, `0` — не привязан | ## Пример ответа ```json { "success": true, "data": { "entityTypeId": 2, "entityId": 3773, "requisiteId": 45, "bankDetailId": 0, "mcRequisiteId": 0, "mcBankDetailId": 0 } } ``` ## Пример ответа при ошибке 404 — связи для этой пары нет: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Битрикс24 вернул ошибку «не найдено»: связи для пары `entityTypeId` и `entityId` нет, либо самой сущности-владельца не существует | | 404 | `NOT_FOUND` | Битрикс24 вернул пустой результат вместо ошибки — связи для этой пары нет | | 400 | `INVALID_ANCHOR` | `entityTypeId` или `entityId` в пути не положительное целое число | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **У связи нет отдельного числового `id`.** Она определяется парой значений владельца — `entityTypeId` и `entityId`, оба передаются в пути. **Отсутствие связи и отсутствие привязок — разные состояния.** Если связь не заводили, ответ `404`. Если связь заведена, но ни один реквизит к ней не привязан, ответ `200`, а все четыре идентификатора равны `0`. ## Смотрите также - [Список связей](/docs/entities/requisite-links/list) - [Зарегистрировать связь](/docs/entities/requisite-links/register) - [Обновить связь](/docs/entities/requisite-links/update) - [Удалить связь](/docs/entities/requisite-links/unregister) - [Поля связи](/docs/entities/requisite-links/fields) --- # Requisite Links: List ## Список связей реквизитов `GET /v1/requisite-links` Возвращает список связей реквизитов с поддержкой фильтрации и авто-пагинации. Каждая связь соединяет реквизит и банковский реквизит с конкретным владельцем — сделкой, счётом, предложением или элементом смарт-процесса. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей, до 5000 | | `offset` | number | `0` | Пропустить N записей. При `offset > 0` рекомендуется `limit ≤ 500` | | `filter` | object | — | Фильтрация по полям. Допустимые ключи: `entityTypeId`, `entityId`, `requisiteId`, `bankDetailId`, `mcRequisiteId`, `mcBankDetailId`. Поддерживаются операторы сравнения (`$gt`/`$gte`/`$lt`/`$lte` и префиксы `>=`/`>`), множества (`$in`/`$nin`). Логические `$or`/`$and` не поддерживаются.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[entityTypeId]=2&filter[entityId]=3773` | | `sort` | string | — | Поле сортировки — один из ключей фильтра. Направление задаётся в `order` | | `order` | string \| object | `asc` | Направление для `sort` (`asc`/`desc`), либо форма `order[поле]=asc\|desc` | Пагинация: при `limit > 50` все записи приходят в одном ответе. Максимум — 5000 записей за вызов. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/requisite-links?filter[entityTypeId]=2&filter[entityId]=3773" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/requisite-links?filter[entityTypeId]=2&filter[entityId]=3773" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/requisite-links?filter[entityTypeId]=2&filter[entityId]=3773', { headers: { 'X-Api-Key': 'YOUR_API_KEY' } }, ) const { success, data, meta } = await res.json() console.log('Найдено связей:', meta.total) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/requisite-links?filter[entityTypeId]=2&filter[entityId]=3773', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }, ) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив связей | | `data[].entityTypeId` | number | Тип владельца. Значения — [Поля связи](/docs/entities/requisite-links/fields) | | `data[].entityId` | number | ID владельца | | `data[].requisiteId` | number | ID реквизита клиента, `0` — не привязан. Источник: [`GET /v1/requisites`](/docs/entities/requisites/list) | | `data[].bankDetailId` | number | ID банковского реквизита клиента, `0` — не привязан. Источник: [`GET /v1/bank-details`](/docs/entities/bank-details/list) | | `data[].mcRequisiteId` | number | ID реквизита вашей компании, `0` — не привязан | | `data[].mcBankDetailId` | number | ID банковского реквизита вашей компании, `0` — не привязан | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа ```json { "success": true, "data": [ { "entityTypeId": 2, "entityId": 3773, "requisiteId": 45, "bankDetailId": 0, "mcRequisiteId": 0, "mcBankDetailId": 0 }, { "entityTypeId": 2, "entityId": 3825, "requisiteId": 0, "bankDetailId": 0, "mcRequisiteId": 0, "mcBankDetailId": 0 } ], "meta": { "total": 68, "hasMore": true } } ``` ## Пример ответа при ошибке 400 — фильтр по `entityId` без `entityTypeId`: ```json { "success": false, "error": { "code": "MISSING_ENTITY_TYPE_ID", "message": "Filtering by entityId requires entityTypeId too — B24 scopes requisite-link access by owner type. Add entityTypeId (e.g. 4 company, 3 contact) to the filter." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_ENTITY_TYPE_ID` | Фильтр по `entityId` без `entityTypeId` | | 400 | `UNKNOWN_FILTER_FIELD` | Неизвестное поле фильтра, в сообщении — список допустимых | | 400 | `UNKNOWN_SORT_FIELD` | Неизвестное поле сортировки, в сообщении — список допустимых | | 400 | `INVALID_FILTER_OPERATOR` | Логический оператор верхнего уровня `$or` или `$and` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **У связи нет отдельного числового `id`.** Каждая связь определяется парой значений владельца — `entityTypeId` и `entityId`, именно они используются для получения и удаления записи. **Связь в списке не означает наличия привязки.** Строка со всеми четырьмя идентификаторами, равными `0`, — это заведённая связь без единой привязки. Чтобы отобрать только реальные привязки, добавьте условие вида `?filter[>requisiteId]=0`. ## Смотрите также - [Получить связь](/docs/entities/requisite-links/get) - [Поиск связей](/docs/entities/requisite-links/search) - [Зарегистрировать связь](/docs/entities/requisite-links/register) - [Поля связи](/docs/entities/requisite-links/fields) - [Реквизиты](/docs/entities/requisites/list) - [Банковские реквизиты](/docs/entities/bank-details/list) - [Синтаксис фильтрации](/docs/filtering) --- # Requisite Links: Register ## Зарегистрировать связь реквизита `POST /v1/requisite-links` Создаёт или обновляет привязку реквизита к сущности-владельцу. Если связь для указанной пары `entityTypeId` и `entityId` уже существует, она перезаписывается целиком. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `entityTypeId` | number | да | Тип владельца связи. Значения — [Поля связи](/docs/entities/requisite-links/fields) | | `entityId` | number | да | ID сущности-владельца. Источник зависит от типа — см. тот же справочник | | `requisiteId` | number | да | ID реквизита клиента. Источник: [`GET /v1/requisites`](/docs/entities/requisites/list). Передайте `0`, чтобы не привязывать | | `bankDetailId` | number | да | ID банковского реквизита клиента. Источник: [`GET /v1/bank-details`](/docs/entities/bank-details/list). Передайте `0`, чтобы не привязывать | | `mcRequisiteId` | number | да | ID реквизита вашей компании. Источник: [`GET /v1/requisites`](/docs/entities/requisites/list). Передайте `0`, чтобы не привязывать | | `mcBankDetailId` | number | да | ID банковского реквизита вашей компании. Источник: [`GET /v1/bank-details`](/docs/entities/bank-details/list). Передайте `0`, чтобы не привязывать | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/requisite-links" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "entityTypeId": 2, "entityId": 3773, "requisiteId": 45, "bankDetailId": 12, "mcRequisiteId": 3, "mcBankDetailId": 7 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/requisite-links" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "entityTypeId": 2, "entityId": 3773, "requisiteId": 45, "bankDetailId": 12, "mcRequisiteId": 3, "mcBankDetailId": 7 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-links', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ entityTypeId: 2, entityId: 3773, requisiteId: 45, bankDetailId: 12, mcRequisiteId: 3, mcBankDetailId: 7, }), }) const { success, data } = await res.json() console.log('Зарегистрирована связь для entityId:', data.entityId) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-links', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ entityTypeId: 2, entityId: 3773, requisiteId: 45, bankDetailId: 12, mcRequisiteId: 3, mcBankDetailId: 7, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Результат регистрации | | `data.entityTypeId` | number | Переданный тип сущности | | `data.entityId` | number | Переданный ID сущности | | `data.registered` | boolean | Всегда `true` при успехе | Сами привязки в ответе не возвращаются. Чтобы увидеть сохранённые значения, прочитайте связь через [`GET /v1/requisite-links/:entityTypeId/:entityId`](/docs/entities/requisite-links/get). ## Пример ответа HTTP-статус: `201 Created` ```json { "success": true, "data": { "entityTypeId": 2, "entityId": 3773, "registered": true } } ``` ## Пример ответа при ошибке 400 — переданы не все шесть полей: ```json { "success": false, "error": { "code": "MISSING_FIELDS", "message": "POST /v1/requisite-links requires entityTypeId, entityId, requisiteId, bankDetailId, mcRequisiteId and mcBankDetailId in the body (use 0 for ids you don't want to link). Missing: requisiteId, bankDetailId, mcRequisiteId, mcBankDetailId. Raw UPPER_SNAKE names are accepted too: ENTITY_TYPE_ID, ENTITY_ID, REQUISITE_ID, BANK_DETAIL_ID, MC_REQUISITE_ID, MC_BANK_DETAIL_ID." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_FIELDS` | Не переданы один или несколько из шести обязательных полей | | 400 | `INVALID_REQUEST` | Тело запроса не является объектом | | 404 | `ENTITY_NOT_FOUND` | Реквизита или банковского реквизита с указанным ID не существует | | 422 | `BITRIX_ERROR` | Привязка отклонена — например, реквизит нельзя привязать к сделке, у которой не выбран клиент | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`0` — это «не привязывать», а не ссылка на объект с нулевым ID.** Все шесть полей обязаны присутствовать в теле, но значение `0` в любом из четырёх идентификаторов означает пустую привязку. Связь, у которой все четыре равны `0`, регистрируется и возвращает `201`. **Регистрация перезаписывает связь целиком.** Повторный вызов заменяет весь набор из четырёх привязок значениями из тела запроса: там, где передан `0`, привязка снимается. Чтобы изменить одну привязку и сохранить остальные, используйте [`PATCH /v1/requisite-links/:entityTypeId/:entityId`](/docs/entities/requisite-links/update). **Реквизит клиента должен принадлежать клиенту сделки.** Чтобы привязать `requisiteId` к сделке, у неё должен быть выбран контакт или компания — владелец этого реквизита. Реквизиты вашей компании — `mcRequisiteId` и `mcBankDetailId` — от клиента сделки не зависят. **При отказе прежняя связь остаётся нетронутой.** Если хотя бы один идентификатор не прошёл проверку, не применяется ни одно из значений запроса. ## Смотрите также - [Поля связи](/docs/entities/requisite-links/fields) - [Обновить связь](/docs/entities/requisite-links/update) - [Удалить связь](/docs/entities/requisite-links/unregister) - [Список связей](/docs/entities/requisite-links/list) - [Реквизиты](/docs/entities/requisites) - [Банковские реквизиты](/docs/entities/bank-details) - [Batch](/docs/batch) --- # Requisite Links: Search ## Поиск связей реквизитов `POST /v1/requisite-links/search` Поиск связей реквизитов с фильтрами и авто-пагинацией. Аналогичен `GET /v1/requisite-links`, но параметры передаются в теле запроса — удобнее для сложных фильтров с большим количеством условий и для программной сборки запросов. ## Поля запроса (body) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Фильтрация. Допустимые ключи: `entityTypeId`, `entityId`, `requisiteId`, `bankDetailId`, `mcRequisiteId`, `mcBankDetailId`. Поддерживаются операторы сравнения (`$gt`/`$gte`/`$lt`/`$lte`), множества (`$in`/`$nin`). Логические `$or`/`$and` не поддерживаются.
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "entityTypeId": 2, "entityId": 3773 }` | | `sort` | string | — | Поле сортировки — один из ключей фильтра | | `order` | string \| object | `asc` | Направление для `sort` (`asc`/`desc`), либо форма `{ "поле": "asc\|desc" }` | | `limit` | number | `50` | Количество записей, до 5000 | | `offset` | number | `0` | Пропустить N записей | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/requisite-links/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "entityTypeId": 2, "requisiteId": 45 }, "limit": 20 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/requisite-links/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "entityTypeId": 2, "requisiteId": 45 }, "limit": 20 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-links/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { entityTypeId: 2, requisiteId: 45 }, limit: 20, }), }) const { success, data } = await res.json() console.log('Найдено:', data.length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-links/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { entityTypeId: 2, requisiteId: 45 }, limit: 20, }), }) const { success, data } = await res.json() ``` ### Другие сценарии Блоки ниже — тела запросов. Все связи по конкретной сделке: ```json { "filter": { "entityTypeId": 2, "entityId": 3773 } } ``` Все связи по конкретному реквизиту — к каким сущностям привязан реквизит с ID 45: ```json { "filter": { "requisiteId": 45 } } ``` Только сделки, у которых реквизит клиента действительно привязан: ```json { "filter": { "entityTypeId": 2, "requisiteId": { "$gt": 0 } }, "limit": 100 } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив связей | | `data[].entityTypeId` | number | Тип владельца. Значения — [Поля связи](/docs/entities/requisite-links/fields) | | `data[].entityId` | number | ID владельца | | `data[].requisiteId` | number | ID реквизита клиента, `0` — не привязан. Источник: [`GET /v1/requisites`](/docs/entities/requisites/list) | | `data[].bankDetailId` | number | ID банковского реквизита клиента, `0` — не привязан. Источник: [`GET /v1/bank-details`](/docs/entities/bank-details/list) | | `data[].mcRequisiteId` | number | ID реквизита вашей компании, `0` — не привязан | | `data[].mcBankDetailId` | number | ID банковского реквизита вашей компании, `0` — не привязан | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа ```json { "success": true, "data": [ { "entityTypeId": 2, "entityId": 3773, "requisiteId": 45, "bankDetailId": 0, "mcRequisiteId": 0, "mcBankDetailId": 0 }, { "entityTypeId": 2, "entityId": 3913, "requisiteId": 225, "bankDetailId": 0, "mcRequisiteId": 0, "mcBankDetailId": 0 } ], "meta": { "total": 40, "hasMore": true } } ``` ## Пример ответа при ошибке 400 — логический оператор верхнего уровня: ```json { "success": false, "error": { "code": "INVALID_FILTER_OPERATOR", "message": "'$or' is not supported. OR/AND logic cannot be expressed in a single requisite-links filter. For same-field set membership use { field: { $in: [v1, v2] } }; for cross-field OR run parallel requests. AND is the default — combine conditions as sibling keys in one filter object." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_FILTER_OPERATOR` | Логический оператор верхнего уровня `$or` или `$and` | | 400 | `MISSING_ENTITY_TYPE_ID` | Фильтр по `entityId` без `entityTypeId` | | 400 | `UNKNOWN_FILTER_FIELD` | Неизвестное поле фильтра, в сообщении — список допустимых | | 400 | `UNKNOWN_SORT_FIELD` | Неизвестное поле сортировки, в сообщении — список допустимых | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Связь в выдаче не означает наличия привязки.** Строка со всеми четырьмя идентификаторами, равными `0`, — это заведённая связь без единой привязки. Чтобы отобрать только реальные привязки, добавьте условие `{ "requisiteId": { "$gt": 0 } }`. **Набор одного поля вместо `$or`.** Несколько значений одного поля задаются через `$in` — например `{ "entityTypeId": { "$in": [2, 31] } }`. Условия по разным полям в одном фильтре объединяются по «и». ## Смотрите также - [Список связей](/docs/entities/requisite-links/list) - [Получить связь](/docs/entities/requisite-links/get) - [Поля связи](/docs/entities/requisite-links/fields) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) --- # Requisite Links: Unregister ## Удалить связь реквизита `DELETE /v1/requisite-links/:entityTypeId/:entityId` Удаляет привязку реквизита к сущности. После удаления реквизит и банковский реквизит остаются в системе — удаляется только связь между ними и сущностью-владельцем. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `entityTypeId` (path) | number | да | Тип владельца связи. Значения — [Поля связи](/docs/entities/requisite-links/fields) | | `entityId` (path) | number | да | ID сущности-владельца | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/requisite-links/2/3825" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/requisite-links/2/3825" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-links/2/3825', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Удалена связь для entityId:', data.entityId) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-links/2/3825', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Результат удаления | | `data.entityTypeId` | number | Тип сущности из пути запроса | | `data.entityId` | number | ID сущности из пути запроса | | `data.unregistered` | boolean | Всегда `true` при успехе | ## Пример ответа HTTP-статус: `200 OK` ```json { "success": true, "data": { "entityTypeId": 2, "entityId": 3825, "unregistered": true } } ``` ## Пример ответа при ошибке 400 — некорректный `entityTypeId` или `entityId` в пути: ```json { "success": false, "error": { "code": "INVALID_ANCHOR", "message": "Path requires entityTypeId and entityId — both positive integers (e.g. /v1/requisite-links/31/42)" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_ANCHOR` | `entityTypeId` или `entityId` в пути не являются положительными целыми числами | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm`. Требуемое сообщение: `This endpoint requires 'crm' scope` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Идемпотентно.** Удаление возвращает `200 {unregistered: true}` даже если связи для пары `(entityTypeId, entityId)` не существовало — повторный вызов безопасен, отдельной ошибки «не найдено» нет. ## Смотрите также - [Зарегистрировать связь](/docs/entities/requisite-links/register) - [Список связей](/docs/entities/requisite-links/list) - [Поиск связей](/docs/entities/requisite-links/search) - [Получить связь](/docs/entities/requisite-links/get) - [Поля связи](/docs/entities/requisite-links/fields) - [Batch](/docs/batch) --- # Requisite Links: Update ## Обновить связь реквизита `PATCH /v1/requisite-links/:entityTypeId/:entityId` Частично обновляет существующую привязку: меняет только переданные поля, остальные сохраняются. Пара владельца `entityTypeId` и `entityId` берётся из пути и не меняется. Полная перезапись всех четырёх привязок доступна через [`POST /v1/requisite-links`](/docs/entities/requisite-links/register). ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `entityTypeId` (path) | number | да | Тип владельца связи. Значения — [Поля связи](/docs/entities/requisite-links/fields) | | `entityId` (path) | number | да | ID сущности-владельца | ## Поля запроса (body) Передавайте только те поля, которые нужно изменить. Опущенные поля сохраняют текущее значение. Передайте `0`, чтобы снять привязку. | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `requisiteId` | number | нет | ID реквизита клиента. Источник: [`GET /v1/requisites`](/docs/entities/requisites/list). `0` — снять привязку | | `bankDetailId` | number | нет | ID банковского реквизита клиента. Источник: [`GET /v1/bank-details`](/docs/entities/bank-details/list). `0` — снять привязку | | `mcRequisiteId` | number | нет | ID реквизита вашей компании. Источник: [`GET /v1/requisites`](/docs/entities/requisites/list). `0` — снять привязку | | `mcBankDetailId` | number | нет | ID банковского реквизита вашей компании. Источник: [`GET /v1/bank-details`](/docs/entities/bank-details/list). `0` — снять привязку | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/requisite-links/2/3773" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "requisiteId": 46 }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/requisite-links/2/3773" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "requisiteId": 46 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-links/2/3773', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ requisiteId: 46, }), }) const { success, data } = await res.json() console.log('Обновлена связь для entityId:', data.entityId) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-links/2/3773', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ requisiteId: 46, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Состояние связи после обновления | | `data.entityTypeId` | number | Тип владельца из пути | | `data.entityId` | number | ID владельца из пути | | `data.requisiteId` | number | Итоговый ID реквизита клиента, `0` — не привязан | | `data.bankDetailId` | number | Итоговый ID банковского реквизита клиента, `0` — не привязан | | `data.mcRequisiteId` | number | Итоговый ID реквизита вашей компании, `0` — не привязан | | `data.mcBankDetailId` | number | Итоговый ID банковского реквизита вашей компании, `0` — не привязан | | `data.updated` | boolean | Всегда `true` при успехе | ## Пример ответа HTTP-статус: `200 OK` ```json { "success": true, "data": { "entityTypeId": 2, "entityId": 3773, "requisiteId": 46, "bankDetailId": 12, "mcRequisiteId": 3, "mcBankDetailId": 7, "updated": true } } ``` ## Пример ответа при ошибке 404 — связи для указанной пары не существует: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Связи для пары `entityTypeId` и `entityId` нет — создайте её через `POST /v1/requisite-links` | | 400 | `INVALID_ANCHOR` | `entityTypeId` или `entityId` в пути не положительное целое число | | 400 | `INVALID_REQUEST` | Тело запроса не является объектом | | 422 | `BITRIX_ERROR` | Привязка отклонена — например, реквизит нельзя привязать к сделке, у которой не выбран клиент | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Обновление не создаёт связь.** На отсутствующую пару `PATCH` отвечает `404`. Чтобы создать связь или полностью перезаписать все четыре привязки, используйте [`POST /v1/requisite-links`](/docs/entities/requisite-links/register). **Ключ связи не меняется.** `entityTypeId` и `entityId` берутся из пути и не обновляются. Чтобы перепривязать реквизит к другому владельцу, удалите старую связь и зарегистрируйте новую. **Опущенное поле и `0` — разные вещи.** Опущенное поле сохраняет текущее значение, явный `0` снимает привязку. ## Смотрите также - [Зарегистрировать связь](/docs/entities/requisite-links/register) - [Получить связь](/docs/entities/requisite-links/get) - [Удалить связь](/docs/entities/requisite-links/unregister) - [Поля связи](/docs/entities/requisite-links/fields) - [Batch](/docs/batch) --- # Requisite Presets: Create ## Создать шаблон реквизитов `POST /v1/requisite-presets` Создаёт новый шаблон — шаблон набора полей реквизита. После создания шаблон становится доступен как источник `presetId` при `POST /v1/requisites`. Восстановить удалённый шаблон нельзя — создавайте новый при необходимости. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `entityTypeId` | number | да | Тип набора полей — всегда `8`, реквизит | | `name` | string | да | Название шаблона («Организация», «ИП», «Физ. лицо») | | `countryId` | number | нет | ID страны набора полей; `1` — Россия | | `active` | boolean | нет | Активен ли шаблон. По умолчанию `true` | | `sort` | number | нет | Порядок сортировки. По умолчанию `500` | | `xmlId` | string | нет | Внешний идентификатор для синхронизации | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/requisite-presets" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "entityTypeId": 8, "name": "Организация", "countryId": 1, "active": true, "sort": 100 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/requisite-presets" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "entityTypeId": 8, "name": "Организация", "countryId": 1 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ entityTypeId: 8, name: 'Организация', countryId: 1, active: true, sort: 100, }), }) const { success, data } = await res.json() console.log('Создан шаблон ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ entityTypeId: 8, name: 'Организация', countryId: 1, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Созданный шаблон | | `data.id` | number | Идентификатор нового шаблона | | `data.entityTypeId` | number | Тип набора полей — `8` | | `data.countryId` | number | ID страны набора полей | | `data.name` | string | Название шаблона | | `data.active` | boolean | Активен ли шаблон | | `data.sort` | number | Порядок сортировки | | `data.xmlId` | string \| null | Внешний идентификатор | | `data.createdAt` | string | Дата создания (ISO 8601) | | `data.updatedAt` | string \| null | `null` сразу после создания | | `data.createdBy` | number | ID создателя | | `data.modifyBy` | number \| null | `null` сразу после создания | ## Пример ответа HTTP-статус: `201 Created` ```json { "success": true, "data": { "id": 31, "entityTypeId": 8, "countryId": 1, "createdAt": "2026-06-10T09:31:49.000Z", "updatedAt": null, "createdBy": 1, "modifyBy": null, "name": "Организация", "xmlId": null, "active": true, "sort": 500 } } ``` ## Пример ответа при ошибке 422 — Битрикс24 отклонил запрос (не указано обязательное поле): ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "ENTITY_TYPE_ID is not defined or invalid." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Битрикс24 отклонил запрос — не указано обязательное поле или передано некорректное значение (текст ошибки содержит имя поля) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Шаблон не содержит полей после создания.** Сразу после создания набор полей шаблона пустой. Чтобы добавить поля (ИНН, КПП, ФИО и т.д.), используйте `POST /v1/requisite-presets/:presetId/fields`. Список доступных полей для добавления — `GET /v1/requisite-presets/:presetId/fields/available`. ## Смотрите также - [Список шаблонов](/docs/entities/requisite-presets/list) - [Обновить шаблон](/docs/entities/requisite-presets/update) - [Удалить шаблон](/docs/entities/requisite-presets/delete) - [Добавить поле в шаблон](/docs/entities/requisite-presets/preset-fields/create) - [Создать реквизит](/docs/entities/requisites/create) - [Batch](/docs/batch) --- # Requisite Presets: Delete ## Удалить шаблон реквизитов `DELETE /v1/requisite-presets/:id` Удаляет шаблон по ID. Восстановить удалённый шаблон через API нельзя — создавайте новый при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID шаблона. Список: `GET /v1/requisite-presets` | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/requisite-presets/31" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/requisite-presets/31" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/31', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Шаблон удалён') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/31', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом. Признак успеха — код ответа, не содержимое. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — шаблон не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "The Preset with ID '999999' is not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Шаблон с таким ID не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Деактивация как альтернатива удалению.** Если шаблон используется реквизитами и удалять его не нужно, используйте поле `active: false` через [обновление](/docs/entities/requisite-presets/update) — шаблон не будет показываться в списке при создании реквизита. ## Смотрите также - [Список шаблонов](/docs/entities/requisite-presets/list) - [Получить шаблон](/docs/entities/requisite-presets/get) - [Обновить шаблон](/docs/entities/requisite-presets/update) - [Batch](/docs/batch) --- # Requisite Presets: Fields ## Поля шаблонов реквизитов `GET /v1/requisite-presets/fields` Возвращает схему полей шаблонов реквизитов: типы, признак доступности только для чтения. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/requisite-presets/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/requisite-presets/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() console.log('Всего полей:', Object.keys(data.fields).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа Ответ — объект `{ success, data: { fields: {...} } }`. Каждое поле описано объектом `{ type, readonly, label, description }`, где `label` — человекочитаемое название поля, а `description` — пояснение к нему. Оба приходят на русском языке. | Поле | Битрикс24 | Тип | RO | Описание | |------|-----------|-----|:--:|---------| | `id` | `ID` | number | да | Идентификатор шаблона | | `entityTypeId` | `ENTITY_TYPE_ID` | number | | Тип сущности — всегда `8`, реквизит. Задаётся при создании шаблона. В схеме помечен флагом `createOnly`, передача в теле обновления отклоняется с `400 READONLY_FIELD` | | `countryId` | `COUNTRY_ID` | number | | Идентификатор страны набора полей. Задаётся при создании шаблона. В схеме помечен флагом `createOnly`, передача в теле обновления отклоняется с `400 READONLY_FIELD` | | `name` | `NAME` | string | | Название шаблона | | `active` | `ACTIVE` | boolean | | Активен ли шаблон | | `sort` | `SORT` | number | | Порядок сортировки | | `xmlId` | `XML_ID` | string | | Внешний идентификатор для синхронизации | | `createdAt` | `DATE_CREATE` | datetime | да | Дата создания | | `updatedAt` | `DATE_MODIFY` | datetime | да | Дата последнего изменения | | `createdBy` | `CREATED_BY_ID` | number | да | Идентификатор создателя | | `modifyBy` | `MODIFY_BY_ID` | number | да | Идентификатор последнего редактора | `xmlId`, `updatedAt`, `modifyBy` могут быть `null`. Поле `createdBy` равно `0` у шаблонов, созданных системой. ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true }, "entityTypeId": { "type": "number", "readonly": false, "createOnly": true }, "countryId": { "type": "number", "readonly": false, "createOnly": true }, "name": { "type": "string", "readonly": false }, "active": { "type": "boolean", "readonly": false }, "sort": { "type": "number", "readonly": false }, "xmlId": { "type": "string", "readonly": false }, "createdAt": { "type": "datetime", "readonly": true }, "updatedAt": { "type": "datetime", "readonly": true }, "createdBy": { "type": "number", "readonly": true }, "modifyBy": { "type": "number", "readonly": true } } } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить шаблон](/docs/entities/requisite-presets/get) - [Создать шаблон](/docs/entities/requisite-presets/create) - [Список шаблонов](/docs/entities/requisite-presets/list) - [Шаблоны реквизитов](/docs/entities/requisite-presets) --- # Requisite Presets: Get ## Получить шаблон реквизитов `GET /v1/requisite-presets/:id` Возвращает шаблон реквизитов по ID со всеми системными полями. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID шаблона | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/requisite-presets/1" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/requisite-presets/1" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/1', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Шаблон:', data.name, '— страна', data.countryId) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/1', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект шаблона | | `data.id` | number | Идентификатор шаблона | | `data.entityTypeId` | number | Тип сущности — всегда `8`, реквизит | | `data.countryId` | number | Идентификатор страны набора полей; `1` — Россия | | `data.name` | string | Название шаблона | | `data.active` | boolean | Активен ли шаблон | | `data.sort` | number | Порядок сортировки | | `data.xmlId` | string \| null | Внешний идентификатор для синхронизации | | `data.createdAt` | datetime | Дата создания (ISO 8601) | | `data.updatedAt` | datetime \| null | Дата последнего изменения; `null`, если шаблон не изменялся | | `data.createdBy` | number | Идентификатор создателя; `0` — создано системой | | `data.modifyBy` | number \| null | Идентификатор последнего редактора; `null`, если шаблон не изменялся | ## Пример ответа ```json { "success": true, "data": { "id": 1, "entityTypeId": 8, "countryId": 1, "name": "Организация", "active": true, "sort": 510, "xmlId": "#CRM_REQUISITE_PRESET_DEF_RU_COMPANY#", "createdAt": "2020-04-20T10:47:23.000Z", "updatedAt": "2021-08-13T14:34:26.000Z", "createdBy": 0, "modifyBy": 1 } } ``` ## Пример ответа при ошибке 404 — шаблон не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "The Preset with ID '999999' is not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Шаблон с таким ID не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Поля шаблонов](/docs/entities/requisite-presets/fields) - [Список шаблонов](/docs/entities/requisite-presets/list) - [Обновить шаблон](/docs/entities/requisite-presets/update) - [Шаблоны реквизитов](/docs/entities/requisite-presets) --- # Requisite Presets: List ## Список шаблонов реквизитов `GET /v1/requisite-presets` Возвращает список шаблонов реквизитов с поддержкой фильтрации, сортировки и авто-пагинации. Используется для получения доступных шаблонов наборов полей перед созданием реквизита. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` Вайбкод автоматически запрашивает несколько страниц у Битрикс24 | | `offset` | number | `0` | Пропустить N записей. При `offset > 0` рекомендуется `limit ≤ 500` | | `select` | string | — | Выборка полей: `?select=id,name,active` | | `order` | object | — | Сортировка: `?order[sort]=asc` или `?order[id]=desc` | | `filter` | object | — | Фильтрация по полям `GET /v1/requisite-presets/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[active]=true&filter[countryId]=1` | ### Пагинация При `limit > 50` Вайбкод автоматически пагинирует запрос на стороне сервера. Максимум — 5000 записей за вызов. Если под фильтр попадает больше, в `meta.hasMore` придёт `true`. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/requisite-presets" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/requisite-presets" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} шаблонов`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив шаблонов (все поля — см. [Поля шаблонов реквизитов](/docs/entities/requisite-presets/fields)) | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | ## Пример ответа ```json { "success": true, "data": [ { "id": 1, "entityTypeId": 8, "countryId": 1, "name": "Организация", "createdAt": "2020-04-20T10:47:23.000Z", "updatedAt": "2021-08-13T14:34:26.000Z", "createdBy": 0, "modifyBy": 1, "active": true, "sort": 510, "xmlId": "#CRM_REQUISITE_PRESET_DEF_RU_COMPANY#" }, { "id": 3, "entityTypeId": 8, "countryId": 1, "name": "ИП", "createdAt": "2020-04-20T10:47:23.000Z", "updatedAt": "2021-07-20T14:39:09.000Z", "createdBy": 0, "modifyBy": 1, "active": false, "sort": 520, "xmlId": "#CRM_REQUISITE_PRESET_DEF_RU_INDIVIDUAL#" }, { "id": 5, "entityTypeId": 8, "countryId": 1, "name": "Физ. лицо", "createdAt": "2020-04-20T10:47:23.000Z", "updatedAt": "2021-08-13T14:34:34.000Z", "createdBy": 0, "modifyBy": null, "active": true, "sort": 530, "xmlId": "#CRM_REQUISITE_PRESET_DEF_RU_PERSON#" } ], "meta": { "total": 14, "hasMore": false } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 400 | `INVALID_FILTER` | Ошибка в синтаксисе фильтра | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Поле `entityTypeId` всегда равно `8`.** Все шаблоны относятся к типу сущности «реквизит» — `entityTypeId: 8`. Значение не изменяется и не передаётся в фильтре как различающий признак. **Поле `countryId`.** Российские шаблоны имеют `countryId: 1`. На портале с региональными шаблонами (Казахстан, Украина, Польша и др.) в списке появятся шаблоны с другими значениями. **Неактивные шаблоны включаются в список.** Шаблон с `active: false` возвращается в списке по умолчанию. Чтобы получить только активные шаблоны, передайте `filter[active]=true`. ## Смотрите также - [Поиск шаблонов реквизитов](/docs/entities/requisite-presets/search) - [Поля шаблонов реквизитов](/docs/entities/requisite-presets/fields) - [Создать реквизит](/docs/entities/requisites/create) - [Синтаксис фильтрации](/docs/filtering) - [Entity API](/docs/entity-api) --- # Requisite Presets: Preset Fields # Поля шаблона реквизитов Методы управления полями шаблона реквизитов CRM (`crm.requisite.preset.field.*`): состав полей шаблона, их настройки и порядок. ## Методы - [Список полей](/docs/entities/requisite-presets/preset-fields/list) - [Данные поля](/docs/entities/requisite-presets/preset-fields/get) - [Добавить поле](/docs/entities/requisite-presets/preset-fields/create) - [Обновить поле](/docs/entities/requisite-presets/preset-fields/update) - [Удалить поле](/docs/entities/requisite-presets/preset-fields/delete) - [Доступные поля](/docs/entities/requisite-presets/preset-fields/available) - [Схема полей](/docs/entities/requisite-presets/preset-fields/schema) Родительский раздел: [Шаблоны реквизитов](/docs/entities/requisite-presets). --- # Requisite Presets: Available ## Поля, доступные для добавления `GET /v1/requisite-presets/:presetId/fields/available` Возвращает имена полей, которые ещё можно добавить в шаблон реквизитов — те, которых пока нет в его составе. Используйте перед `POST /v1/requisite-presets/:presetId/fields`, чтобы узнать допустимые значения `fieldName`. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `presetId` (path) | number | да | ID шаблона реквизитов. Получить список шаблонов: `GET /v1/requisite-presets` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields/available" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields/available" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields/available', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields/available', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив имён полей, доступных для добавления | | `data[]` | string | Имя поля в формате Битрикс24: стандартные поля — `RQ_*`, пользовательские поля — `UF_CRM_*` | ## Пример ответа ```json { "success": true, "data": [ "RQ_NAME", "RQ_FIRST_NAME", "RQ_LAST_NAME", "RQ_SECOND_NAME", "RQ_CONTACT", "RQ_EMAIL", "RQ_PHONE", "RQ_FAX", "RQ_IDENT_DOC", "RQ_IDENT_DOC_SER", "RQ_IDENT_DOC_NUM", "RQ_IDENT_DOC_DATE", "RQ_IDENT_DOC_ISSUED_BY", "RQ_IDENT_DOC_DEP_CODE", "RQ_IFNS", "RQ_OGRNIP", "RQ_OKVED" ] } ``` ## Пример ответа при ошибке ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PRESET_ID` | Переданный `presetId` не является положительным целым числом | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Список сокращается по мере наполнения шаблона.** Каждое добавленное поле исчезает из ответа. Когда все доступные поля уже добавлены, `data` возвращает пустой массив. ## Смотрите также - [Добавить поле в шаблон](/docs/entities/requisite-presets/preset-fields/create) - [Список полей шаблона](/docs/entities/requisite-presets/preset-fields/list) - [Схема поля шаблона](/docs/entities/requisite-presets/preset-fields/schema) - [Шаблоны реквизитов](/docs/entities/requisite-presets) --- # Requisite Presets: Create ## Добавить поле в шаблон `POST /v1/requisite-presets/:presetId/fields` Добавляет поле из числа доступных в шаблон реквизита. Список доступных полей возвращает [`GET /v1/requisite-presets/:presetId/fields/available`](/docs/entities/requisite-presets/preset-fields/available). ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `presetId` (path) | number | да | ID шаблона реквизита | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `fieldName` | string | да | Идентификатор поля реквизита — например, `RQ_INN`. Список допустимых значений: [`GET /v1/requisite-presets/:presetId/fields/available`](/docs/entities/requisite-presets/preset-fields/available) | | `fieldTitle` | string | нет | Заголовок поля в интерфейсе Битрикс24. Если не передан, используется системное название поля | | `inShortList` | boolean | нет | Показывать ли поле в кратком списке. Принимает `true`/`false` | | `sort` | number | нет | Порядок сортировки поля в шаблоне | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "fieldName": "RQ_CONTACT", "inShortList": true, "sort": 500 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "fieldName": "RQ_CONTACT", "inShortList": true, "sort": 500 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ fieldName: 'RQ_CONTACT', inShortList: true, sort: 500, }), }) const { success, data } = await res.json() console.log('Добавлено поле ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ fieldName: 'RQ_CONTACT', inShortList: true, sort: 500, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Созданная строка поля шаблона. Полный набор полей приходит при подтверждённой сверке, иначе — только `id` (см. «Известные особенности») | | `data.id` | number | Идентификатор строки поля шаблона | | `data.fieldName` | string | Системное имя поля реквизита: `RQ_INN`, `RQ_COMPANY_NAME` и др. Приходит при полной форме ответа | | `data.fieldTitle` | string | Заголовок поля. Приходит при полной форме ответа | | `data.inShortList` | boolean | Показывается ли в кратком списке. Приходит при полной форме ответа | | `data.sort` | number | Порядок сортировки. Приходит при полной форме ответа | ## Пример ответа HTTP-статус: `201 Created` ```json { "success": true, "data": { "id": 1, "fieldName": "RQ_CONTACT", "fieldTitle": "Контактное лицо", "inShortList": true, "sort": 500 } } ``` ## Пример ответа — только идентификатор Когда сверку `fieldName` подтвердить не удалось, приходит только идентификатор: ```json { "success": true, "data": { "id": 1 } } ``` ## Пример ответа при ошибке 400 — неверный `presetId`: ```json { "success": false, "error": { "code": "INVALID_PRESET_ID", "message": "presetId must be a positive integer" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PRESET_ID` | `presetId` не является положительным целым числом | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm`. Сообщение: `This endpoint requires 'crm' scope` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Ответ приходит в одной из двух форм.** После создания Вайбкод перечитывает строку и сверяет её `fieldName` с запрошенным. При совпадении возвращается полная строка — `id`, `fieldName`, `fieldTitle`, `inShortList`, `sort`. Если совпадение подтвердить не удалось, возвращается только `id`. Получили ответ только с `id` — перечитайте [список полей шаблона](/docs/entities/requisite-presets/preset-fields/list) и найдите строку по `fieldName`, прежде чем обновлять или удалять её. ## Смотрите также - [Список полей шаблона](/docs/entities/requisite-presets/preset-fields/list) - [Поля, доступные для добавления](/docs/entities/requisite-presets/preset-fields/available) - [Обновить поле шаблона](/docs/entities/requisite-presets/preset-fields/update) - [Удалить поле шаблона](/docs/entities/requisite-presets/preset-fields/delete) - [Шаблоны реквизитов](/docs/entities/requisite-presets) --- # Requisite Presets: Delete ## Удалить поле шаблона `DELETE /v1/requisite-presets/:presetId/fields/:id` Удаляет строку поля из шаблона реквизита. Поле перестаёт входить в шаблон, но из системы не удаляется — его можно добавить обратно через [`POST /v1/requisite-presets/:presetId/fields`](/docs/entities/requisite-presets/preset-fields/create). ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `presetId` (path) | number | да | ID шаблона реквизита | | `id` (path) | number | да | ID строки поля шаблона (из [`GET /v1/requisite-presets/:presetId/fields`](/docs/entities/requisite-presets/preset-fields/list) — поле `id`) | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields/1" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields/1" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields/1', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields/1', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Результат операции | | `data.id` | number | ID удалённой строки поля шаблона | | `data.deleted` | boolean | Всегда `true` при успешном удалении | ## Пример ответа ```json { "success": true, "data": { "id": 1, "deleted": true } } ``` ## Пример ответа при ошибке 404 — строка поля не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "The PresetField with ID '99999' is not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Строка поля с таким `id` не найдена в данном шаблоне | | 400 | `INVALID_PRESET_ID` | `presetId` не является положительным целым числом | | 400 | `INVALID_FIELD_ID` | `id` не является положительным целым числом | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm`. Сообщение: `This endpoint requires 'crm' scope` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Удаление обратимо.** Операция удаляет поле из состава шаблона, но не уничтожает его в системе. Поле можно добавить обратно через [`POST /v1/requisite-presets/:presetId/fields`](/docs/entities/requisite-presets/preset-fields/create). **Перед удалением перечитайте список.** `id` строки поля позиционный и может измениться после изменения состава шаблона. Возьмите актуальный `id` из свежего [списка полей](/docs/entities/requisite-presets/preset-fields/list), найдя строку по `fieldName` — иначе удаление затронет другое поле. ## Смотрите также - [Список полей шаблона](/docs/entities/requisite-presets/preset-fields/list) - [Добавить поле в шаблон](/docs/entities/requisite-presets/preset-fields/create) - [Обновить поле шаблона](/docs/entities/requisite-presets/preset-fields/update) - [Шаблоны реквизитов](/docs/entities/requisite-presets) --- # Requisite Presets: Get ## Получить поле шаблона `GET /v1/requisite-presets/:presetId/fields/:id` Возвращает одну строку поля по её идентификатору в шаблоне реквизитов. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `presetId` (path) | number | да | ID шаблона реквизитов. Получить список шаблонов: `GET /v1/requisite-presets` | | `id` (path) | number | да | ID строки поля в шаблоне. Получить список: `GET /v1/requisite-presets/:presetId/fields` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields/1" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields/1" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields/1', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Поле:', data.fieldName, '— порядок:', data.sort) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields/1', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект строки поля шаблона | | `data.id` | number | Идентификатор строки поля в шаблоне | | `data.fieldName` | string | Системное имя поля реквизита: `RQ_INN`, `RQ_COMPANY_NAME` и др. | | `data.fieldTitle` | string | Заголовок поля. Если не переопределён, при одиночном чтении возвращается название по умолчанию, например «ИНН» для `RQ_INN` | | `data.inShortList` | boolean | Отображается ли поле в кратком списке реквизитов | | `data.sort` | number | Порядок сортировки поля в шаблоне | ## Пример ответа ```json { "success": true, "data": { "id": 1, "fieldName": "RQ_INN", "fieldTitle": "ИНН", "inShortList": true, "sort": 500 } } ``` ## Пример ответа при ошибке 404 — поле не найдено: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "The PresetField with ID '99999' is not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Строка поля с таким `id` не найдена в шаблоне | | 400 | `INVALID_PRESET_ID` | Переданный `presetId` не является положительным целым числом | | 400 | `INVALID_FIELD_ID` | Переданный `id` не является положительным целым числом | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Флаг `inShortList` — булев.** Поле приходит со значением `true` или `false`, а не `Y`/`N`. **`fieldTitle` содержит название по умолчанию.** Даже когда заголовок поля не переопределён, чтение одной записи возвращает его название — «ИНН» для `RQ_INN`, «Контактное лицо» для `RQ_CONTACT`. В [списке полей](/docs/entities/requisite-presets/preset-fields/list) то же поле придёт с `fieldTitle: ""`. **`id` поля — не то же самое, что `fieldName`.** Параметр `id` в пути — числовой идентификатор строки поля в шаблоне — поле `id` из ответа `GET /v1/requisite-presets/:presetId/fields`, а не системное имя поля `fieldName`. Для поиска поля по имени используйте `GET /v1/requisite-presets/:presetId/fields?filter[fieldName]=RQ_INN`. ## Смотрите также - [Список полей шаблона](/docs/entities/requisite-presets/preset-fields/list) - [Обновить поле шаблона](/docs/entities/requisite-presets/preset-fields/update) - [Удалить поле шаблона](/docs/entities/requisite-presets/preset-fields/delete) - [Схема поля шаблона](/docs/entities/requisite-presets/preset-fields/schema) - [Получить шаблон](/docs/entities/requisite-presets/get) --- # Requisite Presets: List ## Список полей шаблона `GET /v1/requisite-presets/:presetId/fields` Возвращает список полей, входящих в шаблон реквизитов. Поля описывают состав реквизита: ИНН, ОГРН, директор, КПП и другие. ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `presetId` (path) | number | да | — | ID шаблона реквизитов. Получить список шаблонов: `GET /v1/requisite-presets` | | `limit` | number | нет | `50` | Количество записей (до 5000) | | `offset` | number | нет | `0` | Пропустить N записей | | `filter` | object | нет | — | Фильтр по точному равенству поля, например `filter[fieldName]=RQ_INN`. Доступные поля: `id`, `fieldName`, `fieldTitle`, `inShortList`, `sort`. Неизвестное поле возвращает `400 UNKNOWN_FILTER_FIELD` | | `sort` | string | нет | — | Поле сортировки: `id`, `fieldName`, `fieldTitle`, `inShortList`, `sort`. Направление задаётся в `order` | | `order` | string | нет | `asc` | Направление сортировки: `asc` или `desc` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Полей в шаблоне: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив строк полей шаблона | | `data[].id` | number | Идентификатор строки поля в шаблоне | | `data[].fieldName` | string | Системное имя поля реквизита: `RQ_INN`, `RQ_COMPANY_NAME` и др. | | `data[].fieldTitle` | string | Пользовательский заголовок поля. Пустая строка означает, что используется заголовок по умолчанию | | `data[].inShortList` | boolean | Отображается ли поле в кратком списке реквизитов | | `data[].sort` | number | Порядок сортировки поля в шаблоне | | `meta.total` | number | Количество записей в наборе: с `filter` — после фильтрации, без `filter` — все поля шаблона | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` в этом наборе | ## Пример ответа ```json { "success": true, "data": [ { "id": 1, "fieldName": "RQ_INN", "fieldTitle": "", "inShortList": true, "sort": 500 }, { "id": 2, "fieldName": "RQ_COMPANY_NAME", "fieldTitle": "", "inShortList": true, "sort": 510 }, { "id": 3, "fieldName": "RQ_COMPANY_FULL_NAME", "fieldTitle": "", "inShortList": false, "sort": 520 } ], "meta": { "total": 13, "hasMore": false } } ``` ## Пример ответа при ошибке 404 — шаблон не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "The Preset with ID '999999' is not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PRESET_ID` | Переданный `presetId` не является положительным целым числом | | 400 | `UNKNOWN_FILTER_FIELD` | В `filter` указано поле вне списка `id`, `fieldName`, `fieldTitle`, `inShortList`, `sort` | | 400 | `UNKNOWN_SORT_FIELD` | В `sort` указано поле вне того же списка | | 400 | `INVALID_FILTER_OPERATOR` | В `filter` передан оператор — поддерживается только точное равенство | | 404 | `ENTITY_NOT_FOUND` | Шаблон с указанным `presetId` не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Идентификатор поля позиционный — не полагайтесь на сохранённое значение между операциями записи.** `data[].id` — позиционный идентификатор строки поля в шаблоне. После изменения состава шаблона — добавления или удаления полей — он может измениться. Для обновления или удаления перечитывайте список и находите нужную строку по `fieldName`, а не по ранее сохранённому `id`. **Флаг `inShortList` — булев.** Поле приходит со значением `true` или `false`, а не `Y`/`N`. **`fieldTitle` в списке пуст, пока заголовок не переопределён.** Название по умолчанию — «ИНН» для `RQ_INN`, «Контактное лицо» для `RQ_CONTACT` — возвращает чтение одной записи: [`GET /v1/requisite-presets/:presetId/fields/:id`](/docs/entities/requisite-presets/preset-fields/get). В списке то же поле придёт с `fieldTitle: ""`. **Пагинация применяется на стороне Вайбкод.** Параметры `limit` и `offset` обрабатываются Вайбкод после получения всего списка от Битрикс24. Если шаблон содержит более 50 полей, передавайте `limit` с нужным значением — по умолчанию возвращается 50 записей. ## Смотрите также - [Получить поле шаблона](/docs/entities/requisite-presets/preset-fields/get) - [Добавить поле в шаблон](/docs/entities/requisite-presets/preset-fields/create) - [Поля, доступные для добавления](/docs/entities/requisite-presets/preset-fields/available) - [Получить шаблон](/docs/entities/requisite-presets/get) - [Список шаблонов реквизитов](/docs/entities/requisite-presets/list) --- # Requisite Presets: Schema ## Схема поля шаблона `GET /v1/requisite-presets/:presetId/fields/schema` Возвращает структуру строки поля шаблона реквизитов: типы, обязательность, флаги доступа. Используйте, чтобы узнать допустимые типы и правила перед `POST /v1/requisite-presets/:presetId/fields` или `PATCH /v1/requisite-presets/:presetId/fields/:id`. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `presetId` (path) | number | да | ID шаблона реквизитов. Получить список шаблонов: `GET /v1/requisite-presets` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields/schema" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields/schema" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields/schema', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields/schema', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект с описанием схемы | | `data.fields` | object | Словарь полей строки шаблона. Ключи — в camelCase: `id`, `fieldName` и другие | | `data.fields.id` | object | Идентификатор строки поля. Только для чтения | | `data.fields.fieldName` | object | Имя поля реквизита, например `RQ_INN`. Обязательно при создании. При обновлении передавать не нужно — текущее значение подставляется автоматически | | `data.fields.fieldTitle` | object | Заголовок поля в печатной форме. Не обязателен | | `data.fields.sort` | object | Порядок сортировки поля в шаблоне | | `data.fields.inShortList` | object | Флаг отображения поля в кратком списке. В API представлен как `true`/`false` | Каждое поле в `data.fields` описано объектом со следующими ключами: | Ключ | Тип | Описание | |------|-----|---------| | `type` | string | Тип значения: `integer`, `string`, `boolean` | | `isRequired` | boolean | Обязательно ли поле при создании | | `isReadOnly` | boolean | Только для чтения — нельзя задать при записи | | `isImmutable` | boolean | Нельзя изменить после создания | | `isMultiple` | boolean | Допускает несколько значений | | `isDynamic` | boolean | Динамическое (пользовательское) поле | | `title` | string | Название поля для отображения, на языке портала | ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "integer", "isRequired": false, "isReadOnly": true, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "ID" }, "fieldName": { "type": "string", "isRequired": true, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Имя" }, "fieldTitle": { "type": "string", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Название в шаблоне" }, "sort": { "type": "integer", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Сортировка" }, "inShortList": { "type": "boolean", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Показывать в кратком списке" } } } } ``` ## Пример ответа при ошибке ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PRESET_ID` | Переданный `presetId` не является положительным целым числом | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Поле `inShortList` и в схеме, и в данных булево.** При записи через `POST` или `PATCH` передавайте `true`/`false`, в ответах чтения поле приходит как `true`/`false`. Битрикс24 в своём описании схемы называет тип этого поля `char` — Вайбкод приводит его к `boolean`, чтобы схема не расходилась со строками, которые она описывает. **Схема объявляет `fieldName` обязательным (`isRequired: true`), но при обновлении его передавать не нужно.** При `PATCH` без `fieldName` Вайбкод получает текущее значение из Битрикс24 и подставляет его автоматически. Обязательным `fieldName` остаётся при создании через `POST`. ## Смотрите также - [Поля, доступные для добавления](/docs/entities/requisite-presets/preset-fields/available) - [Добавить поле в шаблон](/docs/entities/requisite-presets/preset-fields/create) - [Обновить поле шаблона](/docs/entities/requisite-presets/preset-fields/update) - [Шаблоны реквизитов](/docs/entities/requisite-presets) --- # Requisite Presets: Update ## Обновить поле шаблона `PATCH /v1/requisite-presets/:presetId/fields/:id` Обновляет заголовок, позицию сортировки или признак краткого списка у строки поля шаблона. Передавайте только те поля, которые нужно изменить. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `presetId` (path) | number | да | ID шаблона реквизита | | `id` (path) | number | да | ID строки поля шаблона (из [`GET /v1/requisite-presets/:presetId/fields`](/docs/entities/requisite-presets/preset-fields/list) — поле `id`) | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `fieldTitle` | string | нет | Заголовок поля в интерфейсе Битрикс24 | | `inShortList` | boolean | нет | Показывать ли поле в кратком списке. Принимает `true`/`false` | | `sort` | number | нет | Порядок сортировки поля в шаблоне | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields/1" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "fieldTitle": "Инн организации", "inShortList": false, "sort": 100 }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields/1" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "sort": 100 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields/1', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ fieldTitle: 'Инн организации', inShortList: false, sort: 100, }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/1/fields/1', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ sort: 100, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Результат операции | | `data.id` | number | ID обновлённой строки поля шаблона | | `data.updated` | boolean | Всегда `true` при успешном обновлении | ## Пример ответа ```json { "success": true, "data": { "id": 1, "updated": true } } ``` ## Пример ответа при ошибке 404 — строка поля не найдена: ```json { "success": false, "error": { "code": "NOT_FOUND", "message": "Preset field 99999 not found in preset 1" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `NOT_FOUND` | Строка поля с таким `id` не найдена в данном шаблоне | | 400 | `INVALID_FIELD_NAME` | Переданное `fieldName` отличается от имени строки и отсутствует среди [доступных к добавлению](/docs/entities/requisite-presets/preset-fields/available). Обновление не выполнено | | 400 | `INVALID_FIELD_NAME` | `fieldName` передан не строкой (числом, массивом, объектом, `null`). Сообщение: `Field name must be a string, got <тип>.` | | 400 | `INVALID_PRESET_ID` | `presetId` не является положительным целым числом | | 400 | `INVALID_FIELD_ID` | `id` не является положительным целым числом | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm`. Сообщение: `This endpoint requires 'crm' scope` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Смена `fieldName` проверяется до записи.** Если `fieldName` в теле отличается от имени, которое строка уже несёт, имя сверяется со списком [доступных к добавлению](/docs/entities/requisite-presets/preset-fields/available); имя вне этого списка возвращает `400 INVALID_FIELD_NAME`, и ни одно поле строки не меняется — в том числе `sort` и `fieldTitle`, если они пришли тем же запросом. Метод обновления в Битрикс24 сам имя не проверяет, поэтому без этой сверки в шаблоне оседало имя, за которым нет поля. Имя, которое уже занято другой строкой того же шаблона, в списке доступных отсутствует и тоже отклоняется. Надёжнее по-прежнему не переименовывать строку, а удалить её и добавить новую с нужным `fieldName`. **Регистр имени приводится к тому, что вернул Битрикс24.** `fieldName` можно писать в любом регистре: если имя совпадает с текущим, в шаблон записывается сохранённое написание, а при переименовании — то, которое перечислил список доступных. Собственное написание запроса до шаблона не доезжает. **Запрос с `fieldName` на несуществующую строку отвечает `404` до записи.** Раньше он уходил в Битрикс24 и возвращал его ответ. **Перед обновлением перечитайте список.** `id` строки поля позиционный и может измениться после изменения состава шаблона. Возьмите актуальный `id` из свежего [списка полей](/docs/entities/requisite-presets/preset-fields/list), найдя строку по `fieldName` — иначе обновление затронет другое поле. ## Смотрите также - [Список полей шаблона](/docs/entities/requisite-presets/preset-fields/list) - [Добавить поле в шаблон](/docs/entities/requisite-presets/preset-fields/create) - [Удалить поле шаблона](/docs/entities/requisite-presets/preset-fields/delete) - [Шаблоны реквизитов](/docs/entities/requisite-presets) --- # Requisite Presets: Search ## Поиск шаблонов реквизитов `POST /v1/requisite-presets/search` Поиск шаблонов реквизитов с фильтрами и авто-пагинацией. Аналогичен `GET /v1/requisite-presets`, но параметры передаются в теле запроса — удобнее для сложных фильтров с большим количеством условий и для программной сборки запросов. ## Поля запроса (body) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям `GET /v1/requisite-presets/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "active": true, "countryId": 1 }` | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки» | | `order` | object | — | Сортировка: `{ "sort": "asc" }` или `{ "id": "desc" }` | | `select` | string[] | — | Выборка полей: `["id", "name", "active", "countryId"]` | | `autoWindow` | boolean | `true` | Разбивать выборку по недельным окнам при фильтре по диапазону дат шире 14 дней. `false` отключает разбиение | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/requisite-presets/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "active": true }, "limit": 20 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/requisite-presets/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "active": true }, "limit": 20 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { active: true }, limit: 20, }), }) const { success, data, meta } = await res.json() console.log('Найдено:', meta.total) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { active: true }, limit: 20, }), }) const { success, data, meta } = await res.json() ``` ### Другие сценарии Найти шаблоны по стране: ```json { "filter": { "countryId": 1 }, "order": { "sort": "asc" } } ``` Только активные шаблоны, выбрать только id и name: ```json { "filter": { "active": true }, "select": ["id", "name"], "order": { "sort": "asc" } } ``` Найти шаблон по xmlId: ```json { "filter": { "xmlId": "#CRM_REQUISITE_PRESET_DEF_RU_COMPANY#" } } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив шаблонов (все поля — см. [Поля шаблонов реквизитов](/docs/entities/requisite-presets/fields)) | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временны́м окнам | | `meta.windowCount` | number | Число окон. Приходит при `autoWindowed: true` | | `meta.batchWaves` | number | Число волн параллельных запросов. Приходит при `autoWindowed: true` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа ```json { "success": true, "data": [ { "id": 1, "entityTypeId": 8, "countryId": 1, "name": "Организация", "createdAt": "2020-04-20T10:47:23.000Z", "updatedAt": "2021-08-13T14:34:26.000Z", "createdBy": 0, "modifyBy": 1, "active": true, "sort": 510, "xmlId": "#CRM_REQUISITE_PRESET_DEF_RU_COMPANY#" }, { "id": 5, "entityTypeId": 8, "countryId": 1, "name": "Физ. лицо", "createdAt": "2020-04-20T10:47:23.000Z", "updatedAt": "2021-08-13T14:34:34.000Z", "createdBy": 0, "modifyBy": null, "active": true, "sort": 530, "xmlId": "#CRM_REQUISITE_PRESET_DEF_RU_PERSON#" } ], "meta": { "total": 13, "hasMore": false, "durationMs": 224 } } ``` С фильтром по диапазону дат шире 14 дней в `meta` дополнительно приходят `autoWindowed`, `windowCount` и `batchWaves`: ```json { "success": true, "data": [ /* ... */ ], "meta": { "total": 14, "hasMore": false, "autoWindowed": true, "windowCount": 444, "batchWaves": 9, "durationMs": 12658 } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 400 | `INVALID_FILTER` | Ошибка в синтаксисе фильтра | | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Разбиение по временны́м окнам.** Фильтр по диапазону дат шире 14 дней автоматически разбивается на недельные окна, которые выполняются параллельными волнами — так выборка обходит потолок в 5000 записей на один вызов. В `meta` тогда приходят `autoWindowed: true`, число окон `windowCount` и число волн `batchWaves`. Отключает разбиение параметр `autoWindow: false`. При активном разбиении `offset` больше нуля отклоняется с `UNSTABLE_OFFSET_PAGINATION`. **Поле `xmlId` — стабильный идентификатор встроенных шаблонов.** Встроенные российские шаблоны имеют константные значения `xmlId`: `#CRM_REQUISITE_PRESET_DEF_RU_COMPANY#`, `#CRM_REQUISITE_PRESET_DEF_RU_INDIVIDUAL#`, `#CRM_REQUISITE_PRESET_DEF_RU_PERSON#`. Поиск по `xmlId` надёжнее поиска по `id`, который может различаться между порталами. **Пагинация.** При `limit > 50` запрос автоматически разбивается на несколько вызовов к Битрикс24. Для больших выборок используйте `offset` и постраничные запросы. ## Смотрите также - [Список шаблонов реквизитов](/docs/entities/requisite-presets/list) - [Поля шаблонов реквизитов](/docs/entities/requisite-presets/fields) - [Синтаксис фильтрации](/docs/filtering) - [Entity API](/docs/entity-api) --- # Requisite Presets: Update ## Обновить шаблон реквизитов `PATCH /v1/requisite-presets/:id` Обновляет поля существующего шаблона реквизитов. Передавайте только те поля, которые нужно изменить — остальные остаются без изменений. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID шаблона. Список: `GET /v1/requisite-presets` | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `name` | string | нет | Название шаблона | | `active` | boolean | нет | Активен ли шаблон | | `sort` | number | нет | Порядок сортировки | | `xmlId` | string | нет | Внешний идентификатор для синхронизации | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/requisite-presets/31" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Организация (обновлено)", "sort": 999 }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/requisite-presets/31" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Организация (обновлено)" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/31', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Организация (обновлено)', sort: 999, }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisite-presets/31', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Организация (обновлено)', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Обновлённый шаблон с актуальными значениями полей | | `data.id` | number | Идентификатор шаблона | | `data.entityTypeId` | number | Тип набора полей — `8` | | `data.countryId` | number | ID страны набора полей | | `data.name` | string | Название шаблона | | `data.active` | boolean | Активен ли шаблон | | `data.sort` | number | Порядок сортировки | | `data.xmlId` | string \| null | Внешний идентификатор | | `data.createdAt` | string | Дата создания (ISO 8601) | | `data.updatedAt` | string | Дата последнего обновления (ISO 8601) | | `data.createdBy` | number | ID создателя | | `data.modifyBy` | number \| null | ID пользователя, выполнившего обновление | ## Пример ответа ```json { "success": true, "data": { "id": 31, "entityTypeId": 8, "countryId": 1, "createdAt": "2026-06-10T09:31:49.000Z", "updatedAt": "2026-06-10T09:31:49.000Z", "createdBy": 1, "modifyBy": null, "name": "Организация (обновлено)", "xmlId": null, "active": true, "sort": 999 } } ``` ## Пример ответа при ошибке 404 — шаблон не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "The Preset with ID '999999' is not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `READONLY_FIELD` | Передано поле, задаваемое только при создании, — `countryId` или `entityTypeId`. В схеме [`GET /v1/requisite-presets/fields`](./fields.md) они помечены флагом `createOnly` | | 404 | `ENTITY_NOT_FOUND` | Шаблон с таким ID не найден | | 422 | `BITRIX_ERROR` | Битрикс24 отклонил значение одного из полей | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Поля `entityTypeId` и `countryId` задаются только при создании.** В схеме [`GET /v1/requisite-presets/fields`](./fields.md) они приходят с флагом `createOnly` и с `readonly: false` — записать их можно, но лишь в теле создания. Передача любого из них в теле обновления отклоняется с `400 READONLY_FIELD`. Чтобы использовать другую страну, создайте новый шаблон. ## Смотрите также - [Получить шаблон](/docs/entities/requisite-presets/get) - [Список шаблонов](/docs/entities/requisite-presets/list) - [Удалить шаблон](/docs/entities/requisite-presets/delete) - [Поля шаблонов](/docs/entities/requisite-presets/fields) - [Batch](/docs/batch) --- # Requisites: Aggregate ## Агрегация реквизитов `POST /v1/requisites/aggregate` Подсчёт количества реквизитов с фильтрацией и группировкой. **Стандартные поля для `groupBy`:** - `rqInn`, `rqKpp`, `rqOgrn`, `rqOgrnip`, `rqOkpo` — налоговые/регистрационные идентификаторы (ИНН, КПП, ОГРН, ОГРНИП, ОКПО) - `rqVatId` — VAT/налоговый номер (для не-РФ стран) - `rqResidenceCountry` — страна резидентства - `rqCompanyName` — название компании - `entityTypeId` — тип владельца (1 — лид, 3 — контакт, 4 — компания) - `presetId` — шаблон реквизита - `active` — признак активности Все поля в `aggregatable` — идентификаторы и категориальные коды, поэтому по ним работает `groupBy`. Группировка по `rqInn` (или другому идентификатору) — самый быстрый способ найти дубли реквизитов одним вызовом, без выгрузки всех записей. Числовые функции (`sum`/`avg`/`min`/`max`) по этим полям недоступны (это строки) — используйте для них пользовательские UF-поля числового типа. **Контракт `count`.** Функция `count` принимает ТОЛЬКО `field: "*"` — `{ "field": "*", "function": "count" }`. Передача `field: "id"` (или любого другого имени) вернёт `400 INVALID_PARAMS` с сообщением `count aggregate requires field "*"`. Это намеренный контракт: `count` считает строки, а не значения конкретного поля. **Пользовательские поля (UF):** UF-поля типов `integer`, `double`, `money` — для числовых функций, UF любого типа — для `groupBy`. Строковые UF-поля реквизита — ИНН, номер телефона, адрес — доступны только в `groupBy`. Полный список UF-полей конкретного портала приходит в тексте ошибки `INVALID_PARAMS`, если передать несуществующее имя. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций. Каждый элемент: `{ "field": "*", "function": "count" }`. Без параметра — только count | | `filter` | object | нет | Фильтрация по полям `GET /v1/requisites/fields`.
[Синтаксис фильтрации](/docs/filtering) | | `groupBy` | string \| string[] | нет | Поле или массив полей для группировки (максимум 5). Принимает UF-поля любого типа | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/requisites/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "active": true }, "groupBy": "entityTypeId" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/requisites/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "active": true }, "groupBy": "entityTypeId" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisites/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { active: true }, groupBy: 'entityTypeId', }), }) const { success, data } = await res.json() console.log('Всего активных реквизитов:', data.count) console.log('По типам владельцев:', data.groups) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisites/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { active: true }, groupBy: 'entityTypeId', }), }) const { success, data } = await res.json() ``` > Для группировки по нескольким полям передайте массив: `"groupBy": ["entityTypeId", "presetId"]` (максимум 5). ## Другие сценарии Блоки ниже — тела запросов. Общее количество реквизитов в портале — самый быстрый запрос, без выгрузки записей: ```json {} ``` Поиск дублей по ИНН одним вызовом — группы с `count > 1` содержат повторяющиеся ИНН: ```json { "aggregate": [{ "field": "*", "function": "count" }], "groupBy": "rqInn" } ``` Группировка по UF-полю (любой тип — например, пользовательский классификатор): ```json { "groupBy": "UF_CRM_CLASSIFIER" } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Количество записей, соответствующих фильтру | | `data.aggregates` | object | Результаты числовых агрегаций. Пусто, если массив `aggregate` не передан или содержит только `count` | | `data.groups` | array | Группы (только при `groupBy`). Каждый элемент: поля группировки + `count` | | `data.meta.totalRecords` | number | Общее количество записей | | `data.meta.recordsProcessed` | number | Количество обработанных записей | | `data.meta.truncated` | boolean | Был ли результат ограничен. `true` при более 5000 записей | ## Пример ответа Ответ на основной запрос (`groupBy: "entityTypeId"`): ```json { "success": true, "data": { "count": 164, "aggregates": {}, "groups": [ { "entityTypeId": 4, "count": 120 }, { "entityTypeId": 3, "count": 40 }, { "entityTypeId": 1, "count": 4 } ], "meta": { "totalRecords": 164, "recordsProcessed": 164, "truncated": false } } } ``` Без `groupBy` поле `data.groups` в ответе отсутствует. ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "Requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Некорректное имя функции агрегации или несуществующее поле | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Money-поля.** UF-поля типа `money` хранятся в формате `"сумма|валюта"` (`"1500|RUB"`) — агрегат извлекает числовую часть автоматически, складывать можно без парсинга. **Без массива `aggregate` — только count.** Если не передать `aggregate`, метод вернёт `count` записей с учётом фильтра. **Фильтрация по UF работает.** В `filter` можно передавать любые поля — стандартные и пользовательские, любого типа. Например, `{ "filter": { "UF_CRM_1234": "value" } }` вернёт количество реквизитов с этим значением UF. **Ограничение 5000 записей.** Если под фильтр попадает больше 5000 записей, результат будет помечен `meta.truncated: true`. Для точного подсчёта больших выборок используйте `meta.total` в ответе `GET /v1/requisites` с `limit=1` — там хранится реальное количество. ## Смотрите также - [Список реквизитов](/docs/entities/requisites/list) - [Поиск реквизитов](/docs/entities/requisites/search) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Requisites: Create ## Создать реквизит `POST /v1/requisites` Создаёт новый реквизит и привязывает его к контакту или компании CRM. ## Обязательные поля Для создания реквизита обязательны четыре поля: | Поле | Тип | Допустимые значения | Описание | |------|-----|--------------------|---------| | `entityTypeId` | number | `3` (контакт), `4` (компания) | Тип родительской сущности | | `entityId` | number | любой существующий ID | ID родительской сущности. Поиск: `GET /v1/contacts` или `GET /v1/companies` | | `presetId` | number | любой существующий ID шаблона | ID [шаблона реквизита](/docs/entities/requisite-presets) (определяет набор полей). Источник: `GET /v1/requisite-presets` | | `name` | string | непустая строка | Название реквизита в интерфейсе Битрикс24 | ## Популярные поля Все поля в camelCase. Полный список — [`GET /v1/requisites/fields`](./fields.md). ### Общие | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `active` | boolean | `true` | Активен ли реквизит | | `sort` | number | `500` | Порядок сортировки (чем меньше — тем выше) | | `code` / `xmlId` / `originatorId` | string | — | Внешние идентификаторы для синхронизации | | `addressOnly` | boolean | `false` | Признак «только адрес» (для адресных справочников) | ### Юрлица | Параметр | Тип | Описание | |----------|-----|---------| | `rqName` | string | Полное наименование | | `rqCompanyName` | string | Сокращённое название | | `rqCompanyFullName` | string | Полное название юрлица | | `rqCompanyRegDate` | date | Дата регистрации | | `rqInn` | string | ИНН | | `rqKpp` | string | КПП | | `rqOgrn` | string | ОГРН | | `rqOgrnip` | string | ОГРНИП (для ИП) | | `rqOkpo` / `rqOkved` / `rqOktmo` | string | Классификаторы | | `rqDirector` | string | ФИО директора | | `rqAccountant` | string | ФИО главного бухгалтера | | `rqCeoName` / `rqCeoWorkPos` | string | ФИО и должность руководителя | | `rqContact` / `rqEmail` / `rqPhone` / `rqFax` | string | Контакты организации | | `rqVatPayer` | boolean | Плательщик НДС | | `rqVatId` | string | ИНН для НДС (иностранные) | | `rqBaseDoc` | string | Документ-основание деятельности (например, «Устав») | | `rqResidenceCountry` | string | Страна регистрации | ### Физлица | Параметр | Тип | Описание | |----------|-----|---------| | `rqFirstName` / `rqLastName` / `rqSecondName` | string | Имя / Фамилия / Отчество | | `rqIdentDocType` | string | Название документа, удостоверяющего личность | | `rqIdentDocSer` / `rqIdentDocNum` | string | Серия / Номер документа | | `rqIdentDocDate` | date | Дата выдачи | | `rqIdentDocIssuedBy` | string | Кем выдан | | `rqIdentDocDepCode` | string | Код подразделения | ### Международные шаблоны Поля шаблонов других стран — `rqEdrpou`, `rqKbe`, `rqRegon`, `rqSiret`, `rqCnpj` — передаются в camelCase, как остальные поля схемы. Заполняются на реквизитах соответствующего странового шаблона. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/requisites" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "entityTypeId": 4, "entityId": 15, "presetId": 1, "name": "Основной", "rqName": "ООО «Ромашка»", "rqInn": "7701234567", "rqKpp": "770101001", "rqOgrn": "1027700123456", "rqCompanyName": "Ромашка", "rqDirector": "Иванов Иван Иванович", "rqVatPayer": true }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/requisites" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "entityTypeId": 4, "entityId": 15, "presetId": 1, "name": "Основной", "rqName": "ООО «Ромашка»", "rqInn": "7701234567" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisites', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ entityTypeId: 4, entityId: 15, presetId: 1, name: 'Основной', rqName: 'ООО «Ромашка»', rqInn: '7701234567', rqKpp: '770101001', rqOgrn: '1027700123456', rqCompanyName: 'Ромашка', rqDirector: 'Иванов Иван Иванович', rqVatPayer: true, }), }) const { success, data } = await res.json() console.log('Создан реквизит ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisites', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ entityTypeId: 4, entityId: 15, presetId: 1, name: 'Основной', rqName: 'ООО «Ромашка»', rqInn: '7701234567', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Созданный реквизит | | `data.id` | number | Идентификатор новой записи | | `data.entityTypeId` / `data.entityId` / `data.presetId` | number | Переданные значения | | `data.name` | string \| null | Название реквизита | | `data.active` | boolean | Активен ли реквизит. По умолчанию `true` | | `data.sort` | number | Порядок сортировки. По умолчанию `500` | | `data.createdAt` / `data.updatedAt` | datetime | Совпадают при создании | | `data.createdBy` | number | ID создателя | | `data.modifyBy` | number \| null | `null` сразу после создания | Ответ содержит все поля шаблона реквизита в camelCase. Незаполненные поля — `null`. Полный список полей — [Поля реквизита](/docs/entities/requisites/fields). ## Пример ответа HTTP-статус: `201 Created` ```json { "success": true, "data": { "id": 42, "entityTypeId": 4, "entityId": 15, "presetId": 1, "name": "Основной", "active": true, "sort": 500, "createdAt": "2026-04-19T14:30:00+03:00", "updatedAt": "2026-04-19T14:30:00+03:00", "createdBy": 1, "modifyBy": null, "rqName": "ООО «Ромашка»", "rqInn": "7701234567", "rqKpp": "770101001", "rqOgrn": "1027700123456", "rqCompanyName": "Ромашка", "rqDirector": "Иванов Иван Иванович", "rqVatPayer": true, "rqAccountant": null, "rqCeoName": null, "rqOkpo": null, "rqOkved": null } } ``` ## Пример ответа при ошибке 422 — не указан `presetId`: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "PRESET_ID is not defined or invalid." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Не указано обязательное поле — Битрикс24 отвечает текстом вида `PRESET_ID is not defined or invalid` / «Не заполнено обязательное поле „Название"» | | 422 | `BITRIX_ERROR` | Битрикс24 отклонил значение одного из полей (например, несуществующий `presetId`) | | 403 | `BITRIX_ACCESS_DENIED` | Нет доступа к родительской компании/контакту | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Поля, которых нет в шаблоне, игнорируются.** Переданное поле, которого нет в выбранном шаблоне, отбрасывается: ошибка не возникает, значение не сохраняется. ## Смотрите также - [Список реквизитов](/docs/entities/requisites/list) - [Поля реквизита](/docs/entities/requisites/fields) - [Обновить реквизит](/docs/entities/requisites/update) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Requisites: Delete ## Удалить реквизит `DELETE /v1/requisites/:id` Удаляет реквизит по ID. Вместе с ним удаляются привязанные к нему адреса и банковские реквизиты — отключить это нельзя. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID реквизита | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/requisites/42" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/requisites/42" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisites/42', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Реквизит удалён') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisites/42', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — реквизит не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "The Requisite with ID '999999999' is not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Реквизит с таким ID не найден | | 403 | `BITRIX_ACCESS_DENIED` | Нет доступа к родительской сущности | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Мягкое удаление отсутствует.** После удаления восстановить реквизит нельзя — создавайте новый. Если нужен временный «отказ от использования», используйте поле `active: false` через [обновление](/docs/entities/requisites/update). ## Смотрите также - [Список реквизитов](/docs/entities/requisites/list) - [Получить реквизит](/docs/entities/requisites/get) - [Обновить реквизит](/docs/entities/requisites/update) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Requisites: Fields ## Поля реквизита `GET /v1/requisites/fields` Возвращает полный перечень полей реквизита. Поля схемы Вайбкод возвращаются в camelCase, пользовательские поля `UF_CRM_*` — в исходном регистре Битрикс24. Каждый реквизит хранит значения только тех полей, которые есть в его шаблоне. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/requisites/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/requisites/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisites/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() console.log('Всего полей:', Object.keys(data.fields).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisites/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Формат ответа Ответ — объект `{ success, data: { fields: {...} } }`. Каждое поле описано объектом: - **Поля схемы Вайбкод** в camelCase: `{ type, readonly, label, description }`, где `label` и `description` приходят на русском языке. В ответах `list`, `get`, `create`, `update`, `search` возвращаются под camelCase-именем. Фильтр и сортировка — по тому же имени. - **Пользовательские поля `UF_CRM_*`** в исходном регистре: `{ type, readonly, label }`, где `label` — название поля на языке портала. ## Поля схемы Вайбкод Поля российских и международных шаблонов реквизита. ### Служебные | Вайбкод-имя | Битрикс24 | Тип | RO | Описание | |----------|----------|-----|:--:|---------| | `id` | `ID` | number | да | ID реквизита | | `entityTypeId` | `ENTITY_TYPE_ID` | number | | `3` — контакт, `4` — компания | | `entityId` | `ENTITY_ID` | number | | ID родительской сущности | | `presetId` | `PRESET_ID` | number | | ID [шаблона реквизитов](/docs/entities/requisite-presets). Неизменяем после создания | | `name` | `NAME` | string | | Название в интерфейсе Битрикс24 | | `code` | `CODE` | string | | Символьный код для внешних интеграций | | `xmlId` | `XML_ID` | string | | Внешний идентификатор для синхронизации | | `originatorId` | `ORIGINATOR_ID` | string | | ID системы-источника | | `active` | `ACTIVE` | boolean | | Активен ли реквизит | | `sort` | `SORT` | number | | Порядок сортировки. Меньше — выше | | `createdAt` | `DATE_CREATE` | datetime | да | Дата создания | | `updatedAt` | `DATE_MODIFY` | datetime | да | Дата последнего изменения | | `createdBy` | `CREATED_BY_ID` | number | да | ID создателя | | `modifyBy` | `MODIFY_BY_ID` | number | да | ID последнего редактора | | `addressOnly` | `ADDRESS_ONLY` | boolean | | Признак «только адрес» | ### Юрлица | Вайбкод-имя | Битрикс24 | Тип | Описание | |----------|----------|-----|---------| | `rqName` | `RQ_NAME` | string | Полное наименование | | `rqCompanyName` | `RQ_COMPANY_NAME` | string | Сокращённое название | | `rqCompanyFullName` | `RQ_COMPANY_FULL_NAME` | string | Полное название | | `rqCompanyId` | `RQ_COMPANY_ID` | string | Идентификатор компании | | `rqCompanyRegDate` | `RQ_COMPANY_REG_DATE` | date | Дата регистрации | | `rqDirector` | `RQ_DIRECTOR` | string | ФИО директора | | `rqAccountant` | `RQ_ACCOUNTANT` | string | ФИО главного бухгалтера | | `rqCeoName` | `RQ_CEO_NAME` | string | ФИО руководителя | | `rqCeoWorkPos` | `RQ_CEO_WORK_POS` | string | Должность руководителя | | `rqContact` | `RQ_CONTACT` | string | Контактное лицо | | `rqEmail` | `RQ_EMAIL` | string | Email организации | | `rqPhone` | `RQ_PHONE` | string | Телефон организации | | `rqFax` | `RQ_FAX` | string | Факс | | `rqInn` | `RQ_INN` | string | ИНН | | `rqKpp` | `RQ_KPP` | string | КПП | | `rqUsn` | `RQ_USN` | string | УСН | | `rqOgrn` | `RQ_OGRN` | string | ОГРН | | `rqOgrnip` | `RQ_OGRNIP` | string | ОГРНИП (для ИП) | | `rqOkpo` | `RQ_OKPO` | string | ОКПО | | `rqOkved` | `RQ_OKVED` | string | ОКВЭД | | `rqOktmo` | `RQ_OKTMO` | string | ОКТМО | | `rqIfns` | `RQ_IFNS` | string | ИФНС | | `rqUsrle` | `RQ_USRLE` | string | Сведения о регистрации в реестре юридических лиц | | `rqTaxRegime` | `RQ_TAX_REGIME` | string | Налоговый режим. Значение из справочника портала | | `rqVatPayer` | `RQ_VAT_PAYER` | boolean | Плательщик НДС | | `rqVatId` | `RQ_VAT_ID` | string | ИНН для НДС | | `rqVatCertSer` | `RQ_VAT_CERT_SER` | string | Серия свидетельства НДС | | `rqVatCertNum` | `RQ_VAT_CERT_NUM` | string | Номер свидетельства НДС | | `rqVatCertDate` | `RQ_VAT_CERT_DATE` | date | Дата свидетельства НДС | | `rqResidenceCountry` | `RQ_RESIDENCE_COUNTRY` | string | Страна регистрации | | `rqBaseDoc` | `RQ_BASE_DOC` | string | Документ-основание | | `rqBaseDocDate` | `RQ_BASE_DOC_DATE` | date | Дата документа-основания | | `rqBaseDocNum` | `RQ_BASE_DOC_NUM` | string | Номер документа-основания | | `rqRegCertNum` | `RQ_REG_CERT_NUM` | string | Свидетельство о регистрации — номер | | `rqRegCertDate` | `RQ_REG_CERT_DATE` | date | Свидетельство о регистрации — дата | | `rqStCertSer` | `RQ_ST_CERT_SER` | string | Серия свидетельства о государственной регистрации | | `rqStCertNum` | `RQ_ST_CERT_NUM` | string | Номер свидетельства о государственной регистрации | | `rqStCertDate` | `RQ_ST_CERT_DATE` | string | Дата свидетельства о государственной регистрации | | `rqRegOrganization` | `RQ_REG_ORGANIZATION` | string | Регистрирующий орган | | `rqStateReg` | `RQ_STATE_REG` | string | Государственная регистрация | | `rqMnplReg` | `RQ_MNPL_REG` | string | Муниципальная регистрация | | `rqStampPresent` | `RQ_STAMP_PRESENT` | boolean | Наличие печати | ### Физлица | Вайбкод-имя | Битрикс24 | Тип | Описание | |----------|----------|-----|---------| | `rqFirstName` | `RQ_FIRST_NAME` | string | Имя | | `rqLastName` | `RQ_LAST_NAME` | string | Фамилия | | `rqSecondName` | `RQ_SECOND_NAME` | string | Отчество | | `rqIdentType` | `RQ_IDENT_TYPE` | string | Тип документа, удостоверяющего личность. Значение из справочника портала | | `rqIdentDocType` | `RQ_IDENT_DOC` | string | Название документа, удостоверяющего личность | | `rqIdentDocSer` | `RQ_IDENT_DOC_SER` | string | Серия документа | | `rqIdentDocNum` | `RQ_IDENT_DOC_NUM` | string | Номер документа | | `rqIdentDocPersNum` | `RQ_IDENT_DOC_PERS_NUM` | string | Персональный номер документа | | `rqIdentDocDate` | `RQ_IDENT_DOC_DATE` | date | Дата выдачи | | `rqIdentDocIssuedBy` | `RQ_IDENT_DOC_ISSUED_BY` | string | Кем выдан | | `rqIdentDocDepCode` | `RQ_IDENT_DOC_DEP_CODE` | string | Код подразделения | ### Международные шаблоны Поля шаблонов других стран. Заполнены только на реквизитах соответствующего странового шаблона — на российских реквизитах возвращаются как `null`. | Вайбкод-имя | Битрикс24 | Страна | Описание | |----------|----------|--------|---------| | `rqEdrpou` | `RQ_EDRPOU` | 🇺🇦 Украина | ЕДРПОУ | | `rqDrfo` | `RQ_DRFO` | 🇺🇦 Украина | ДРФО | | `rqKbe` | `RQ_KBE` | 🇰🇿 Казахстан | КБе | | `rqIin` | `RQ_IIN` | 🇰🇿 Казахстан | ИИН | | `rqBin` | `RQ_BIN` | 🇰🇿 Казахстан | БИН | | `rqRegon` | `RQ_REGON` | 🇵🇱 Польша | REGON | | `rqKrs` | `RQ_KRS` | 🇵🇱 Польша | KRS | | `rqPesel` | `RQ_PESEL` | 🇵🇱 Польша | PESEL | | `rqSiret` | `RQ_SIRET` | 🇫🇷 Франция | SIRET | | `rqSiren` | `RQ_SIREN` | 🇫🇷 Франция | SIREN | | `rqRcs` | `RQ_RCS` | 🇫🇷 Франция | RCS | | `rqCapital` | `RQ_CAPITAL` | 🇫🇷 Франция | Capital | | `rqCnpj` | `RQ_CNPJ` | 🇧🇷 Бразилия | CNPJ — юрлица | | `rqCpf` | `RQ_CPF` | 🇧🇷 Бразилия | CPF — физлица | | `rqLegalForm` | `RQ_LEGAL_FORM` | общее | Форма юрлица | ## Пользовательские поля `UF_CRM_*` — поля, настроенные на портале через интерфейс Битрикс24. Возвращаются в исходном регистре с дополнительной меткой `label`. ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true }, "entityTypeId": { "type": "number", "readonly": false }, "presetId": { "type": "number", "readonly": false }, "rqInn": { "type": "string", "readonly": false }, "rqKpp": { "type": "string", "readonly": false }, "rqCompanyName": { "type": "string", "readonly": false }, "rqDirector": { "type": "string", "readonly": false }, "rqEdrpou": { "type": "string", "readonly": false }, "rqRegon": { "type": "string", "readonly": false }, "createdAt": { "type": "datetime", "readonly": true }, "createdBy": { "type": "number", "readonly": true }, "UF_CRM_1698325419": { "type": "string", "readonly": false, "label": "Внутренний код" } } } } ``` Показана небольшая часть полей. Полный состав зависит от настроенных на портале шаблонов и пользовательских полей. ## Пример ответа при ошибке 401 — нет токенов: ```json { "success": false, "error": { "code": "TOKEN_MISSING", "message": "API key has no OAuth tokens configured" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Все активные шаблоны в одном ответе.** Метод возвращает поля со всех активных шаблонов портала, включая страновые. На отдельном реквизите заполнены только поля его шаблона, остальные возвращаются как `null`. **Пустые значения нормализованы.** Для строковых, числовых, date и datetime полей Вайбкод приводит `""` к `null` в ответах `list`, `get`, `create`, `update`, `search`. На метод `fields` это не влияет — он возвращает только метаданные поля. **Метка `label` у пользовательских полей.** У полей `UF_CRM_*` возвращается `label` с названием поля на языке портала. У полей схемы Вайбкод `label` и `description` приходят на русском языке. ## Смотрите также - [Создать реквизит](/docs/entities/requisites/create) - [Список реквизитов](/docs/entities/requisites/list) - [Entity API](/docs/entity-api) - [Лимиты и оптимизация](/docs/optimization) --- # Requisites: Get ## Получить реквизит `GET /v1/requisites/:id` Возвращает реквизит по ID со всеми полями, которые доступны в его шаблоне (шаблон задаёт набор полей: наименование, ИНН/КПП/ОГРН, директор, бухгалтер и т. д.). ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID реквизита | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/requisites/42" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/requisites/42" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisites/42', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Реквизит:', data.rqName, '— ИНН', data.rqInn) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisites/42', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект реквизита | | `data.id` | number | Идентификатор реквизита | | `data.entityTypeId` | number | Тип родительской сущности: `3` — контакт, `4` — компания | | `data.entityId` | number | ID родительской сущности | | `data.presetId` | number | ID [шаблона реквизитов](/docs/entities/requisite-presets) | | `data.name` | string | Название реквизита в интерфейсе | | `data.active` | boolean | Активен ли реквизит | | `data.sort` | number | Порядок сортировки | | `data.createdAt` / `data.updatedAt` | datetime | Даты создания и изменения (ISO 8601) | | `data.createdBy` / `data.modifyBy` | number \| null | ID создателя / последнего редактора | | `data.rqName` / `data.rqInn` / `data.rqKpp` / `data.rqOgrn` | string \| null | Основные реквизиты юрлица | Поля шаблона, которые не заполнены, возвращаются как `null`. Полный список полей — [Поля реквизита](/docs/entities/requisites/fields). ## Пример ответа ```json { "success": true, "data": { "id": 42, "entityTypeId": 4, "entityId": 15, "presetId": 1, "name": "Основной реквизит", "active": true, "sort": 500, "code": null, "xmlId": null, "addressOnly": false, "createdAt": "2025-01-15T09:30:00+03:00", "updatedAt": "2026-03-20T14:00:00+03:00", "createdBy": 1, "modifyBy": 1, "rqName": "ООО «Ромашка»", "rqInn": "7701234567", "rqKpp": "770101001", "rqOgrn": "1027700123456", "rqOkpo": "12345678", "rqOkved": "62.01", "rqOktmo": null, "rqVatPayer": false, "rqCompanyName": "Ромашка", "rqCompanyFullName": "Общество с ограниченной ответственностью «Ромашка»", "rqDirector": "Иванов Иван Иванович", "rqAccountant": "Петрова Анна Сергеевна", "rqCeoName": null, "rqCeoWorkPos": null, "rqContact": null, "rqEmail": null, "rqPhone": null, "rqBaseDoc": "Устав" } } ``` ## Пример ответа при ошибке 404 — реквизит не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "The Requisite with ID '999999999' is not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Реквизит с таким ID не найден | | 403 | `BITRIX_ACCESS_DENIED` | Нет доступа к родительской сущности (контакту/компании) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Набор полей зависит от шаблона.** Реквизит хранит только поля, которые определены в его шаблоне `presetId`. Например, у шаблона «Организация» будет `rqCompanyName`, `rqCompanyFullName`, `rqDirector`, а у шаблона «Физ. лицо» — `rqFirstName`, `rqLastName`, `rqSecondName` и т. д. **Пользовательские поля — в исходном регистре.** Поля схемы Вайбкод возвращаются в camelCase, а пользовательские `UF_CRM_*` — в исходном регистре Битрикс24. ## Смотрите также - [Поля реквизита](/docs/entities/requisites/fields) - [Обновить реквизит](/docs/entities/requisites/update) - [Удалить реквизит](/docs/entities/requisites/delete) - [Список реквизитов](/docs/entities/requisites/list) - [Лимиты и оптимизация](/docs/optimization) --- # Requisites: List ## Список реквизитов `GET /v1/requisites` Возвращает список реквизитов CRM с поддержкой фильтрации, сортировки и авто-пагинации. Реквизиты всегда принадлежат конкретному контакту или компании — почти всегда вам нужен фильтр по `entityTypeId` и `entityId`. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` Вайбкод автоматически запрашивает несколько страниц у Битрикс24 | | `offset` | number | `0` | Пропустить N записей. При `offset > 0` рекомендуется `limit ≤ 500` | | `select` | string | — | Выборка полей: `?select=id,rqName,rqInn` | | `order` | object | — | Сортировка: `?order[sort]=asc` или `?sort=-id` | | `filter` | object | — | Фильтрация по полям `GET /v1/requisites/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[entityTypeId]=4&filter[entityId]=15` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/requisites?filter[entityTypeId]=4&filter[entityId]=15" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/requisites?filter[entityTypeId]=4&filter[entityId]=15" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisites?filter[entityTypeId]=4&filter[entityId]=15', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} реквизитов`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisites?filter[entityTypeId]=4&filter[entityId]=15', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив реквизитов (все поля — см. [Поля реквизита](/docs/entities/requisites/fields)) | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами limit | ## Пример ответа ```json { "success": true, "data": [ { "id": 42, "entityTypeId": 4, "entityId": 15, "presetId": 1, "name": "Основной реквизит", "active": true, "sort": 500, "code": null, "xmlId": null, "addressOnly": false, "createdAt": "2025-01-15T09:30:00+03:00", "updatedAt": "2026-03-20T14:00:00+03:00", "createdBy": 1, "modifyBy": 1, "rqName": "ООО «Ромашка»", "rqInn": "7701234567", "rqKpp": "770101001", "rqOgrn": "1027700123456", "rqOkpo": "12345678", "rqOkved": "62.01", "rqCompanyName": "Ромашка", "rqCompanyFullName": "Общество с ограниченной ответственностью «Ромашка»", "rqDirector": "Иванов Иван Иванович", "rqAccountant": "Петрова Анна Сергеевна", "rqVatPayer": false } ], "meta": { "total": 1, "hasMore": false } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "Requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 400 | `INVALID_FILTER` | Ошибка в синтаксисе фильтра | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Поля схемы — camelCase, пользовательские — в исходном регистре.** Все поля схемы Вайбкод, в том числе поля международных шаблонов `rqEdrpou`, `rqKbe`, `rqRegon`, `rqSiret`, `rqCnpj`, возвращаются в camelCase. Фильтр и сортировка — по тому же имени. Пользовательские поля `UF_CRM_*` возвращаются в исходном регистре Битрикс24. **Пустые значения нормализованы.** Битрикс24 возвращает `""` для очищенных полей и `null` для никогда не заполненных. Вайбкод приводит их к `null` для string/number/date/datetime типов — клиенту достаточно проверки `if (v)` без дополнительных условий. **Сужайте выборку фильтром по владельцу.** В портале могут быть десятки тысяч реквизитов. Для получения реквизитов конкретной компании или контакта передавайте `entityTypeId` + `entityId`. **Коды `entityTypeId`:** `3` — контакт, `4` — компания. Для смарт-процессов и других сущностей CRM реквизиты не поддерживаются на уровне Битрикс24. **Авто-пагинация.** При `limit > 50` Вайбкод автоматически запрашивает несколько страниц у Битрикс24 и возвращает все записи в одном ответе. **Ограничение offset.** При `offset ≥ 2500` Битрикс24 может вернуть `INTERNAL_ERROR`. Используйте `limit ≤ 500` при больших offset. ## Смотрите также - [Получить реквизит](/docs/entities/requisites/get) - [Поиск реквизитов](/docs/entities/requisites/search) - [Поля реквизита](/docs/entities/requisites/fields) - [Синтаксис фильтрации](/docs/filtering) - [Entity API](/docs/entity-api) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Requisites: Search ## Поиск реквизитов `POST /v1/requisites/search` Поиск реквизитов с фильтрами и авто-пагинацией. Аналогичен `GET /v1/requisites`, но параметры передаются в теле запроса — удобнее для сложных фильтров с большим количеством условий и для программной сборки запросов. ## Поля запроса (body) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям `GET /v1/requisites/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "entityTypeId": 4, "entityId": 15 }` | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки» | | `order` | object | — | Сортировка: `{ "sort": "asc" }` | | `select` | string[] | — | Выборка полей: `["id", "rqName", "rqInn"]` | | `autoWindow` | boolean | `true` | Разбивать выборку по недельным окнам при фильтре по диапазону дат шире 14 дней. `false` отключает разбиение | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/requisites/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "entityTypeId": 4, "active": true }, "limit": 20, "order": { "sort": "asc" } }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/requisites/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "entityTypeId": 4, "active": true }, "limit": 20, "order": { "sort": "asc" } }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisites/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { entityTypeId: 4, active: true }, limit: 20, order: { sort: 'asc' }, }), }) const { success, data } = await res.json() console.log('Найдено:', data.length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisites/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { entityTypeId: 4, active: true }, limit: 20, order: { sort: 'asc' }, }), }) const { success, data } = await res.json() ``` ### Другие сценарии Поиск по ИНН: ```json { "filter": { "rqInn": "7701234567" } } ``` Поиск по полю странового шаблона (французский SIRET): ```json { "filter": { "rqSiret": "73282932000074" } } ``` Международные поля `rqSiret`, `rqSiren`, `rqRegon`, `rqKbe`, `rqCnpj` — это поля схемы, фильтр по ним в camelCase. Все реквизиты одной компании: ```json { "filter": { "entityTypeId": 4, "entityId": 15 }, "order": { "sort": "asc" } } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив реквизитов (все поля — см. [Поля реквизита](/docs/entities/requisites/fields)) | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временны́м окнам | | `meta.windowCount` | number | Число окон. Приходит при `autoWindowed: true` | | `meta.batchWaves` | number | Число волн параллельных запросов. Приходит при `autoWindowed: true` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа ```json { "success": true, "data": [ { "id": 42, "entityTypeId": 4, "entityId": 15, "presetId": 1, "name": "Основной реквизит", "active": true, "sort": 500, "rqName": "ООО «Ромашка»", "rqInn": "7701234567", "rqKpp": "770101001", "rqOgrn": "1027700123456", "rqCompanyName": "Ромашка", "rqDirector": "Иванов Иван Иванович", "createdAt": "2025-01-15T09:30:00+03:00" } ], "meta": { "total": 79, "hasMore": true, "durationMs": 188 } } ``` С фильтром по диапазону дат шире 14 дней в `meta` дополнительно приходят `autoWindowed`, `windowCount` и `batchWaves`: ```json { "success": true, "data": [ /* ... */ ], "meta": { "total": 174, "hasMore": true, "autoWindowed": true, "windowCount": 444, "batchWaves": 9, "durationMs": 20835 } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "Requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 400 | `INVALID_FILTER` | Ошибка в синтаксисе фильтра | | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Разбиение по временны́м окнам.** Фильтр по диапазону дат шире 14 дней автоматически разбивается на недельные окна, которые выполняются параллельными волнами — так выборка обходит потолок в 5000 записей на один вызов. В `meta` тогда приходят `autoWindowed: true`, число окон `windowCount` и число волн `batchWaves`. Отключает разбиение параметр `autoWindow: false`. При активном разбиении `offset` больше нуля отклоняется с `UNSTABLE_OFFSET_PAGINATION`. **Имена полей в фильтре.** Поля Вайбкод-схемы передавайте в camelCase — `rqInn`, `rqKpp`, `entityTypeId`, `rqCompanyName`, `rqDirector`, а также поля международных шаблонов `rqEdrpou`, `rqKbe`, `rqRegon`, `rqSiret`, `rqCnpj` и редкие служебные `rqIfns`, `rqUsrle`. Пользовательские поля `UF_CRM_*` — в исходном регистре. **Пагинация.** При `limit > 50` запрос автоматически разбивается на несколько вызовов к Битрикс24. Для больших выборок используйте `offset` и постраничные запросы. ## Смотрите также - [Список реквизитов](/docs/entities/requisites/list) - [Поля реквизита](/docs/entities/requisites/fields) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Requisites: Update ## Обновить реквизит `PATCH /v1/requisites/:id` Обновляет поля существующего реквизита. Передавайте только те поля, которые нужно изменить. Полный список — [`GET /v1/requisites/fields`](/docs/entities/requisites/fields). ## Часто обновляемые поля | Параметр | Тип | Описание | |----------|-----|---------| | `name` | string | Название реквизита в интерфейсе Битрикс24 | | `active` | boolean | Активен ли реквизит | | `sort` | number | Порядок сортировки | | `rqName` | string | Полное наименование | | `rqInn` | string | ИНН | | `rqKpp` | string | КПП | | `rqOgrn` | string | ОГРН | | `rqCompanyName` | string | Сокращённое название юрлица | | `rqDirector` | string | ФИО директора | | `rqAccountant` | string | ФИО главного бухгалтера | | `rqVatPayer` | boolean | Плательщик НДС | Все поля в camelCase, включая поля международных шаблонов — `rqEdrpou`, `rqKbe`, `rqRegon`, `rqSiret`, `rqCnpj`. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID реквизита | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/requisites/42" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "rqInn": "7701234567", "rqKpp": "770101001", "rqDirector": "Иванов Иван Иванович" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/requisites/42" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "rqInn": "7701234567", "rqKpp": "770101001" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisites/42', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ rqInn: '7701234567', rqKpp: '770101001', rqDirector: 'Иванов Иван Иванович', }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/requisites/42', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ rqInn: '7701234567', rqKpp: '770101001', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Обновлённый реквизит с актуальными значениями полей | | `data.id` | number | Идентификатор реквизита | | `data.updatedAt` | datetime | Новая дата изменения | | `data.modifyBy` | number | ID пользователя, выполнившего обновление | Объект содержит все поля шаблона в camelCase — включая неизменённые. Незаполненные поля — `null`. Полный список — [Поля реквизита](/docs/entities/requisites/fields). ## Пример ответа ```json { "success": true, "data": { "id": 42, "entityTypeId": 4, "entityId": 15, "presetId": 1, "name": "Основной реквизит", "active": true, "sort": 500, "rqName": "ООО «Ромашка»", "rqInn": "7701234567", "rqKpp": "770101001", "rqOgrn": "1027700123456", "rqDirector": "Иванов Иван Иванович", "updatedAt": "2026-04-19T15:00:00+03:00", "modifyBy": 1 } } ``` ## Пример ответа при ошибке 404 — реквизит не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "The Requisite with ID '999999999' is not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Реквизит с таким ID не найден | | 403 | `BITRIX_ACCESS_DENIED` | Нет доступа к родительской сущности | | 400 | `INVALID_REQUEST` | Некорректные поля | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Сменить шаблон нельзя.** Поле `presetId` задаётся при создании и его нельзя изменить обновлением. Если нужен другой шаблон — создайте новый реквизит и удалите старый. **Перенос между сущностями невозможен.** `entityTypeId` и `entityId` также неизменяемы: реквизит остаётся привязан к тому контакту или компании, для которых создан. **Поля вне шаблона игнорируются.** Значения полей, которых нет в шаблоне реквизита, отбрасываются. Ошибка не возникает, но и данные не сохраняются. Проверить результат — `GET /v1/requisites/:id`. **Пустое значение очищает поле.** Чтобы очистить поле, передайте пустую строку `""`. В ответах Вайбкод приводит очищенные строки к `null`, чтобы формат пустых значений был единым. ## Смотрите также - [Получить реквизит](/docs/entities/requisites/get) - [Поля реквизита](/docs/entities/requisites/fields) - [Удалить реквизит](/docs/entities/requisites/delete) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Sites: Aggregate ## Агрегация сайтов `POST /v1/sites/aggregate` Подсчёт количества сайтов с учётом фильтра и группировка по категориальным полям. Поддерживает функцию `count` и группировку `groupBy`. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций. Для сайтов осмысленна `{ "field": "*", "function": "count" }` — числовых полей-метрик для `sum`/`avg`/`min`/`max` у сущности нет. Без параметра возвращается `count` записей с учётом фильтра | | `groupBy` | string \| array | нет | Поле или поля для группировки. Допустимы только поля из `aggregatable`: `type`, `active`, `deleted`, `lang`, `tplId`, `domainId`, `createdById`, `modifiedById`. До 5 полей | | `groupOrderBy` | array | нет | Сортировка групп: массив `{ "field": "count" \| "<измерение>", "direction": "asc" \| "desc" }`. Работает только вместе с `groupBy` | | `groupLimit` | number | нет | Ограничение числа возвращаемых групп (1..1000). Работает только вместе с `groupBy` | | `filter` | object | нет | Фильтрация по ключевым полям сайта.
[Синтаксис фильтрации](/docs/filtering) | | `scope` | string | нет | Внутренняя область лендингов: `KNOWLEDGE` / `GROUP` / `MAINPAGE`. Без параметра подсчитываются обычные сайты-лендинги | > **Фильтр по типу и область (`scope`).** Если вы передали `{"filter": {"type": "KNOWLEDGE"}}` или `"GROUP"` без `scope`, Вайбкод сам подставит соответствующую область (`type=KNOWLEDGE` → `scope=KNOWLEDGE`) — подсчёт баз знаний и страниц групп работает без ручного указания `scope`, как в списке и поиске. Явный `scope` в приоритете. `MAINPAGE` — область, а не тип сайта (её сайты имеют тип `VIBE`), поэтому из фильтра по типу не выводится: для главных страниц передавайте `scope=MAINPAGE` явно. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/sites/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "groupBy": "type" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/sites/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "groupBy": "type" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/sites/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ groupBy: 'type', }), }) const { success, data } = await res.json() console.log('Сайтов по типу:', data.groups) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/sites/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ groupBy: 'type', }), }) const { success, data } = await res.json() ``` ## Другие сценарии Общее количество сайтов в портале — самый быстрый запрос, без выгрузки записей: ```json {} ``` Количество активных сайтов-лендингов: ```json { "filter": { "type": "PAGE", "active": true } } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Количество сайтов, соответствующих фильтру | | `data.aggregates` | object | Результаты числовых агрегаций. Для сайтов остаётся пустым — нет числовых полей-метрик | | `data.groups` | array | Присутствует при `groupBy`. Каждый элемент — значение измерения плюс `count` записей в группе | | `data.meta.totalRecords` | number | Общее количество записей | | `data.meta.recordsProcessed` | number | Количество обработанных записей | | `data.meta.truncated` | boolean | Был ли результат ограничен (`true` при более 5000 записей) | | `data.meta.groupTotal` | number | Присутствует при `groupBy` — количество групп | | `data.meta.groupsTruncated` | boolean | Присутствует при `groupBy`. `true`, если число групп превысило лимит и список групп усечён | ## Пример ответа Группировка по типу (`groupBy: "type"`): ```json { "success": true, "data": { "count": 18, "aggregates": {}, "groups": [ { "type": "PAGE", "count": 11, "aggregates": {} }, { "type": "STORE", "count": 5, "aggregates": {} }, { "type": "VIBE", "count": 2, "aggregates": {} } ], "meta": { "totalRecords": 18, "recordsProcessed": 18, "truncated": false, "groupTotal": 3, "groupsTruncated": false } } } ``` Простой подсчёт без группировки (`{}`): ```json { "success": true, "data": { "count": 18, "aggregates": {}, "meta": { "totalRecords": 18, "recordsProcessed": 0, "truncated": false } } } ``` ## Пример ответа при ошибке 400 — поле вне списка `aggregatable`: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "groupBy field 'title' is not aggregatable on this entity. Available: type, active, deleted, lang, tplId, domainId, createdById, modifiedById." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Поле `groupBy` вне списка `aggregatable` или неизвестная функция агрегации | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `landing` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Группировка считается по выборке.** При более 5000 записей (`meta.truncated: true`) счётчики групп основаны на выборке из 5000 записей, а верхний `count` остаётся точным общим числом по фильтру. **Видимость по правам пользователя.** В подсчёт попадают только те сайты, к которым у владельца API-ключа есть право «просмотр». Если ожидается ненулевой результат, но `count` равен нулю — проверьте права пользователя, под которым выпущен ключ. ## Смотрите также - [Список сайтов](/docs/entities/sites/list) - [Поиск сайтов](/docs/entities/sites/search) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Sites: Create ## Создать сайт `POST /v1/sites` Создаёт новый сайт на портале. Тип сайта определяется полем `type`. Поля передаются плоско в корне JSON — без обёртки `fields`. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `title` | string | да | Название сайта, до 255 символов | | `type` | string | нет | Тип сайта. По умолчанию `PAGE` — лендинг. Также `STORE` — интернет-магазин, `KNOWLEDGE` — база знаний 2.0. Для `KNOWLEDGE` обязательно передайте также `scope: "KNOWLEDGE"` — см. ниже | | `scope` | string | нет | Раздел Битрикс24, в котором создаётся сайт: `KNOWLEDGE` (база знаний 2.0), `GROUP` (база знаний группы) или `MAINPAGE`. Без него создаётся обычный сайт-лендинг. **Чтобы создать базу знаний, передайте `scope: "KNOWLEDGE"` вместе с `type: "KNOWLEDGE"`** — иначе сервер вернёт `403 BITRIX_ACCESS_DENIED` («Доступ на создание сайта запрещён»). Можно передать как поле тела или query-параметром `?scope=KNOWLEDGE`. То же значение `scope` нужно при [обновлении](/docs/entities/sites/update) и [удалении](/docs/entities/sites/delete) такого сайта | | `code` | string | да | Символьный код сайта в URL. **Ключ обязателен**, но значение может быть пустым (`""`) или `null` — тогда код генерируется из `title`. Если опустить сам ключ `code`, создание возвращает `422` (см. «Адрес сайта обязателен» в «Известных особенностях»). Если код только из цифр — добавляется префикс `site`. Если код уже занят на домене — числовой суффикс (`code2`, `code3`) | | `domainId` | number | нет | Идентификатор домена. Если не передавать, адрес формируется из `code` на `bitrix24site.ru` | | `description` | string | нет | Описание сайта, до 255 символов | | `xmlId` | string | нет | Внешний идентификатор, до 255 символов | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/sites" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Лендинг конференции", "code": "conf-2026", "type": "PAGE" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/sites" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Лендинг конференции", "code": "conf-2026", "type": "PAGE" }' ``` ### curl — база знаний 2.0 (`scope=KNOWLEDGE`) ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/sites" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "База знаний компании", "type": "KNOWLEDGE", "scope": "KNOWLEDGE" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/sites', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Лендинг конференции', code: 'conf-2026', type: 'PAGE', }), }) const { success, data } = await res.json() console.log('Site ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/sites', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Лендинг конференции', code: 'conf-2026', type: 'PAGE', }), }) const { success, data } = await res.json() ``` ## Поля ответа Возвращается полный объект созданного сайта. | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор созданного сайта | | `title` | string | Название сайта | | `code` | string | Фактический символьный код (с авто-суффиксом, если код запроса был занят) | | `type` | string | Тип сайта | | `active` | boolean | Всегда `false` для только что созданного сайта | | `domainId` | number | Идентификатор домена (выданного автоматически или переданного) | | `createdById` | number | Идентификатор создавшего пользователя | | `dateCreate` | datetime | Дата создания | | `dateModify` | datetime | Дата последнего изменения | URL сайта в Битрикс24 строится из `id`: ``` https://.bitrix24.ru/sites/site// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": { "id": 173, "title": "Лендинг конференции", "code": "/conf-2026/", "type": "PAGE", "active": false, "domainId": 28, "createdById": 1, "dateCreate": "07.05.2026 12:14:08", "dateModify": "07.05.2026 12:14:08" } } ``` ## Пример ответа при ошибке 422 — некорректный код сайта: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Адрес сайта введен неверно. Вы можете использовать только следующие символы: \"a-z\", \"0-9\", \"-\", \".\"." } } ``` ## Ошибки | HTTP | `error.code` | Маркер в `error.message` | Описание | |------|--------------|--------------------------|---------| | 400 | `READONLY_FIELD` | `Field 'active' is read-only` | В теле передан `active` — поле только для чтения (Битрикс24 его не сохраняет). Уберите его из тела, сайт активируется публикацией в интерфейсе | | 422 | `BITRIX_ERROR` | `Не заполнено обязательное поле "Адрес сайта"` | Опущен ключ `code` — у сайта нет адреса. Передайте `code` с любым значением, можно пустым | | 422 | `BITRIX_ERROR` | `SLASH_IS_NOT_ALLOWED` | В `code` передан символ `/` — слеши в коде запрещены | | 422 | `BITRIX_ERROR` | `DOMAIN_IS_INCORRECT` | Адрес сайта введён неверно: разрешены только символы `a-z`, `0-9`, `-`, `.` | | 422 | `BITRIX_ERROR` | `DOMAIN_EXIST` | Указанный домен уже занят другим сайтом | | 422 | `BITRIX_ERROR` | `DOMAIN_EXIST_TRASH` | Домен привязан к сайту в корзине — сначала отвяжите его | | 422 | `BITRIX_ERROR` | `DOMAIN_NOT_FOUND` | Домен с указанным `domainId` не существует | | 422 | `BITRIX_ERROR` | `SITE_LIMIT_REACHED` | Достигнут лимит количества сайтов на текущем тарифе | | 403 | `BITRIX_ACCESS_DENIED` | `Доступ на создание сайта запрещён` | У пользователя нет права на создание сайтов — ИЛИ создаётся `type: "KNOWLEDGE"` без `scope: "KNOWLEDGE"` (добавьте `scope`, см. таблицу полей) | | 403 | `SCOPE_DENIED` | — | API-ключ не имеет скоупа `landing` | | 401 | `TOKEN_MISSING` | — | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Слеши в ответе.** Поле `code` в ответе возвращается с обрамляющими слешами (`/conf-2026/`) — это представление пути сайта в URL. В запросе слеши передавать нельзя. **Ключ `code` обязателен.** Значение `code` может быть пустой строкой `""` или `null` — тогда код генерируется из `title`. Но если опустить сам ключ `code`, создание возвращает `422 BITRIX_ERROR` с сообщением `Не заполнено обязательное поле "Адрес сайта"`. Если `domainId` не передан, адрес формируется из `code` на `bitrix24site.ru`, например `b24-xxxxx.bitrix24site.ru`. **Активность не задаётся через API.** Поле `active` только для чтения: Битрикс24 не сохраняет переданное значение ни при создании, ни при обновлении, поэтому запрос с ним отклоняется с `400 READONLY_FIELD` до вызова Битрикс24. Новый сайт всегда создаётся неактивным — `active: false` в ответе; активируется сайт публикацией в интерфейсе портала Битрикс24. **Главная страница и страницы ошибок.** Поля `landingIdIndex`, `landingId404`, `landingId503` при создании не задаются — страниц ещё нет. Назначьте их через [обновление](/docs/entities/sites/update) после создания страниц сайта. **База знаний 2.0.** Создаётся как сайт с `type: "KNOWLEDGE"` И `scope: "KNOWLEDGE"` — оба поля обязательны. Без `scope` сервер вернёт `403 BITRIX_ACCESS_DENIED`, потому что Битрикс24 создаёт сайты типа `KNOWLEDGE` только в разделе баз знаний (тот же `scope` доступен для списка, чтения, обновления и удаления — см. соответствующие методы). Достаточно скоупа `landing` у ключа. Отдельного скоупа для баз знаний не требуется. ## Смотрите также - [Список сайтов](/docs/entities/sites/list) - [Обновить сайт](/docs/entities/sites/update) - [Удалить сайт](/docs/entities/sites/delete) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Sites: Delete ## Удалить сайт `DELETE /v1/sites/:id` Удаляет сайт по идентификатору. **Удалить можно только пустой сайт** — без страниц (включая страницы в корзине). Если на сайте есть хотя бы одна страница, запрос вернёт ошибку. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор сайта | | `scope` | string | нет | Для сайта в разделе баз знаний передайте `scope: "KNOWLEDGE"` (то же значение, что при создании) — иначе сервер вернёт `403 BITRIX_ACCESS_DENIED`. Можно как query-параметр `?scope=KNOWLEDGE` или поле тела. Для обычных сайтов не требуется | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/sites/173" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/sites/173" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/sites/173', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Сайт удалён') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/sites/173', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Сайт удалён') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — успех проверяется по статусу. ## Пример ответа ```http HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 422 — на сайте есть страницы: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Сайт содержит страницы." } } ``` ## Ошибки | HTTP | `error.code` | Маркер в `error.message` | Описание | |------|--------------|--------------------------|---------| | 422 | `BITRIX_ERROR` | `SITE_IS_NOT_EMPTY` | На сайте есть страницы (включая страницы в корзине) | | 422 | `BITRIX_ERROR` | `SITE_IS_LOCK` | Сайт заблокирован на удаление | | 403 | `BITRIX_ACCESS_DENIED` | — | У пользователя нет права на удаление этого сайта, либо сайт с таким ID не существует или недоступен — Битрикс24 отвечает «Доступ запрещён». При удалении `404` не возвращается, в отличие от `GET /v1/sites/:id` | | 403 | `BITRIX_ACCESS_DENIED` | `ACCESS_DENIED_DELETED` | На портале подключён доменный провайдер — удаление сайта через API недоступно, удалите через интерфейс портала | | 403 | `SCOPE_DENIED` | — | API-ключ не имеет скоупа `landing` | | 401 | `TOKEN_MISSING` | — | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Корзина не освобождает сайт.** Сайт нельзя удалить, пока на нём остаются страницы в корзине, — сначала очистите корзину страниц. ## Смотрите также - [Список страниц сайта](/docs/entities/pages) - [Список сайтов](/docs/entities/sites/list) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Sites: Fields ## Поля сайта `GET /v1/sites/fields` Возвращает карту всех полей сайта с типом, признаком только для чтения, подписью и описанием. Поля без признака только для чтения доступны для записи при создании и обновлении. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/sites/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/sites/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/sites/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data.fields).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/sites/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа Объект `data` содержит карту `fields`, список `aggregatable` с полями, по которым доступна группировка в [агрегации](./aggregate.md), и список `batch` с операциями, доступными в массовом режиме. Каждое поле карты `fields` описано ключами `type`, `readonly`, подписью `label` и описанием `description` — подпись и описание приходят у всех 22 полей. У поля `type` приходит дополнительно перечень допустимых значений `enum` — каждое значение с английской подписью `label` и русской `labelRu`. Ключ `nullable: true` стоит у восьми полей, у которых значение может отсутствовать: `description`, `xmlId`, `landingIdIndex`, `landingId404`, `landingId503`, `tplCode`, `smnSiteId`, `lang`. Как выглядит отсутствующее значение у каждого из них — в таблице ниже. | Поле | Битрикс24 | Тип | RO | Описание | |------|----------|-----|:--:|---------| | `id` | `ID` | number | да | Идентификатор сайта | | `title` | `TITLE` | string | | Название, до 255 символов | | `code` | `CODE` | string | | Символьный код в URL | | `type` | `TYPE` | string | | Тип сайта: `PAGE`, `STORE`, `KNOWLEDGE` — создаваемые через API. В ответах встречаются также `VIBE` и `SMN` | | `active` | `ACTIVE` | boolean | да | Активен ли сайт. Только для чтения: Битрикс24 не сохраняет значение ни при создании, ни при обновлении, поэтому передача поля отклоняется с `400 READONLY_FIELD`. Активность включается публикацией сайта в интерфейсе | | `domainId` | `DOMAIN_ID` | number | | Идентификатор домена | | `description` | `DESCRIPTION` | string \| null | | Описание, до 255 символов. `null`, если не задано | | `xmlId` | `XML_ID` | string \| null | | Внешний идентификатор. `null`, если не задан | | `landingIdIndex` | `LANDING_ID_INDEX` | number \| null | | Главная страница. Задаётся в обновлении после создания страниц | | `landingId404` | `LANDING_ID_404` | number \| null | | Страница ошибки 404. Если не назначена — `0` или `null` | | `landingId503` | `LANDING_ID_503` | number \| null | | Страница ошибки 503. Если не назначена — `0` или `null` | | `deleted` | `DELETED` | string | да | Признак корзины: `"Y"` / `"N"` | | `createdById` | `CREATED_BY_ID` | number | да | Создатель. Поиск: `GET /v1/users` | | `modifiedById` | `MODIFIED_BY_ID` | number | да | Последний редактор. Поиск: `GET /v1/users` | | `dateCreate` | `DATE_CREATE` | datetime | да | Дата создания. Формат локали Битрикс24, не ISO 8601 | | `dateModify` | `DATE_MODIFY` | datetime | да | Дата последнего изменения. Формат локали Битрикс24 | | `tplId` | `TPL_ID` | number | да | Идентификатор шаблона сайта | | `tplCode` | `TPL_CODE` | string \| null | да | Символьный код шаблона. `null`, если у шаблона нет кода | | `smnSiteId` | `SMN_SITE_ID` | string \| null | да | Связанный сайт «Управление сайтом» типа `SMN`. `null` у обычных сайтов | | `lang` | `LANG` | string \| null | да | Код языка, например `ru`. `null`, если не задан | | `special` | `SPECIAL` | string | да | Служебный признак Битрикс24: `"Y"` / `"N"` | | `version` | `VERSION` | number | да | Версия внутренней структуры сайта | ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "Идентификатор сайта", "description": "Уникальный числовой идентификатор сайта." }, "title": { "type": "string", "readonly": false, "label": "Название", "description": "Название сайта, до 255 символов. Обязательно при создании." }, "type": { "type": "string", "readonly": false, "label": "Тип сайта", "description": "Тип сайта. PAGE/STORE/KNOWLEDGE создаются через API (для KNOWLEDGE при создании и изменении нужен scope: \"KNOWLEDGE\"). VIBE (сайт из конструктора) и SMN (связка с модулем «Управление сайтом») встречаются только в ответах и доступны только для чтения.", "enum": [ { "value": "PAGE", "label": "Landing", "labelRu": "Лендинг" }, { "value": "STORE", "label": "Online store", "labelRu": "Интернет-магазин" }, { "value": "KNOWLEDGE", "label": "Knowledge base 2.0", "labelRu": "База знаний 2.0" }, { "value": "VIBE", "label": "Constructor site (read-only)", "labelRu": "Сайт из конструктора (только для чтения)" }, { "value": "SMN", "label": "Site Management link (read-only)", "labelRu": "Связка с «Управлением сайтом» (только для чтения)" } ] }, "active": { "type": "boolean", "readonly": true, "label": "Активен", "description": "Активен ли сайт. Только для чтения: Битрикс24 не сохраняет значение ни при создании, ни при обновлении — landing.site.add и landing.site.update поле не объявляют, новый сайт всегда создаётся неактивным, а живая проверка обоих вызовов вернула успех при выключенном признаке. Активность включается публикацией сайта в интерфейсе Битрикс24." }, "description": { "type": "string", "readonly": false, "nullable": true, "label": "Описание", "description": "Описание сайта, до 255 символов. Если не задано, в ответе приходит null." } }, "aggregatable": ["type", "active", "deleted", "lang", "tplId", "domainId", "createdById", "modifiedById"], "batch": ["create", "update", "delete"] } } ``` Показаны 5 из 22 полей. Полный список — в таблице выше. ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'landing' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `landing` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать сайт](/docs/entities/sites/create) - [Обновить сайт](/docs/entities/sites/update) - [Сайты](/docs/entities/sites) - [Entity API](/docs/entity-api) --- # Sites: Get ## Получить сайт `GET /v1/sites/:id` Возвращает один сайт по идентификатору. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор сайта | | `scope` (query) | string | нет | Внутренняя область лендингов: `KNOWLEDGE` / `GROUP` / `MAINPAGE`. Указывайте, если сайт принадлежит соответствующей области. Иначе возвращается `404 ENTITY_NOT_FOUND`. Пример: `GET /v1/sites/42?scope=KNOWLEDGE` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/sites/157" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/sites/157" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/sites/157', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Сайт:', data.title, '—', data.type) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/sites/157', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа Возвращается полный объект сайта со всеми полями — см. [Поля сайта](/docs/entities/sites/fields). > **Формат дат — локаль-зависимый, не ISO 8601.** `dateCreate` / `dateModify` приходят строкой в локальном формате портала: на RU-локали `ДД.ММ.ГГГГ ЧЧ:ММ:СС` (`30.12.2021 12:30:52`), на EN-локали `MM/DD/YYYY hh:mm:ss am/pm` (`04/22/2020 02:39:17 pm`). Значение возвращается как есть — `new Date(value)` даст `Invalid Date` либо перепутает день и месяц. ## Пример ответа ```json { "success": true, "data": { "id": 157, "title": "Промо-лендинг", "code": "/promo/", "type": "PAGE", "active": true, "domainId": 5, "createdById": 1, "dateCreate": "12.09.2024 10:23:14", "dateModify": "04.11.2025 08:51:20" } } ``` ## Пример ответа при ошибке 404 — сайт не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "site 999999999 not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Сайт с таким ID не найден или недоступен пользователю | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `landing` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список сайтов](/docs/entities/sites/list) - [Обновить сайт](/docs/entities/sites/update) - [Удалить сайт](/docs/entities/sites/delete) - [Лимиты и оптимизация](/docs/optimization) --- # Sites: List ## Список сайтов `GET /v1/sites` Возвращает список сайтов портала с поддержкой фильтрации и авто-пагинации. По умолчанию возвращаются только не удалённые сайты — для получения сайтов из корзины передайте `filter[deleted]=Y`. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей | | `select` | string | — | Выборка полей: `?select=id,title,type` | | `filter` | object | — | Фильтрация по ключевым полям сайта.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[type]=PAGE` | | `scope` | string | — | Внутренняя область лендингов. Допустимые значения: `KNOWLEDGE` (база знаний), `GROUP` (страницы рабочих групп), `MAINPAGE` (главные страницы). Без параметра возвращаются обычные сайты-лендинги. Принимается как `?scope=KNOWLEDGE` или `?filter[scope]=KNOWLEDGE` — обе формы дают одинаковый запрос к Битрикс24 | > **Фильтр по типу и область (`scope`).** Битрикс24 привязывает фильтр `filter[type]` к текущей области: в области по умолчанию доступны только типы `PAGE` / `STORE` / `SMN` / `VIBE`. Если вы фильтруете `filter[type]=KNOWLEDGE` или `filter[type]=GROUP` и **не** передали `scope`, Вайбкод сам подставит соответствующую область (`type=KNOWLEDGE` → `scope=KNOWLEDGE`) — фильтр по базам знаний и страницам групп работает без ручного указания `scope`. Явный `scope` всегда в приоритете. Если тип задан списком или оператором (`?filter[type][]=KNOWLEDGE&filter[type][]=PAGE`), где одну область выбрать нельзя, в `meta.warnings` придёт подсказка с кодом `TYPE_REQUIRES_SCOPE`. `MAINPAGE` — это область, а не тип сайта (её сайты имеют тип `VIBE`), поэтому из фильтра по типу не выводится: для главных страниц передавайте `scope=MAINPAGE` явно. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/sites?limit=10&filter[type]=PAGE" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/sites?limit=10&filter[type]=PAGE" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/sites?limit=10&filter[type]=PAGE', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} сайтов`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/sites?limit=10&filter[type]=PAGE', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив сайтов (каждая запись содержит ключевые поля сайта) | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.warnings` | array | Подсказки о применении запроса. Приходит, когда фильтр по типу задан списком или оператором — код `TYPE_REQUIRES_SCOPE` | URL любого сайта из массива `data` — его `id`: ``` https://.bitrix24.ru/sites/site// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 157, "title": "Промо-лендинг", "code": "/promo/", "type": "PAGE", "active": true, "domainId": 5, "createdById": 1, "dateCreate": "12.09.2024 10:23:14", "dateModify": "04.11.2025 08:51:20" }, { "id": 3, "title": "Каталог услуг", "code": "/services/", "type": "PAGE", "active": true, "domainId": 5, "createdById": 1, "dateCreate": "22.04.2020 14:39:17", "dateModify": "06.05.2024 15:43:34" } ], "meta": { "total": 25, "hasMore": true } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'landing' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `landing` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Видимость по правам пользователя.** В список попадают только сайты, к которым у владельца API-ключа есть право «просмотр». Если на портале есть сайты, но ответ пустой — проверьте права пользователя, под которым выпущен ключ. **Корзина.** Чтобы получить удалённые сайты, передайте `filter[deleted]=Y`. Значения — `Y` или `N`. **Постраничный переход через `offset` поддерживается.** Вайбкод возвращает запрошенное окно `[offset, offset + limit)`. Значение `meta.total` — точное число записей под фильтром, а `meta.hasMore` показывает, есть ли записи за пределами окна. **Сортировка.** Поддерживается через `?order[поле]=asc|desc` или короткую форму `?sort=-поле` (по убыванию). Без параметра выборка идёт по возрастанию `id`. **База знаний и другие внутренние области.** Параметр `scope` переключает источник: `KNOWLEDGE` — сайты базы знаний, `GROUP` — сайты внутри рабочих групп, `MAINPAGE` — главные страницы. Без параметра возвращаются обычные сайты-лендинги (источник по умолчанию). Пример: `GET /v1/sites?scope=KNOWLEDGE` возвращает сайты базы знаний и игнорирует обычные лендинги. ## Смотрите также - [Получить сайт](/docs/entities/sites/get) - [Поиск сайтов](/docs/entities/sites/search) - [Создать сайт](/docs/entities/sites/create) - [Синтаксис фильтрации](/docs/filtering) - [Entity API](/docs/entity-api) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Sites: Search ## Поиск сайтов `POST /v1/sites/search` Поиск сайтов с фильтрацией и авто-пагинацией. Аналогичен `GET /v1/sites` с фильтрами, но через POST — удобнее для сложных запросов с большим количеством условий. ## Поля запроса (body) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Фильтрация по ключевым полям сайта.
[Синтаксис фильтрации](/docs/filtering) | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки» | | `select` | string[] | — | Выборка полей: `["id", "title", "type"]` | | `autoWindow` | boolean | `true` | Разбивать выборку по недельным окнам при фильтре по диапазону дат шире 14 дней. `false` отключает разбиение | | `scope` | string | — | Внутренняя область лендингов: `KNOWLEDGE` / `GROUP` / `MAINPAGE`. Без параметра возвращаются обычные сайты-лендинги. Принимается на верхнем уровне тела (`"scope": "KNOWLEDGE"`) или внутри `filter.scope` — обе формы дают одинаковый запрос к Битрикс24 | > **Фильтр по типу и область (`scope`).** Битрикс24 привязывает `filter.type` к текущей области — в области по умолчанию доступны только `PAGE` / `STORE` / `SMN` / `VIBE`. Если фильтруете `{"filter": {"type": "KNOWLEDGE"}}` или `"GROUP"` и **не** передали `scope`, Вайбкод сам подставит соответствующую область (`type=KNOWLEDGE` → `scope=KNOWLEDGE`), и поиск вернёт именно базы знаний / страницы групп. Явный `scope` в приоритете. Если тип задан списком/оператором (`{"type": {"$in": ["KNOWLEDGE", "PAGE"]}}`), где одну область выбрать нельзя, в `meta.warnings` придёт подсказка с кодом `TYPE_REQUIRES_SCOPE`. `MAINPAGE` — область, а не тип сайта (её сайты имеют тип `VIBE`), поэтому из фильтра не выводится. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/sites/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "type": "PAGE", "active": true }, "limit": 10, "select": ["id", "title", "type", "active"] }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/sites/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "type": "PAGE", "active": true }, "limit": 10, "select": ["id", "title", "type", "active"] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/sites/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { type: 'PAGE', active: true }, limit: 10, select: ['id', 'title', 'type', 'active'], }), }) const { success, data, meta } = await res.json() console.log('Найдено:', meta.total) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/sites/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { type: 'PAGE', active: true }, limit: 10, select: ['id', 'title', 'type', 'active'], }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив сайтов с ключевыми полями | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временны́м окнам | | `meta.windowCount` | number | Число окон. Приходит при `autoWindowed: true` | | `meta.batchWaves` | number | Число волн параллельных запросов. Приходит при `autoWindowed: true` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. URL любого сайта из массива `data` — его `id`: ``` https://.bitrix24.ru/sites/site// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 157, "title": "Промо-лендинг", "code": "/promo/", "type": "PAGE", "active": true, "domainId": 5, "createdById": 1, "dateCreate": "12.09.2024 10:23:14", "dateModify": "04.11.2025 08:51:20" } ], "meta": { "total": 10, "hasMore": false, "durationMs": 99 } } ``` С фильтром по диапазону дат шире 14 дней в `meta` дополнительно приходят `autoWindowed`, `windowCount` и `batchWaves`: ```json { "success": true, "data": [ /* ... */ ], "meta": { "total": 2, "hasMore": false, "autoWindowed": true, "windowCount": 339, "batchWaves": 4, "durationMs": 3136 } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'landing' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `landing` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Разбиение по временны́м окнам.** Фильтр по диапазону дат шире 14 дней автоматически разбивается на недельные окна, которые выполняются параллельными волнами — так выборка обходит потолок в 5000 записей на один вызов. В `meta` тогда приходят `autoWindowed: true`, число окон `windowCount` и число волн `batchWaves`. Отключает разбиение параметр `autoWindow: false`. При активном разбиении `offset` больше нуля отклоняется с `UNSTABLE_OFFSET_PAGINATION`. **Видимость по правам пользователя.** Поиск возвращает только те сайты, к которым у владельца API-ключа есть право «просмотр». Если ожидается результат, но `data` пустой — проверьте права пользователя. **Удалённые сайты.** По умолчанию исключаются. Чтобы включить их в результат, передайте `{"filter": {"deleted": "Y"}}`. Значения — `Y` или `N`. **Постраничный переход через `offset` поддерживается.** Вайбкод возвращает запрошенное окно `[offset, offset + limit)`. Значение `meta.total` — точное число записей под фильтром, а `meta.hasMore` показывает, есть ли записи за пределами окна. **Сортировка.** Поле `sort` в теле: `{"sort": "-id"}` — по убыванию, `{"sort": "id"}` — по возрастанию (принимается и алиас `order`). Без параметра — по возрастанию `id`. ## Смотрите также - [Список сайтов](/docs/entities/sites/list) - [Получить сайт](/docs/entities/sites/get) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Sites: Update ## Обновить сайт `PATCH /v1/sites/:id` Обновляет поля существующего сайта. Передавайте только изменяемые поля плоско в корне JSON — без обёртки `fields`. Поле `active` только для чтения: Битрикс24 переданное значение не сохраняет, поэтому запрос с ним отклоняется с `400 READONLY_FIELD` до вызова Битрикс24. Активность сайта включается публикацией в интерфейсе портала Битрикс24. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор сайта | | `scope` | string | нет | Для сайта в разделе баз знаний передайте `scope: "KNOWLEDGE"` (то же значение, что при создании) — иначе сервер вернёт `403 BITRIX_ACCESS_DENIED` («Доступ на изменение сайта запрещён»). Можно как поле тела или query-параметром `?scope=KNOWLEDGE`. Для обычных сайтов-лендингов не требуется | ## Поля для обновления (body) | Параметр | Тип | Описание | |----------|-----|---------| | `title` | string | Название сайта, до 255 символов | | `code` | string | Символьный код сайта в URL. Слеши запрещены. Если код состоит только из цифр, добавится префикс `site` | | `domainId` | number | Идентификатор домена | | `type` | string | Тип сайта: `PAGE`, `STORE` или `KNOWLEDGE` | | `description` | string | Описание сайта, до 255 символов | | `xmlId` | string | Внешний идентификатор, до 255 символов | | `landingIdIndex` | number | Идентификатор главной страницы сайта | | `landingId404` | number | Идентификатор страницы ошибки 404 | | `landingId503` | number | Идентификатор страницы ошибки 503 | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/sites/157" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Промо-лендинг — обновлено" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/sites/157" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Промо-лендинг — обновлено" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/sites/157', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Промо-лендинг — обновлено', }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/sites/157', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Промо-лендинг — обновлено', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | object | Обновлённый объект сайта со всеми ключевыми полями | ## Пример ответа ```json { "success": true, "data": { "id": 157, "title": "Промо-лендинг — обновлено", "code": "/promo/", "type": "PAGE", "active": false, "domainId": 5, "createdById": 1, "dateCreate": "12.09.2024 10:23:14", "dateModify": "07.05.2026 12:18:42" } } ``` ## Пример ответа при ошибке 403 — нет прав на обновление этого сайта: ```json { "success": false, "error": { "code": "BITRIX_ACCESS_DENIED", "message": "Access denied" } } ``` ## Ошибки | HTTP | `error.code` | Маркер в `error.message` | Описание | |------|--------------|--------------------------|---------| | 400 | `READONLY_FIELD` | `Field 'active' is read-only` | В теле передан `active` — поле только для чтения. Уберите его из тела, активность включается публикацией в интерфейсе | | 403 | `BITRIX_ACCESS_DENIED` | — | Нет права на изменение сайта или указанных полей, либо сайт с таким ID не существует или недоступен — Битрикс24 отвечает «Доступ запрещён». При PATCH `404` не возвращается, в отличие от `GET /v1/sites/:id` | | 422 | `BITRIX_ERROR` | `SLASH_IS_NOT_ALLOWED` | В `code` передан символ `/` — слеши в коде запрещены | | 422 | `BITRIX_ERROR` | `DOMAIN_IS_INCORRECT` | Передан некорректный формат доменного имени | | 422 | `BITRIX_ERROR` | `DOMAIN_EXIST` | Указанный домен уже занят другим сайтом | | 422 | `BITRIX_ERROR` | `DOMAIN_EXIST_TRASH` | Домен привязан к сайту в корзине — сначала отвяжите его | | 422 | `BITRIX_ERROR` | `DOMAIN_NOT_FOUND` | Домен с указанным `domainId` не существует | | 422 | `BITRIX_ERROR` | `CODE_IS_NOT_UNIQUE` | Код сайта не уникален в рамках домена | | 403 | `SCOPE_DENIED` | — | API-ключ не имеет скоупа `landing` | | 401 | `TOKEN_MISSING` | — | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить сайт](/docs/entities/sites/get) - [Список сайтов](/docs/entities/sites/list) - [Удалить сайт](/docs/entities/sites/delete) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Smart Processes: Aggregate ## Агрегация типов смарт-процессов `POST /v1/smart-processes/aggregate` Подсчёт количества типов смарт-процессов по фильтру с опциональной группировкой. Считает, сколько типов на портале удовлетворяют условию, и разбивает их по значению выбранного поля — например, сколько типов создал каждый сотрудник или у скольких включена та или иная возможность. ## Поля для агрегации Группировка и числовые функции работают по полям из списка `aggregatable`: - `createdBy`, `updatedBy` — кто создал и кто последним изменил тип. Подходят для `groupBy`. - `customSectionId` — идентификатор цифрового рабочего места. Подходит для `groupBy`. - `isCategoriesEnabled`, `isStagesEnabled`, `isAutomationEnabled`, `isBizProcEnabled`, `isPaymentsEnabled`, `isCountersEnabled`, `isLinkWithProductsEnabled` — флаги возможностей. Основной сценарий для каталога типов — `count` (сколько типов под фильтр) и `groupBy` (разбивка по полю). У типов смарт-процессов нет пользовательских полей — агрегируются только перечисленные стандартные. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций. Каждый элемент: `{ "field": "*", "function": "count" }`. Функция `count` считает строки, а не значения поля. Функции: `count`, `sum`, `avg`, `min`, `max`. Без массива возвращается только `count` | | `filter` | object | нет | Фильтрация по полям типа. Список полей: [Поля типа](/docs/entities/smart-processes/fields). [Синтаксис фильтрации](/docs/filtering) | | `groupBy` | string \| string[] | нет | Поле или массив полей для группировки (максимум 5). Принимает только поля из списка `aggregatable` выше | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/smart-processes/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "isStagesEnabled": true }, "groupBy": "createdBy" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/smart-processes/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "isStagesEnabled": true }, "groupBy": "createdBy" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/smart-processes/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { isStagesEnabled: true }, groupBy: 'createdBy', }), }) const { success, data } = await res.json() console.log('Всего типов:', data.count) console.log('По создателям:', data.groups) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/smart-processes/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { isStagesEnabled: true }, groupBy: 'createdBy', }), }) const { success, data } = await res.json() ``` > Для группировки по нескольким полям передайте массив: `"groupBy": ["createdBy", "isStagesEnabled"]` (максимум 5). ## Другие сценарии Подсчёт записей — `count` с полем `"*"`, самый быстрый запрос без выгрузки записей. Без массива `aggregate` результат тот же: ```json { "aggregate": [{ "field": "*", "function": "count" }] } ``` Сколько типов с включёнными роботами и триггерами: ```json { "filter": { "isAutomationEnabled": true } } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Количество типов, соответствующих фильтру | | `data.aggregates` | object | Результаты числовых функций. Для группировки по `count` — пустой объект | | `data.groups` | array | Группы (только при `groupBy`). Каждый элемент: поле группировки + `count` + `aggregates` | | `data.meta.totalRecords` | number | Общее количество типов под фильтр | | `data.meta.recordsProcessed` | number | Сколько типов обработано для агрегации | | `data.meta.truncated` | boolean | `true`, если под фильтр попало больше 5000 типов | | `data.meta.groupTotal` | number | Количество групп (только при `groupBy`) | | `data.meta.groupsTruncated` | boolean | `true`, если список групп был усечён | ## Пример ответа Группировка по создателю (`groupBy: "createdBy"`): ```json { "success": true, "data": { "count": 7, "aggregates": {}, "groups": [ { "createdBy": 1, "count": 4, "aggregates": {} }, { "createdBy": 835, "count": 2, "aggregates": {} }, { "createdBy": 1013, "count": 1, "aggregates": {} } ], "meta": { "totalRecords": 7, "recordsProcessed": 7, "truncated": false, "groupTotal": 3, "groupsTruncated": false } } } ``` Без `groupBy` поле `data.groups` в ответе отсутствует. ## Пример ответа при ошибке 400 — поле недоступно для группировки: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "groupBy field 'title' is not aggregatable on this entity. Available: customSectionId, createdBy, updatedBy, isCategoriesEnabled, isStagesEnabled, isAutomationEnabled, isBizProcEnabled, isPaymentsEnabled, isCountersEnabled, isLinkWithProductsEnabled." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Неизвестная функция, несуществующее поле или поле вне списка `aggregatable` — сообщение перечисляет доступные поля | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`count` считается одним вызовом.** Запрос без массива `aggregate` возвращает количество типов под фильтр одним обращением к Битрикс24, не выгружая записи. **Группировка по флагу даёт две группы — `true` и `false`.** Например, `groupBy: "isAutomationEnabled"` разделит типы на две группы: с включёнными роботами и без них. Если все типы имеют одинаковое значение флага, в ответе будет одна группа. ## Смотрите также - [Список типов](/docs/entities/smart-processes/list) - [Поиск типов](/docs/entities/smart-processes/search) - [Поля типа](/docs/entities/smart-processes/fields) - [Агрегация элементов](/docs/entities/items/aggregate) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Smart Processes: Create ## Создать тип смарт-процесса `POST /v1/smart-processes` Создаёт новый тип смарт-процесса с автоматически назначенным `entityTypeId`. После создания тип доступен в `/v1/items/:entityTypeId` для CRUD операций по элементам. ## Поля запроса (body) | Поле | Тип | Обяз. | По умолч. | Описание | |------|-----|:-----:|:---------:|---------| | `title` | string | **да** | — | Название смарт-процесса | | `isCategoriesEnabled` | boolean | | `false` | Использовать в смарт-процессе свои воронки и туннели продаж | | `isStagesEnabled` | boolean | | `false` | Использовать в смарт-процессе свои стадии и канбан | | `isBeginCloseDatesEnabled` | boolean | | `false` | Поля «Дата начала» и «Дата завершения» | | `isClientEnabled` | boolean | | `false` | Поле «Клиент» с привязкой к контактам и компаниям | | `isLinkWithProductsEnabled` | boolean | | `false` | Привязка товаров каталога | | `isMycompanyEnabled` | boolean | | `false` | Поле «Реквизиты вашей компании» | | `isObserversEnabled` | boolean | | `false` | Поле «Наблюдатели» | | `isSourceEnabled` | boolean | | `false` | Поля «Источник» и «Дополнительно об источнике» | | `isAutomationEnabled` | boolean | | `false` | Роботы и триггеры | | `isBizProcEnabled` | boolean | | `false` | Дизайнер бизнес-процессов | | `isDocumentsEnabled` | boolean | | `false` | Печать документов | | `isRecyclebinEnabled` | boolean | | `false` | Использование корзины | | `isSetOpenPermissions` | boolean | | **`true`** | Делать новые воронки доступными для всех | | `isUseInUserfieldEnabled` | boolean | | `false` | Использовать смарт-процесс в пользовательском поле | | `isRecurringEnabled` | boolean | | `false` | Поле «Регулярность» | | `isPaymentsEnabled` | boolean | | `false` | Онлайн-оплата | | `isCountersEnabled` | boolean | | `false` | Счётчики (уведомления и бейджи) | | `relations` | object | | `{}` | Связи с другими сущностями CRM — см. «Связи и пользовательские поля» ниже | | `linkedUserFields` | object | | `{}` | Набор пользовательских полей, в которых будет отображаться смарт-процесс — см. «Связи и пользовательские поля» ниже | Полный список полей: [GET /v1/smart-processes/fields](/docs/entities/smart-processes/fields). ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/smart-processes \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Договоры поставки", "isStagesEnabled": true, "isCategoriesEnabled": true, "isAutomationEnabled": true, "isBizProcEnabled": true, "isLinkWithProductsEnabled": true }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/smart-processes \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Договоры поставки", "isStagesEnabled": true, "isCategoriesEnabled": true, "isAutomationEnabled": true, "isBizProcEnabled": true, "isLinkWithProductsEnabled": true }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/smart-processes', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Договоры поставки', isStagesEnabled: true, isCategoriesEnabled: true, isAutomationEnabled: true, isBizProcEnabled: true, isLinkWithProductsEnabled: true, }), }) const { success, data } = await res.json() console.log('Создан тип, entityTypeId:', data.entityTypeId) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/smart-processes', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Договоры поставки', isStagesEnabled: true, isCategoriesEnabled: true, isAutomationEnabled: true, isBizProcEnabled: true, isLinkWithProductsEnabled: true, }), }) const { success, data } = await res.json() ``` ## Связи и пользовательские поля Поля `relations` и `linkedUserFields` не описаны в `/fields`, но принимаются при создании и сохраняются Битрикс24. ### `relations` — связи с сущностями CRM Объект с двумя массивами: `parent` (родительские типы) и `child` (дочерние типы). ```json { "title": "Договоры поставки", "relations": { "parent": [ { "entityTypeId": 2, "isChildrenListEnabled": "Y" } ], "child": [ { "entityTypeId": 3, "isChildrenListEnabled": "Y" } ] } } ``` | Поле записи | Тип | Описание | |---|---|---| | `entityTypeId` | number | ID связанного типа (2 = сделки, 3 = контакты, 4 = компании, 7 = коммерческие предложения, 31 = счета, 1030+ = смарт-процессы) | | `isChildrenListEnabled` | boolean / string | Отображать ли список записей этого смарт-процесса в карточке связанного типа | > **Формат `isChildrenListEnabled`.** Поле принимает булево `true`/`false`, строки `"Y"`/`"N"` или `"true"`/`"false"` — значение нормализуется автоматически (`true`/`"Y"`/`"yes"`/`1` → включено, `false`/`"N"`/`"no"`/`0` → выключено). В ответе флаг всегда возвращается как `"Y"`/`"N"`. **Побочный эффект от `isClientEnabled: true`:** Битрикс24 автоматически добавит в `relations.parent` связи с контактами (`entityTypeId: 3`) и компаниями (`entityTypeId: 4`) с флагом `isPredefined: "Y"` — передавать их вручную не нужно. ### `linkedUserFields` — отображение в пользовательских полях Объект, где ключ — идентификатор поля из другой сущности в формате `{ENTITY_CODE}|{FIELD_NAME}`, значение — включить (`true`) или выключить (`false`) отображение. > **Формат значения.** Поле принимает булево `true`/`false`, строки `"Y"`/`"N"` или `"true"`/`"false"` — значение нормализуется автоматически (`true`/`"Y"`/`"yes"`/`1` → включено, `false`/`"N"`/`"no"`/`0` → выключено). В ответе флаг всегда возвращается как `"Y"`/`"N"`. ```json { "title": "Договоры поставки", "linkedUserFields": { "TASKS_TASK|UF_CRM_TASK": "Y", "TASKS_TASK_TEMPLATE|UF_CRM_TASK": "Y", "CALENDAR_EVENT|UF_CRM_CAL_EVENT": "Y" } } ``` Поддерживаются 3 фиксированных ключа: | Ключ | Где отобразится смарт-процесс | |------|------------------------------| | `TASKS_TASK\|UF_CRM_TASK` | Поле «Элемент CRM» в задачах | | `TASKS_TASK_TEMPLATE\|UF_CRM_TASK` | Поле «Элемент CRM» в шаблонах задач | | `CALENDAR_EVENT\|UF_CRM_CAL_EVENT` | Поле «Элемент CRM» в событиях календаря | ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Внутренний ID записи типа | | `entityTypeId` | number | **Назначенный `entityTypeId`** — используется в `/v1/items/:entityTypeId` | | `title` | string | Название | | `createdBy` | number | Создатель | | `updatedBy` | number | Последний редактор | | `createdTime` | datetime | Дата создания | | `updatedTime` | datetime | Дата изменения | | `customSectionId` | number \| null | ID цифрового рабочего места, если привязан | Плюс все `isXxxEnabled` флаги в том состоянии, которое было передано (или `false` по умолчанию). Полный список — [Поля типа](/docs/entities/smart-processes/fields). Список элементов созданного типа открывается в Битрикс24 по `entityTypeId`: ``` https://.bitrix24.ru/crm/type//list/category/0/ ``` `0` — основная воронка. `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": { "id": 31, "entityTypeId": 1050, "title": "Договоры поставки", "createdBy": 1, "createdTime": "2026-04-21T13:46:45+03:00", "updatedTime": "2026-04-21T13:46:45+03:00", "updatedBy": 1, "customSectionId": null, "isCategoriesEnabled": true, "isStagesEnabled": true, "isBeginCloseDatesEnabled": false, "isClientEnabled": false, "isLinkWithProductsEnabled": true, "isMycompanyEnabled": false, "isObserversEnabled": false, "isSourceEnabled": false, "isAutomationEnabled": true, "isBizProcEnabled": true, "isDocumentsEnabled": false, "isRecyclebinEnabled": false, "isSetOpenPermissions": true, "isUseInUserfieldEnabled": false, "isRecurringEnabled": false, "isPaymentsEnabled": false, "isCountersEnabled": false, "isInitialized": false } } ``` ## Пример ответа при ошибке 422 — не передано обязательное поле: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Не заполнено обязательное поле \"Название\"" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `MISSING_API_KEY` | Заголовок `X-Api-Key` не передан | | 401 | `INVALID_API_KEY` | Ключ не найден или отозван | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 400 | `READONLY_FIELD` | В теле передано поле только для чтения (`id`, `isInitialized`, `createdTime` и другие) | | 422 | `BITRIX_ERROR` | Любая ошибка от Битрикс24: не передано `title`, `entityTypeId` вне диапазона, превышен лимит смарт-процессов на портале и т. д. Конкретная причина — в поле `message` | Типичные сообщения в `message` при `BITRIX_ERROR`: - `Не заполнено обязательное поле "Название"` — пропущен `title` - `EntityTypeId should be more or equal than 128 and less than 192` — передан `entityTypeId` вне диапазона - `Превышено максимальное количество смарт-процессов` — достигнут лимит портала Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Авто-генерация `entityTypeId`.** Битрикс24 сам назначает свободный идентификатор. Если вы хотите передать собственный, значение должно быть **уникальным** и попадать в один из диапазонов: от `128` до `191` (`≥ 128` и `< 192`), либо чётное число `≥ 1030`. Значение возвращается в поле `entityTypeId` ответа — сохраните его и используйте во всех запросах к типу и его элементам. **После создания `isInitialized: false`.** Битрикс24 ещё не сгенерировал стандартные стадии и воронки. Они создаются при первом обращении к типу в интерфейсе или программно — через `/v1/statuses` и `/v1/categories/:entityTypeId`. **`relations` двунаправленные.** Если вы указали `parent: [{entityTypeId: 2, ...}]`, то в сделках (тип 2) в поле `relations.child` автоматически появится ссылка на ваш новый тип с флагом `isPredefined: "N"` (пользовательская связь). **`isSetOpenPermissions` по умолчанию `true`** — это единственный флаг с положительным дефолтом. Если нужны приватные воронки, передавайте `false` явно. ## Смотрите также - [Обновить тип](/docs/entities/smart-processes/update) - [Удалить тип](/docs/entities/smart-processes/delete) - [Список типов](/docs/entities/smart-processes/list) - [Поля типа](/docs/entities/smart-processes/fields) - [Элементы смарт-процессов](/docs/entities/items) - [Стадии и воронки](/docs/entities/categories) - [Лимиты и оптимизация](/docs/optimization) --- # Smart Processes: Delete ## Удалить тип смарт-процесса `DELETE /v1/smart-processes/:entityTypeId` Удаляет тип смарт-процесса по `entityTypeId`. Вместе с типом удаляются все связанные с ним метаданные: воронки, стадии, права доступа, настройки бизнес-процессов. **Удалить можно только тип, у которого нет элементов.** Если в типе есть хотя бы один элемент — сначала удалите элементы через `DELETE /v1/items/:entityTypeId/:id` или перенесите их в другой тип. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `entityTypeId` (path) | number | **да** | ID типа сущности. Список: `GET /v1/smart-processes` | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/smart-processes/1050" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/smart-processes/1050" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/smart-processes/1050', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Тип удалён') } else { const { error } = await res.json() console.error('Ошибка:', error.code, error.message) } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/smart-processes/1050', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Тип удалён') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — тип не найден: ```json { "success": false, "error": { "code": "SMART_PROCESS_NOT_FOUND", "message": "Smart process with entityTypeId=99999 not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `MISSING_API_KEY` | Заголовок `X-Api-Key` не передан | | 401 | `INVALID_API_KEY` | Ключ не найден или отозван | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 400 | `INVALID_ENTITY_TYPE_ID` | `entityTypeId` не является положительным целым. Сообщение: `entityTypeId must be a positive integer` | | 404 | `SMART_PROCESS_NOT_FOUND` | Тип с таким `entityTypeId` не найден. Сообщение: `Smart process with entityTypeId=X not found` | | 422 | `BITRIX_ERROR` | В типе есть элементы (сообщение: `Вы не можете удалить тип сущности, у которого есть элементы`) или другая ошибка от Битрикс24 | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Удаление необратимо.** Нет корзины и отката — удалённый тип восстановить нельзя. Связанные метаданные (воронки, стадии, права) удаляются вместе с типом. **Перед удалением проверьте количество элементов.** Если есть сомнения, получите количество: ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/items/1050/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"count": true}' ``` Если `count > 0` — сначала удалите элементы или перенесите в другой тип. **`entityTypeId` не переиспользуется.** После удаления Битрикс24 не выдаст этот же `entityTypeId` новому типу — при следующем создании вы получите новое значение из диапазона `≥ 1030`. **Связи в других типах остаются.** Если другой тип ссылается на удалённый через `relations.parent` или `relations.child`, связь в его настройках сохранится, но станет «висячей». Настройте связи в оставшихся типах после удаления. ## Смотрите также - [Список типов](/docs/entities/smart-processes/list) - [Получить тип](/docs/entities/smart-processes/get) - [Обновить тип](/docs/entities/smart-processes/update) - [Агрегация элементов](/docs/entities/items/aggregate) - [Удалить элемент](/docs/entities/items) - [Лимиты и оптимизация](/docs/optimization) --- # Smart Processes: Fields ## Поля типа смарт-процесса `GET /v1/smart-processes/fields` Возвращает описание полей типа смарт-процесса: какие можно передавать при создании и обновлении, какие доступны только на чтение. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/smart-processes/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/smart-processes/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/smart-processes/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data.fields).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/smart-processes/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | RO | Описание | |------|-----|:--:|---------| | `id` | number | да | Внутренний ID записи типа | | `entityTypeId` | number | | ID типа сущности. Передаётся в `/v1/items/:entityTypeId` для работы с элементами. Если не передан при создании — Битрикс24 назначает свободное значение автоматически | | `title` | string | | Название типа смарт-процесса | | `code` | string \| null | | Символьный код типа (для программной идентификации). `null`, если не задан | | `customSectionId` | number \| null | | ID цифрового рабочего места, к которому привязан тип. `null`, если не привязан. Записывается при создании, но не обновляется | | `isCategoriesEnabled` | boolean | | Использовать в смарт-процессе свои воронки и туннели продаж | | `isStagesEnabled` | boolean | | Использовать в смарт-процессе свои стадии и канбан | | `isBeginCloseDatesEnabled` | boolean | | Поля «Дата начала» и «Дата завершения» | | `isClientEnabled` | boolean | | Поле «Клиент» с привязкой к контактам и компаниям | | `isLinkWithProductsEnabled` | boolean | | Привязка товаров каталога | | `isMycompanyEnabled` | boolean | | Поле «Реквизиты вашей компании» | | `isObserversEnabled` | boolean | | Поле «Наблюдатели» | | `isSourceEnabled` | boolean | | Поля «Источник» и «Дополнительно об источнике» | | `isAutomationEnabled` | boolean | | Роботы и триггеры | | `isBizProcEnabled` | boolean | | Дизайнер бизнес-процессов | | `isDocumentsEnabled` | boolean | | Печать документов | | `isRecyclebinEnabled` | boolean | | Использование корзины | | `isSetOpenPermissions` | boolean | | Делать новые воронки доступными для всех | | `isUseInUserfieldEnabled` | boolean | | Использовать смарт-процесс в пользовательском поле | | `isRecurringEnabled` | boolean | | Поле «Регулярность» | | `isPaymentsEnabled` | boolean | | Онлайн-оплата | | `isCountersEnabled` | boolean | | Счётчики (уведомления и бейджи) | | `isInitialized` | boolean | да | Тип полностью инициализирован в портале | | `createdBy` | number | да | Кем создан. Поиск: `GET /v1/users` | | `updatedBy` | number | да | Кем изменён. Поиск: `GET /v1/users` | | `createdTime` | datetime | да | Дата создания | | `updatedTime` | datetime | да | Дата изменения | Ответ также содержит массив `aggregatable` — поля, по которым доступна группировка в [агрегации](/docs/entities/smart-processes/aggregate), и массив `batch` со списком операций, доступных для пакетной обработки: `create`, `update`, `delete`. > **Формат datetime.** `createdTime`/`updatedTime` приходят в ISO 8601, но конкретное представление (со смещением `+03:00` либо UTC `…Z` с миллисекундами) зависит от портала — парсьте как ISO 8601, не сравнивайте строки побайтно. ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "Внутренний ID", "description": "Внутренний числовой идентификатор записи типа смарт-процесса." }, "entityTypeId": { "type": "number", "readonly": false, "label": "ID типа сущности", "description": "Идентификатор типа смарт-процесса, используемый в /v1/items/:entityTypeId; назначается автоматически, если не передан при создании." }, "title": { "type": "string", "readonly": false, "label": "Название", "description": "Название типа смарт-процесса, отображаемое в интерфейсе Битрикс24." }, "isCategoriesEnabled": { "type": "boolean", "readonly": false, "label": "Свои воронки", "description": "Включает собственные воронки и туннели продаж." }, "isStagesEnabled": { "type": "boolean", "readonly": false, "label": "Свои стадии и канбан", "description": "Включает собственные стадии и канбан-доску." }, "isLinkWithProductsEnabled": { "type": "boolean", "readonly": false, "label": "Привязка товаров", "description": "Включает привязку товаров каталога к элементам." }, "code": { "type": "string", "readonly": false, "label": "Символьный код", "description": "Символьный код типа смарт-процесса; может отсутствовать (null)." }, "createdBy": { "type": "number", "readonly": true, "label": "Кем создан", "description": "ID пользователя, создавшего тип смарт-процесса." }, "customSectionId": { "type": "number", "readonly": false, "label": "Цифровое рабочее место", "description": "ID цифрового рабочего места, к которому привязан тип; задаётся только при создании и не обновляется." }, "createdTime": { "type": "datetime", "readonly": true, "label": "Дата создания", "description": "Дата и время создания типа смарт-процесса." } }, "aggregatable": ["customSectionId", "createdBy", "updatedBy", "isCategoriesEnabled", "isStagesEnabled", "isAutomationEnabled", "isBizProcEnabled", "isPaymentsEnabled", "isCountersEnabled", "isLinkWithProductsEnabled"], "batch": ["create", "update", "delete"] } } ``` Показаны 10 полей из 27. Полный список — в таблице выше. ## Пример ответа при ошибке 401 — ключ не передан: ```json { "success": false, "error": { "code": "MISSING_API_KEY", "message": "API key required. Pass via X-Api-Key header." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `MISSING_API_KEY` | Заголовок `X-Api-Key` не передан | | 401 | `INVALID_API_KEY` | Ключ не найден или отозван | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Вложенные структуры.** При создании и обновлении можно передавать поля `relations` (связи с другими типами CRM) и `linkedUserFields` (связанные пользовательские поля). Они не описаны в ответе `/fields`, но принимаются и сохраняются Битрикс24 без изменений. Подробнее — в [Создать тип](/docs/entities/smart-processes/create). **Отличие от `GET /v1/{entity}/fields` у стандартных сущностей.** Этот эндпоинт описывает поля **типа смарт-процесса** (`crm.type.*`), а не элементов внутри него. Для полей элементов используйте `GET /v1/items/:entityTypeId/fields`. ## Смотрите также - [Список типов](/docs/entities/smart-processes/list) - [Создать тип](/docs/entities/smart-processes/create) - [Обновить тип](/docs/entities/smart-processes/update) - [Элементы смарт-процессов](/docs/entities/items) - [Поля элементов](/docs/entities/items/fields) - [Пользовательские поля](/docs/userfields) - [Лимиты и оптимизация](/docs/optimization) --- # Smart Processes: Get ## Получить тип смарт-процесса `GET /v1/smart-processes/:entityTypeId` Возвращает тип смарт-процесса по `entityTypeId`. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `entityTypeId` (path) | number | **да** | ID типа сущности. Список: `GET /v1/smart-processes` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/smart-processes/174" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/smart-processes/174" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/smart-processes/174', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Тип:', data.title, 'entityTypeId:', data.entityTypeId) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/smart-processes/174', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | object | Тип смарт-процесса. Полный список полей — см. [Поля типа](/docs/entities/smart-processes/fields) | ## Пример ответа ```json { "success": true, "data": { "id": 3, "entityTypeId": 174, "title": "Договоры", "code": null, "customSectionId": null, "isCategoriesEnabled": true, "isStagesEnabled": true, "isClientEnabled": true, "isLinkWithProductsEnabled": true, "isObserversEnabled": true, "isSourceEnabled": true, "isAutomationEnabled": true, "isBizProcEnabled": true, "isDocumentsEnabled": true, "isRecyclebinEnabled": true, "isSetOpenPermissions": true, "isUseInUserfieldEnabled": true, "createdBy": 1, "updatedBy": 1, "createdTime": "2021-07-20T16:04:10+03:00", "updatedTime": "2024-07-19T14:27:27+03:00" } } ``` > **Карточка возвращает больше полей, чем список и `/fields`.** В дополнение к полям выше `GET /v1/smart-processes/:entityTypeId` отдаёт `relations` (объект с массивами `parent`/`child`), `linkedUserFields` (map) и `customSections` (массив) — это сквозной проброс от Битрикс24 `crm.type.get`, которого нет ни в списке, ни в `/fields`. `relations`/`linkedUserFields` документированы как входные поля create/update. `customSections` — только в ответе карточки. > > **`id` ≠ ключ карточки.** В ответе есть внутренний `id` (напр. 3), но карточка адресуется по `entityTypeId` (напр. 174): `GET /v1/smart-processes/`. `GET /v1/smart-processes/` вернёт `404 ENTITY_NOT_FOUND` — не путайте поле `id` с ключом пути. ## Пример ответа при ошибке 404 — тип не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Смарт-процесс не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `MISSING_API_KEY` | Заголовок `X-Api-Key` не передан | | 401 | `INVALID_API_KEY` | Ключ не найден или отозван | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 404 | `ENTITY_NOT_FOUND` | Тип с таким `entityTypeId` не найден | | 422 | `BITRIX_ERROR` | Ошибка от Битрикс24. Конкретная причина — в поле `message` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список типов](/docs/entities/smart-processes/list) - [Создать тип](/docs/entities/smart-processes/create) - [Обновить тип](/docs/entities/smart-processes/update) - [Удалить тип](/docs/entities/smart-processes/delete) - [Поля типа](/docs/entities/smart-processes/fields) - [Элементы смарт-процессов](/docs/entities/items) - [Лимиты и оптимизация](/docs/optimization) --- # Smart Processes: List ## Список типов смарт-процессов `GET /v1/smart-processes` Возвращает типы смарт-процессов на портале. Каждый тип имеет `entityTypeId` — используйте его для работы с элементами через [/v1/items/:entityTypeId](/docs/entities/items). ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям. Пример: `?filter[isStagesEnabled]=true`. [Синтаксис фильтрации](/docs/filtering) | | `select` | string | — | Выборка полей: `?select=id,title,entityTypeId` | | `sort` | string | — | Сортировка по полю: `?sort=title` (по возрастанию), `?sort=-createdTime` (по убыванию) | | `limit` | number | — | Ограничить количество записей в ответе | Список полей для `filter` и `select` — [Поля типа](/docs/entities/smart-processes/fields). Для нескольких условий фильтрации одновременно используйте [Поиск типов](/docs/entities/smart-processes/search) — POST с телом запроса вместо строки запроса. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/smart-processes" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/smart-processes" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/smart-processes', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() for (const sp of data) { console.log(`${sp.title}: entityTypeId=${sp.entityTypeId}`) } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/smart-processes', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив типов смарт-процессов. Поля каждого типа — см. [Поля типа](/docs/entities/smart-processes/fields) | Список элементов любого типа из массива `data` открывается в Битрикс24 по `entityTypeId`: ``` https://.bitrix24.ru/crm/type//list/category/0/ ``` `0` — основная воронка. `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 3, "entityTypeId": 174, "title": "Договоры", "code": null, "customSectionId": null, "isCategoriesEnabled": true, "isStagesEnabled": true, "isClientEnabled": true, "isLinkWithProductsEnabled": true, "isObserversEnabled": true, "isSourceEnabled": true, "isAutomationEnabled": true, "isBizProcEnabled": true, "isDocumentsEnabled": true, "isRecyclebinEnabled": true, "isSetOpenPermissions": true, "isUseInUserfieldEnabled": true, "createdBy": 1, "updatedBy": 1, "createdTime": "2021-07-20T16:04:10+03:00", "updatedTime": "2024-07-19T14:27:27+03:00" } ] } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `MISSING_API_KEY` | Заголовок `X-Api-Key` не передан | | 401 | `INVALID_API_KEY` | Ключ не найден или отозван | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 422 | `BITRIX_ERROR` | Ошибка от Битрикс24. Конкретная причина — в поле `message` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`entityTypeId` — ключевое поле.** Сохраняйте его и передавайте в `/v1/items/:entityTypeId` для работы с элементами этого типа. **Пагинации нет.** Ответ содержит все типы смарт-процессов портала одним массивом. ## Смотрите также - [Создать тип](/docs/entities/smart-processes/create) - [Получить тип](/docs/entities/smart-processes/get) - [Поля типа](/docs/entities/smart-processes/fields) - [Поиск типов](/docs/entities/smart-processes/search) - [Элементы смарт-процессов](/docs/entities/items) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Smart Processes: Search ## Поиск типов смарт-процессов `POST /v1/smart-processes/search` Поиск типов смарт-процессов с фильтрами в теле POST-запроса. Применяется, когда условий фильтрации несколько и они не помещаются в строку запроса. ## Поля запроса (body) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | `{}` | Фильтрация по любым полям типа (`title`, `entityTypeId`, `isStagesEnabled`, `isClientEnabled`, `isAutomationEnabled` и т. д.). [Синтаксис фильтрации](/docs/filtering) | | `limit` | number | `50` | Количество записей в ответе | | `offset` | number | `0` | Пропустить N записей. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки» | | `autoWindow` | boolean | `true` | Разбивать выборку по недельным окнам при фильтре по диапазону дат шире 14 дней. `false` отключает разбиение | Полный список полей, по которым можно фильтровать: [Поля типа](/docs/entities/smart-processes/fields). ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/smart-processes/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "isClientEnabled": true, "isStagesEnabled": true }, "limit": 10 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/smart-processes/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "isClientEnabled": true, "isStagesEnabled": true }, "limit": 10 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/smart-processes/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { isClientEnabled: true, isStagesEnabled: true }, limit: 10, }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/smart-processes/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { isClientEnabled: true, isStagesEnabled: true }, limit: 10, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | array | Массив типов, удовлетворяющих фильтру. Поля каждого типа — см. [Поля типа](/docs/entities/smart-processes/fields) | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временны́м окнам | | `meta.windowCount` | number | Число окон. Приходит при `autoWindowed: true` | | `meta.batchWaves` | number | Число волн параллельных запросов. Приходит при `autoWindowed: true` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. Список элементов любого типа из массива `data` открывается в Битрикс24 по `entityTypeId`: ``` https://.bitrix24.ru/crm/type//list/category/0/ ``` `0` — основная воронка. `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 3, "entityTypeId": 174, "title": "Договоры", "isStagesEnabled": true, "isClientEnabled": true, "isCategoriesEnabled": true, "isLinkWithProductsEnabled": true } ], "meta": { "total": 7, "hasMore": false, "durationMs": 884 } } ``` В каждом объекте показаны 7 полей. Полный ответ содержит все поля типа. С фильтром по диапазону дат шире 14 дней в `meta` дополнительно приходят `autoWindowed`, `windowCount` и `batchWaves`: ```json { "success": true, "data": [], "meta": { "total": 0, "hasMore": false, "autoWindowed": true, "windowCount": 131, "batchWaves": 3, "durationMs": 1492 } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | | 401 | `MISSING_API_KEY` | Заголовок `X-Api-Key` не передан | | 401 | `INVALID_API_KEY` | Ключ не найден или отозван | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 422 | `BITRIX_ERROR` | Ошибка от Битрикс24. Конкретная причина — в поле `message` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Разбиение по временны́м окнам.** Фильтр по диапазону дат шире 14 дней автоматически разбивается на недельные окна, которые выполняются параллельными волнами — так выборка обходит потолок в 5000 записей на один вызов. В `meta` тогда приходят `autoWindowed: true`, число окон `windowCount` и число волн `batchWaves`. Отключает разбиение параметр `autoWindow: false`. При активном разбиении `offset` больше нуля отклоняется с `UNSTABLE_OFFSET_PAGINATION`. **Булевы фильтры передавайте как `true`/`false`**, не как `"Y"`/`"N"` — Вайбкод сам преобразует их для Битрикс24. **Когда использовать search вместо list.** Когда нужно несколько условий фильтрации одновременно — тело запроса читаемее длинной строки запроса. Для получения всех типов подойдёт `GET /v1/smart-processes`. ## Смотрите также - [Список типов](/docs/entities/smart-processes/list) - [Поля типа](/docs/entities/smart-processes/fields) - [Получить тип](/docs/entities/smart-processes/get) - [Элементы смарт-процессов](/docs/entities/items) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Smart Processes: Update ## Обновить тип смарт-процесса `PATCH /v1/smart-processes/:entityTypeId` Обновляет поля существующего типа смарт-процесса. Передавайте только те поля, которые нужно изменить — остальные остаются прежними. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `entityTypeId` (path) | number | **да** | ID типа сущности. Список: `GET /v1/smart-processes` | ## Поля запроса (body) Все поля опциональны. Не переданные поля остаются без изменений. | Поле | Тип | Описание | |------|-----|---------| | `title` | string | Название смарт-процесса | | `code` | string | Символьный код типа (для программной идентификации) | | `isCategoriesEnabled` | boolean | Использовать свои воронки и туннели продаж | | `isStagesEnabled` | boolean | Использовать свои стадии и канбан | | `isBeginCloseDatesEnabled` | boolean | Поля «Дата начала» и «Дата завершения» | | `isClientEnabled` | boolean | Поле «Клиент» с привязкой к контактам и компаниям | | `isLinkWithProductsEnabled` | boolean | Привязка товаров каталога | | `isMycompanyEnabled` | boolean | Поле «Реквизиты вашей компании» | | `isObserversEnabled` | boolean | Поле «Наблюдатели» | | `isSourceEnabled` | boolean | Поля «Источник» и «Дополнительно об источнике» | | `isAutomationEnabled` | boolean | Роботы и триггеры | | `isBizProcEnabled` | boolean | Дизайнер бизнес-процессов | | `isDocumentsEnabled` | boolean | Печать документов | | `isRecyclebinEnabled` | boolean | Использование корзины | | `isSetOpenPermissions` | boolean | Делать новые воронки доступными для всех | | `isUseInUserfieldEnabled` | boolean | Использовать смарт-процесс в пользовательском поле | | `isRecurringEnabled` | boolean | Поле «Регулярность» | | `isPaymentsEnabled` | boolean | Онлайн-оплата | | `isCountersEnabled` | boolean | Счётчики (уведомления и бейджи) | | `relations` | object | Связи с другими сущностями CRM. **Полностью заменяет** существующие связи — см. «Известные особенности» | | `linkedUserFields` | object | Пользовательские поля, в которых отображается смарт-процесс. Формат — см. [Создать тип](/docs/entities/smart-processes/create#связи-и-пользовательские-поля) | Полный список полей: [GET /v1/smart-processes/fields](/docs/entities/smart-processes/fields). **Сменить `entityTypeId` нельзя** — он устанавливается при создании и остаётся неизменным. ## Основные обновляемые поля - `title` — переименование типа - `isStagesEnabled`, `isCategoriesEnabled`, `isAutomationEnabled`, `isBizProcEnabled` — включение/выключение основных возможностей - `code` — назначение программного идентификатора - `relations` — настройка связей с другими типами CRM ## Примеры ### curl — личный ключ ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/smart-processes/1050 \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Договоры поставки (обновлённое название)", "code": "supply_contracts", "isAutomationEnabled": false }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/smart-processes/1050 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Договоры поставки (обновлённое название)", "code": "supply_contracts", "isAutomationEnabled": false }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/smart-processes/1050', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Договоры поставки (обновлённое название)', code: 'supply_contracts', isAutomationEnabled: false, }), }) const { success, data } = await res.json() console.log('Обновлено в:', data.updatedTime) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/smart-processes/1050', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Договоры поставки (обновлённое название)', code: 'supply_contracts', isAutomationEnabled: false, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | object | Полный объект типа после обновления. Список полей — см. [Поля типа](/docs/entities/smart-processes/fields) | ## Пример ответа ```json { "success": true, "data": { "id": 31, "entityTypeId": 1050, "title": "Договоры поставки (обновлённое название)", "code": "supply_contracts", "createdBy": 1, "createdTime": "2026-04-21T13:46:45+03:00", "updatedBy": 1, "updatedTime": "2026-04-21T14:50:13+03:00", "customSectionId": null, "isCategoriesEnabled": true, "isStagesEnabled": true, "isBeginCloseDatesEnabled": false, "isClientEnabled": false, "isLinkWithProductsEnabled": true, "isMycompanyEnabled": false, "isObserversEnabled": false, "isSourceEnabled": false, "isAutomationEnabled": false, "isBizProcEnabled": true, "isDocumentsEnabled": false, "isRecyclebinEnabled": false, "isSetOpenPermissions": true, "isUseInUserfieldEnabled": false, "isRecurringEnabled": false, "isPaymentsEnabled": false, "isCountersEnabled": false, "isInitialized": true } } ``` ## Пример ответа при ошибке 404 — тип не найден: ```json { "success": false, "error": { "code": "SMART_PROCESS_NOT_FOUND", "message": "Smart process with entityTypeId=99999 not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `MISSING_API_KEY` | Заголовок `X-Api-Key` не передан | | 401 | `INVALID_API_KEY` | Ключ не найден или отозван | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 400 | `INVALID_ENTITY_TYPE_ID` | `entityTypeId` не является положительным целым. Сообщение: `entityTypeId must be a positive integer` | | 400 | `READONLY_FIELD` | В теле передано поле только для чтения (`id`, `isInitialized`, `createdTime` и другие) | | 404 | `SMART_PROCESS_NOT_FOUND` | Тип с таким `entityTypeId` не найден. Сообщение: `Smart process with entityTypeId=X not found` | | 422 | `BITRIX_ERROR` | Ошибка валидации от Битрикс24. Конкретная причина — в поле `message` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`relations` полностью заменяет существующие связи.** Если передать `relations: {parent: [{entityTypeId: 3}]}`, все прежние `parent`-связи **будут удалены** и заменены на один новый массив. Чтобы добавить связь, не потеряв текущие, — сначала получите текущее состояние через `GET /v1/smart-processes/:entityTypeId`, добавьте новую запись в массив и передайте весь обновлённый список. Аналогично для `child` и `linkedUserFields` — это «перезапись», не «патч по записям». **Пустое тело запроса (`{}`) допустимо.** PATCH с пустым объектом возвращает HTTP 200 и текущее состояние типа, ничего не меняя. **Изменение `entityTypeId` невозможно** — он задаётся при создании и служит стабильным идентификатором типа. ## Смотрите также - [Получить тип](/docs/entities/smart-processes/get) - [Список типов](/docs/entities/smart-processes/list) - [Создать тип](/docs/entities/smart-processes/create) - [Удалить тип](/docs/entities/smart-processes/delete) - [Поля типа](/docs/entities/smart-processes/fields) - [Элементы смарт-процессов](/docs/entities/items) - [Лимиты и оптимизация](/docs/optimization) --- # Statuses: Aggregate ## Агрегация записей справочника `POST /v1/statuses/aggregate` Подсчёт `count` и числовые агрегации `sum`, `avg`, `min`, `max` по записям справочников CRM с фильтром. Основной сценарий — `count`: сколько записей в справочнике или под фильтром. ## Стандартные поля Числовые функции применяются к числовым полям записи: | Поле | Назначение | |------|------------| | `sort` | Порядок сортировки — `min` / `max` / `avg` дают диапазон весов | | `id` | Идентификатор записи | | `categoryId` | ID воронки для справочников вида `DEAL_STAGE_N` | Поля `entityId`, `statusId`, `name`, `semantics` — категориальные. Для них доступен только `count` с фильтром. Группировка `groupBy` у справочников не поддерживается. Пользовательских полей у справочников CRM нет. ## Поля запроса (тело) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций вида `{ "field": "sort", "function": "min" }`. Функции: `sum`, `avg`, `min`, `max` — только по полям `sort`, `id`, `categoryId`. Без параметра возвращается `count` записей с учётом фильтра | | `filter` | object | нет | Фильтрация по полям записи — `id`, `entityId`, `statusId`, `name`, `sort`, `semantics`, `categoryId`. Только точное равенство по одному значению. Список значений (`$in` или массив) не поддерживается ни по одному полю — такой фильтр отклоняется с `400 UNSUPPORTED_FILTER`. Считайте каждое значение отдельным вызовом или соберите вызовы в [`POST /v1/batch`](/docs/batch).
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "entityId": "DEAL_STAGE" }` | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/statuses/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "entityId": "DEAL_STAGE" } }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/statuses/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "entityId": "DEAL_STAGE" } }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/statuses/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { entityId: 'DEAL_STAGE' }, }), }) const { success, data } = await res.json() console.log('Стадий в воронке:', data.count) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/statuses/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { entityId: 'DEAL_STAGE' }, }), }) const { success, data } = await res.json() ``` ## Другие сценарии Общее число записей всех справочников — `count` без фильтра: ```json {} ``` Диапазон и среднее значение сортировки стадий воронки — числовые функции по полю `sort`: ```json { "aggregate": [ { "field": "sort", "function": "min" }, { "field": "sort", "function": "max" }, { "field": "sort", "function": "avg" } ], "filter": { "entityId": "DEAL_STAGE" } } ``` Ответ на такой запрос содержит заполненный `data.aggregates`: ```json { "success": true, "data": { "count": 8, "aggregates": { "sort": { "min": 10, "max": 80, "avg": 45 } }, "meta": { "totalRecords": 8, "recordsProcessed": 8, "truncated": false } } } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Количество записей, соответствующих фильтру | | `data.aggregates` | object | Результаты числовых функций по полям. Для `count` без функций — пустой объект `{}` | | `data.meta.totalRecords` | number | Общее количество записей под фильтром | | `data.meta.recordsProcessed` | number | Сколько записей загружено для расчёта. Для `count` — `0`, для числовых функций — число обработанных записей | | `data.meta.truncated` | boolean | `true`, если записей больше 5000 и расчёт выполнен по первым 5000 | ## Пример ответа ```json { "success": true, "data": { "count": 8, "aggregates": {}, "meta": { "totalRecords": 8, "recordsProcessed": 0, "truncated": false } } } ``` С числовыми функциями поле `data.aggregates` заполняется — см. «Другие сценарии». ## Пример ответа при ошибке 400 — числовая функция по несуществующему полю: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "Field 'nope' not found. Available numeric fields: id, sort, categoryId." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Неизвестная функция — сообщение перечисляет допустимые: `count`, `sum`, `avg`, `min`, `max` | | 400 | `INVALID_PARAMS` | Несуществующее поле в `aggregate` — сообщение перечисляет числовые поля: `id`, `sort`, `categoryId` | | 400 | `INVALID_PARAMS` | Нечисловое поле в `sum` / `avg` / `min` / `max` — сообщение называет тип поля | | 400 | `INVALID_PARAMS` | Передан `groupBy` — группировка у справочников недоступна | | 400 | `UNSUPPORTED_FILTER` | В `filter` передан список значений — `$in` или массив. Сообщение называет поле и перечисляет фильтруемые: `id`, `entityId`, `statusId`, `name`, `sort`, `semantics`, `categoryId` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | Не передан API-ключ | Полный список ошибок — [Ошибки](/docs/errors). ## Известные особенности **`count` против числовых функций.** `count` считается одним обращением к Битрикс24 на любом объёме, записи не выгружаются — поэтому `data.meta.recordsProcessed` равен `0`. Функции `sum` / `avg` / `min` / `max` загружают записи постранично и считают на стороне Вайбкод. При выборке больше 5000 записей приходит `data.meta.truncated: true`, а результат рассчитан по первым 5000. **Группировка недоступна.** Поля справочника не входят в набор группируемых, поэтому `groupBy` возвращает `400 INVALID_PARAMS`. Чтобы посчитать записи по типам справочника, вызывайте `count` с фильтром `filter[entityId]` отдельно для каждого типа. ## Смотрите также - [Список справочников](./list.md) - [Поиск записей справочника](./search.md) - [Поля справочника](./fields.md) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Statuses: Create ## Создать запись справочника `POST /v1/statuses` Создаёт новую запись в справочнике CRM. Обязательные поля: `entityId`, `statusId`, `name`. ## Параметры тела запроса | Параметр | Тип | Обязат. | Описание | |----------|-----|:-------:|---------| | `entityId` | string | да | Тип справочника (DEAL_STAGE, SOURCE и др.) | | `statusId` | string | да | Символьный код значения | | `name` | string | да | Название | | `sort` | number | | Порядок сортировки | | `color` | string | | Цвет в HEX, напр. `#22B9FF`. Решётку можно опустить | | `semantics` | string | | Семантика: `S` — успех, `F` — провал | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/statuses" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"entityId": "SOURCE", "statusId": "PARTNER", "name": "Партнёр", "sort": 50}' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/statuses" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"entityId": "SOURCE", "statusId": "PARTNER", "name": "Партнёр", "sort": 50}' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/statuses', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ entityId: 'SOURCE', statusId: 'PARTNER', name: 'Партнёр', sort: 50 }), }) const { success, data } = await res.json() console.log('ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/statuses', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ entityId: 'SOURCE', statusId: 'PARTNER', name: 'Партнёр', sort: 50 }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID записи | | `entityId` | string | Тип справочника | | `statusId` | string | Символьный код | | `name` | string | Название | | `nameInit` | string/null | Исходное название | | `sort` | number | Сортировка | | `system` | boolean | Системное значение. Только для чтения | | `categoryId` | number/null | ID воронки. Заполняется для справочников вида `DEAL_STAGE_N`, иначе `0` или `null` | | `color` | string/null | Цвет в HEX с ведущей `#` | | `semantics` | string/null | Семантика: `S` — успех, `F` — провал. `null` — стадия «в работе» или справочник без семантики | | `extra` | object/null | Дополнительные данные справочников со стадиями — `STATUS`, `DEAL_STAGE`, `DEAL_STAGE_N`, `QUOTE_STATUS`. Вложенные ключи `SEMANTICS` и `COLOR`, значения `SEMANTICS` — в [Полях справочника](/docs/entities/statuses/fields). Только для чтения, у остальных справочников отсутствует | ## Пример ответа ```json { "success": true, "data": { "id": 801, "entityId": "SOURCE", "statusId": "PARTNER", "name": "Партнёр", "nameInit": null, "sort": 50, "system": false, "categoryId": 0, "color": null, "semantics": null } } ``` ## Пример ответа при ошибке 422 — дублирование кода: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Указанный идентификатор статуса, уже существует." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Ошибка Битрикс24 (дублирование statusId и др.) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | Не передан API-ключ | Полный список ошибок — [Ошибки](/docs/errors). ## Смотрите также - [Список справочников](/docs/entities/statuses/list) - [Поля справочника](/docs/entities/statuses/fields) - [Справочники CRM](/docs/entities/statuses) --- # Statuses: Delete ## Удалить запись справочника `DELETE /v1/statuses/:id` Удаляет запись справочника CRM по ID. Системные записи (`system: true`) удалить нельзя. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID записи справочника | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/statuses/42" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/statuses/42" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/statuses/42', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) if (res.status === 204) { console.log('Запись удалена') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/statuses/42', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 422 — запись не найдена или системная: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Status is not found." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Запись не найдена, является системной (`system: true`) или ID невалиден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | Не передан API-ключ | Полный список ошибок — [Ошибки](/docs/errors). ## Смотрите также - [Список справочников](/docs/entities/statuses/list) - [Справочники CRM](/docs/entities/statuses) --- # Statuses: Fields ## Поля справочника `GET /v1/statuses/fields` Возвращает описание всех полей сущности с типами и атрибутами. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/statuses/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/statuses/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/statuses/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/statuses/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | RO | Описание | |------|-----|:--:|---------| | `id` | number | да | ID записи | | `entityId` | string | | Тип справочника (DEAL_STAGE, SOURCE и др.) | | `statusId` | string | | Символьный код значения | | `name` | string | | Название | | `nameInit` | string | | Исходное название | | `sort` | number | | Сортировка | | `color` | string | | Цвет (HEX) | | `semantics` | string | | Семантика: `S` — успех, `F` — провал, `null` — в работе или без семантики | | `system` | boolean | да | Системное значение (нельзя изменить/удалить) | | `categoryId` | number | | ID воронки (для `entityId` вида `DEAL_STAGE_N`) | | `extra` | object | да | Дополнительные данные справочников со стадиями — `STATUS`, `DEAL_STAGE`, `DEAL_STAGE_N`, `QUOTE_STATUS`. Вложенные ключи `SEMANTICS` и `COLOR`. У остальных справочников поле отсутствует | ## Пример ответа `GET /v1/statuses/fields` возвращает описания полей под ключом `data.fields` (имена — camelCase, как в ответах API), где каждое поле — `{ type, readonly, label, description }`. Подписи есть у всех одиннадцати полей, включая служебное `extra`. Плюс `data.batch` со списком доступных batch-операций. ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "ID", "description": "Уникальный числовой идентификатор записи справочника." }, "entityId": { "type": "string", "readonly": false, "label": "Тип справочника", "description": "Тип справочника, к которому относится запись (например, DEAL_STAGE, SOURCE, STATUS)." }, "statusId": { "type": "string", "readonly": false, "label": "Код значения", "description": "Символьный код значения внутри своего справочника." }, "name": { "type": "string", "readonly": false, "label": "Название", "description": "Отображаемое название записи." }, "nameInit": { "type": "string", "readonly": false, "label": "Исходное название", "description": "Исходное название, присвоенное при создании записи." }, "sort": { "type": "number", "readonly": false, "label": "Сортировка", "description": "Порядок сортировки внутри справочника." }, "color": { "type": "string", "readonly": false, "label": "Цвет", "description": "Цвет значения в формате HEX." }, "semantics": { "type": "string", "readonly": false, "label": "Семантика", "description": "Семантика стадии: S — успех, F — провал, null — в работе или без семантики." }, "system": { "type": "boolean", "readonly": true, "label": "Системное", "description": "Системное значение, которое нельзя изменить или удалить." }, "categoryId": { "type": "number", "readonly": false, "label": "ID воронки", "description": "ID воронки для значений entityId вида DEAL_STAGE_N." }, "extra": { "type": "object", "readonly": true, "label": "Дополнительные данные", "description": "Дополнительные данные стадийных справочников — объект с вложенными ключами SEMANTICS (семантика стадии) и COLOR (цвет стадии). Заполняется Битрикс24, только для чтения." } }, "batch": ["create", "update", "delete"] } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | Не передан API-ключ | Полный список ошибок — [Ошибки](/docs/errors). ## Известные особенности **Ключ `SEMANTICS` внутри `extra` подробнее поля `semantics`.** Поле различает три состояния, вложенный ключ — четыре: | `extra.SEMANTICS` | `semantics` | Состояние стадии | |-------------------|-------------|------------------| | `process` | `null` | Промежуточная стадия | | `success` | `S` | Успешное завершение | | `failure` | `F` | Провал | | `apology` | `F` | Ещё одна финальная стадия провала | Стадии `failure` и `apology` в поле `semantics` неразличимы — обе приходят как `F`. Если сценарий их различает, читайте `extra.SEMANTICS`. ## Смотрите также - [Справочники CRM](/docs/entities/statuses) - [Список справочников](/docs/entities/statuses/list) --- # Statuses: Get ## Получить запись справочника `GET /v1/statuses/:id` Возвращает одну запись справочника CRM по ID. ## Параметры пути | Параметр | Тип | Описание | |----------|-----|---------| | `id` | number | ID записи справочника | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/statuses/1" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/statuses/1" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/statuses/1', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/statuses/1', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID записи | | `entityId` | string | Тип справочника (DEAL_STAGE, SOURCE, CONTACT_TYPE и др.) | | `statusId` | string | Символьный код значения | | `name` | string | Название | | `nameInit` | string/null | Исходное название | | `sort` | number | Сортировка | | `system` | boolean | Системное значение. Только для чтения | | `categoryId` | number/null | ID воронки. Заполняется для справочников вида `DEAL_STAGE_N`, иначе `0` или `null` | | `color` | string/null | Цвет в HEX с ведущей `#` | | `semantics` | string/null | Семантика: `S` — успех, `F` — провал. `null` — стадия «в работе» или справочник без семантики | | `extra` | object/null | Дополнительные данные справочников со стадиями — `STATUS`, `DEAL_STAGE`, `DEAL_STAGE_N`, `QUOTE_STATUS`. Вложенные ключи `SEMANTICS` и `COLOR`, значения `SEMANTICS` — в [Полях справочника](/docs/entities/statuses/fields). Только для чтения, у остальных справочников отсутствует | ## Пример ответа ```json { "success": true, "data": { "id": 101, "entityId": "DEAL_STAGE", "statusId": "NEW", "name": "Новая", "nameInit": "Новая", "sort": 10, "system": true, "categoryId": null, "color": "#39A8EF", "semantics": null, "extra": { "SEMANTICS": "process", "COLOR": "#39A8EF" } } } ``` ## Пример ответа при ошибке ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "CRM Status is not found." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Запись с указанным `id` не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | Не передан API-ключ | Полный список ошибок — [Ошибки](/docs/errors). ## Смотрите также - [Список справочников](/docs/entities/statuses/list) - [Обновить запись](/docs/entities/statuses/update) - [Справочники CRM](/docs/entities/statuses) --- # Statuses: List ## Список справочников `GET /v1/statuses` Возвращает записи справочников CRM. Используйте `filter[entityId]` для выбора конкретного типа. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` авто-пагинация | | `offset` | number | `0` | Пропустить N записей | | `select` | string | — | Выборка полей: `?select=id,name,entityId` | | `order` | object | — | Сортировка: `?order[sort]=asc` | | `filter` | object | — | Только точное равенство по одному значению — по полям `id`, `entityId`, `statusId`, `name`, `sort`, `semantics`, `categoryId`. Список значений (`$in` или массив) не поддерживается ни по одному полю: метод справочника его не принимает, поэтому такой фильтр отклоняется сразу с `400 UNSUPPORTED_FILTER` — передавайте одно значение, а несколько значений запрашивайте отдельными вызовами или через `POST /v1/batch`. Операторы (`>`, `>=`, `<`, `<=`, `!`, `%`, `$ne`, `$contains`, `$nin`) и другие поля (например `color`) не поддерживаются — тоже `400 UNSUPPORTED_FILTER`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[entityId]=DEAL_STAGE` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/statuses?filter[entityId]=DEAL_STAGE&order[sort]=asc" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/statuses?filter[entityId]=DEAL_STAGE&order[sort]=asc" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/statuses?filter[entityId]=DEAL_STAGE&order[sort]=asc', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data, meta } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/statuses?filter[entityId]=DEAL_STAGE&order[sort]=asc', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data[].id` | number | ID записи | | `data[].entityId` | string | Тип справочника (DEAL_STAGE, SOURCE, CONTACT_TYPE и др.) | | `data[].statusId` | string | Символьный код значения | | `data[].name` | string | Название | | `data[].nameInit` | string/null | Исходное название | | `data[].sort` | number | Сортировка | | `data[].system` | boolean | Системное значение. Только для чтения | | `data[].categoryId` | number/null | ID воронки. Заполняется для справочников вида `DEAL_STAGE_N`, иначе `0` или `null` | | `data[].color` | string/null | Цвет в HEX с ведущей `#` | | `data[].semantics` | string/null | Семантика: `S` — успех, `F` — провал. `null` — стадия «в работе» или справочник без семантики | | `data[].extra` | object/null | Дополнительные данные справочников со стадиями — `STATUS`, `DEAL_STAGE`, `DEAL_STAGE_N`, `QUOTE_STATUS`. Вложенные ключи `SEMANTICS` и `COLOR`, значения `SEMANTICS` — в [Полях справочника](/docs/entities/statuses/fields). Только для чтения, у остальных справочников отсутствует | ## Пример ответа ```json { "success": true, "data": [ { "id": 101, "entityId": "DEAL_STAGE", "statusId": "NEW", "name": "Новая", "nameInit": "Новая", "sort": 10, "system": true, "categoryId": null, "color": "#39A8EF", "semantics": null, "extra": { "SEMANTICS": "process", "COLOR": "#39A8EF" } }, { "id": 111, "entityId": "DEAL_STAGE", "statusId": "WON", "name": "Сделка успешна", "nameInit": "Сделка успешна", "sort": 60, "system": true, "categoryId": null, "color": "#7BD500", "semantics": "S", "extra": { "SEMANTICS": "success", "COLOR": "#7BD500" } } ], "meta": { "total": 12, "hasMore": false } } ``` ## Пример ответа при ошибке 400 — оператор или неподдерживаемое поле в фильтре: ```json { "success": false, "error": { "code": "UNSUPPORTED_FILTER", "message": "UNSUPPORTED_FILTER: 'color' is not filterable on 'statuses'. Its Bitrix24 method (crm.status.list) filters by exact match only. Filterable: id, entityId, statusId, name, sort, semantics, categoryId." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSUPPORTED_FILTER` | Оператор, неподдерживаемое поле или список значений. Фильтруйте точным равенством по одному значению — по полям `id`, `entityId`, `statusId`, `name`, `sort`, `semantics`, `categoryId` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | Не передан API-ключ | Полный список ошибок — [Ошибки](/docs/errors). ## Смотрите также - [Справочники CRM](/docs/entities/statuses) - [Создать запись](/docs/entities/statuses/create) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) --- # Statuses: Search ## Поиск записей справочника `POST /v1/statuses/search` Поиск записей справочников CRM с фильтрацией. Аналогичен [`GET /v1/statuses`](./list.md), но условия передаются в теле запроса — это позволяет задать несколько условий сразу. Фильтр работает только по точному совпадению. ## Поля запроса (тело) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям `GET /v1/statuses/fields`. Только точное совпадение. Поля: `id`, `entityId`, `statusId`, `name`, `sort`, `semantics`, `categoryId`.
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "entityId": "DEAL_STAGE" }` | | `limit` | number | `50` | Количество записей, до 5000 | | `select` | string[] | — | Выборка полей: `["id", "statusId", "name", "sort"]` | | `order` | object | — | Сортировка: `{ "sort": "asc" }` | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/statuses/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "entityId": "DEAL_STAGE" }, "select": ["id", "statusId", "name", "sort", "semantics"], "order": { "sort": "asc" } }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/statuses/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "entityId": "DEAL_STAGE" }, "select": ["id", "statusId", "name", "sort", "semantics"], "order": { "sort": "asc" } }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/statuses/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { entityId: 'DEAL_STAGE' }, select: ['id', 'statusId', 'name', 'sort', 'semantics'], order: { sort: 'asc' }, }), }) const { success, data, meta } = await res.json() console.log('Стадий в воронке:', meta.total) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/statuses/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { entityId: 'DEAL_STAGE' }, select: ['id', 'statusId', 'name', 'sort', 'semantics'], order: { sort: 'asc' }, }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив записей справочника. Без `select` элемент содержит все поля — см. [Поля справочника](./fields.md) | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа ```json { "success": true, "data": [ { "id": 101, "statusId": "NEW", "name": "Новая", "sort": 10, "semantics": null }, { "id": 111, "statusId": "WON", "name": "Сделка успешна", "sort": 60, "semantics": "S" }, { "id": 113, "statusId": "LOSE", "name": "Сделка провалена", "sort": 70, "semantics": "F" } ], "meta": { "total": 8, "hasMore": false, "durationMs": 2243 } } ``` ## Пример ответа при ошибке 400 — фильтр по неподдерживаемому полю: ```json { "success": false, "error": { "code": "UNSUPPORTED_FILTER", "message": "'foo' is not filterable on 'statuses'. Filters by exact match only. Filterable: id, entityId, statusId, name, sort, semantics, categoryId." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSUPPORTED_FILTER` | Фильтр по полю вне списка фильтруемых или с неточным условием | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | Не передан API-ключ | Полный список ошибок — [Ошибки](/docs/errors). ## Известные особенности **Фильтр — точное совпадение по одному значению.** Фильтр отбирает записи, у которых поле точно равно заданному значению. Операторы сравнения `$gte`, `$lt` и подобные возвращают `400 UNSUPPORTED_FILTER`. Список значений (`$in` или массив) метод справочника не поддерживает ни по одному полю — такой фильтр отклоняется с `400 UNSUPPORTED_FILTER`. Передавайте одно значение, а несколько значений запрашивайте отдельными вызовами или через `POST /v1/batch`. **`select` ограничивает поля ответа.** С `select` каждый элемент `data` содержит только перечисленные поля. Без `select` возвращаются все поля записи, включая вложенный объект `extra` у справочников `STATUS`, `DEAL_STAGE`, `DEAL_STAGE_N`, `QUOTE_STATUS`. ## Смотрите также - [Список справочников](./list.md) - [Получить запись](./get.md) - [Поля справочника](./fields.md) - [Агрегация записей справочника](./aggregate.md) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) --- # Statuses: Update ## Обновить запись справочника `PATCH /v1/statuses/:id` Обновляет поля записи справочника CRM по ID. ## Параметры пути | Параметр | Тип | Описание | |----------|-----|---------| | `id` | number | ID записи справочника | ## Параметры тела запроса | Параметр | Тип | Описание | |----------|-----|---------| | `name` | string | Название | | `sort` | number | Порядок сортировки | | `color` | string | Цвет в HEX, напр. `#22B9FF`. Решётку можно опустить | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/statuses/42" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "Предоплата получена", "sort": 35}' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/statuses/42" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name": "Предоплата получена", "sort": 35}' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/statuses/42', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Предоплата получена', sort: 35 }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/statuses/42', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Предоплата получена', sort: 35 }), }) const { success, data } = await res.json() ``` ## Поля ответа Возвращается обновлённая запись целиком. | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID записи | | `entityId` | string | Тип справочника (DEAL_STAGE, SOURCE, CONTACT_TYPE и др.) | | `statusId` | string | Символьный код значения | | `name` | string | Название | | `nameInit` | string/null | Исходное название | | `sort` | number | Сортировка | | `system` | boolean | Системное значение. Только для чтения | | `categoryId` | number/null | ID воронки. Заполняется для справочников вида `DEAL_STAGE_N`, иначе `0` или `null` | | `color` | string/null | Цвет в HEX с ведущей `#` | | `semantics` | string/null | Семантика: `S` — успех, `F` — провал. `null` — стадия «в работе» или справочник без семантики | | `extra` | object/null | Дополнительные данные справочников со стадиями — `STATUS`, `DEAL_STAGE`, `DEAL_STAGE_N`, `QUOTE_STATUS`. Вложенные ключи `SEMANTICS` и `COLOR`, значения `SEMANTICS` — в [Полях справочника](/docs/entities/statuses/fields). Только для чтения, у остальных справочников отсутствует | ## Пример ответа ```json { "success": true, "data": { "id": 42, "entityId": "DEAL_STAGE", "statusId": "PREPAYMENT_INVOICE", "name": "Предоплата получена", "nameInit": null, "sort": 35, "system": false, "categoryId": null, "color": "#39A8EF", "semantics": null, "extra": { "SEMANTICS": "process", "COLOR": "#39A8EF" } } } ``` ## Пример ответа при ошибке ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Status is not found." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Запись с указанным `id` не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | Не передан API-ключ | Полный список ошибок — [Ошибки](/docs/errors). ## Смотрите также - [Получить запись](/docs/entities/statuses/get) - [Описание полей](/docs/entities/statuses/fields) - [Справочники CRM](/docs/entities/statuses) --- # Storages: Fields ## Поля хранилища `GET /v1/storages/fields` Возвращает карту всех полей хранилища с типом и признаком только для чтения. Все поля хранилища доступны только для чтения — раздел не поддерживает создание и обновление. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/storages/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/storages/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/storages/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data.fields).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/storages/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа Объект `data` содержит карту `fields` (имя поля → `{ type, readonly, label, description }`) и список `batch` с операциями массового режима. Для хранилищ `batch` пуст — раздел только для чтения. | Поле | Битрикс24 | Тип | RO | Описание | |------|----------|-----|:--:|---------| | `id` | `ID` | number | да | Идентификатор хранилища | | `name` | `NAME` | string | да | Название хранилища | | `code` | `CODE` | string \| null | да | Символьный код. На проверенных порталах `null` | | `module` | `MODULE_ID` | string | да | Модуль-владелец хранилища, для Диска — `disk` | | `entityType` | `ENTITY_TYPE` | string | да | Тип владельца: `user`, `group`, `common` | | `entityId` | `ENTITY_ID` | string | да | Идентификатор владельца. Строка, у общего диска нечисловая, например `shared_files_s1` | | `rootFolderId` | `ROOT_OBJECT_ID` | number | да | Идентификатор корневой папки хранилища. Содержимое — [`GET /v1/folders`](/docs/entities/folders) | ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "ID", "description": "Уникальный идентификатор хранилища Диска." }, "name": { "type": "string", "readonly": true, "label": "Название", "description": "Название хранилища, отображаемое пользователю." }, "code": { "type": "string", "readonly": true, "label": "Символьный код", "description": "Символьный код хранилища; на практике часто отсутствует (null)." }, "entityType": { "type": "string", "readonly": true, "label": "Тип владельца", "description": "Тип владельца хранилища — пользователь, группа или общий диск компании." }, "entityId": { "type": "string", "readonly": true, "label": "ID владельца", "description": "Идентификатор владельца хранилища; для общего диска может быть нечисловым значением." }, "rootFolderId": { "type": "number", "readonly": true, "label": "Корневая папка", "description": "ID корневой папки хранилища, с которой начинается его содержимое." }, "module": { "type": "string", "readonly": true, "label": "Модуль", "description": "Код модуля-владельца хранилища; для Диска — значение disk." } }, "batch": [] } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'disk' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `disk` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список хранилищ](/docs/entities/storages/list) - [Получить хранилище](/docs/entities/storages/get) - [Хранилища](/docs/entities/storages) - [Entity API](/docs/entity-api) --- # Storages: Get ## Получить хранилище `GET /v1/storages/:id` Возвращает одно хранилище Битрикс24.Диска по идентификатору. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор хранилища | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/storages/1" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/storages/1" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/storages/1', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Хранилище:', data.name, '—', data.entityType) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/storages/1', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Идентификатор хранилища | | `data.name` | string | Название хранилища | | `data.code` | string \| null | Символьный код. На проверенных порталах `null` | | `data.module` | string | Модуль-владелец хранилища, для Диска — `disk` | | `data.entityType` | string | Тип владельца: `user`, `group`, `common` | | `data.entityId` | string | Идентификатор владельца. Строка, у общего диска нечисловая, например `shared_files_s1` | | `data.rootFolderId` | number | Идентификатор корневой папки хранилища | ## Пример ответа ```json { "success": true, "data": { "id": 1, "name": "Летта", "code": null, "module": "disk", "entityType": "user", "entityId": "1", "rootFolderId": 1 } } ``` ## Пример ответа при ошибке 404 — хранилище не найдено: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Could not find entity with id '999999'." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Хранилище с указанным `id` не существует или недоступно пользователю | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `disk` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список хранилищ](/docs/entities/storages/list) - [Поля хранилища](/docs/entities/storages/fields) - [Папки](/docs/entities/folders) - [Лимиты и оптимизация](/docs/optimization) --- # Storages: List ## Список хранилищ `GET /v1/storages` Возвращает список хранилищ Битрикс24.Диска с фильтрацией по точному совпадению полей и автопагинацией. **Порядок выдачи.** Без сортировки список приходит по возрастанию `id`. К вашей сортировке `id` добавляется последним ключом, поэтому порядок всегда полный и однозначный, а постраничный обход повторяем: при сортировке по неуникальному полю строка с тем же значением иначе могла на границе страниц попасть в две страницы сразу или пропасть. Если вы сортируете по `id` сами, ваше направление сохраняется. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` запрос автоматически собирается из нескольких страниц на стороне сервера | | `offset` | number | `0` | Пропустить N записей. Применяется для чтения выборок больше 5000 записей | | `select` | string | — | Выборка полей: `?select=id,name`. Возвращаются только перечисленные поля | | `sort` | string | — | Поле сортировки, минус впереди означает по убыванию: `?sort=-id`. Порядок меняют `id`, `name`, `entityType`, `entityId`, `rootFolderId` (проверено живьём). Поля `code` и `module` метод принимает, но на проверенных аккаунтах эти колонки одинаковы у всех хранилищ, поэтому порядок по ним не меняется | | `order` | object | — | То же в объектной форме: `?order[id]=desc`. При одновременной передаче с `sort` выигрывает `sort` | | `filter` | object | — | Только точное равенство и `$in` (IN-множество) по полям `id`, `name`, `code`, `entityType`, `entityId`. Операторы (`>`, `>=`, `<`, `<=`, `!`, `%`, `$ne`, `$contains`, `$nin`) и другие поля (например `rootFolderId`) не поддерживаются — вернётся `400 UNSUPPORTED_FILTER`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[entityType]=group` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/storages?limit=10&filter[entityType]=group" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/storages?limit=10&filter[entityType]=group" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/storages?limit=10&filter[entityType]=group', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Всего хранилищ под фильтром: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/storages?limit=10&filter[entityType]=group', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив хранилищ | | `data[].id` | number | Идентификатор хранилища | | `data[].name` | string | Название хранилища | | `data[].code` | string \| null | Символьный код. На проверенных порталах `null` | | `data[].module` | string | Модуль-владелец хранилища, для Диска — `disk` | | `data[].entityType` | string | Тип владельца: `user`, `group`, `common` | | `data[].entityId` | string | Идентификатор владельца. Строка, у общего диска нечисловая | | `data[].rootFolderId` | number | Идентификатор корневой папки хранилища | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Признак наличия дополнительных записей | ## Пример ответа ```json { "success": true, "data": [ { "id": 1, "name": "Летта", "code": null, "module": "disk", "entityType": "user", "entityId": "1", "rootFolderId": 1 }, { "id": 11, "name": "Общий диск", "code": null, "module": "disk", "entityType": "common", "entityId": "shared_files_s1", "rootFolderId": 19 } ], "meta": { "total": 490, "hasMore": true } } ``` ## Пример ответа при ошибке 400 — оператор или неподдерживаемое поле в фильтре: ```json { "success": false, "error": { "code": "UNSUPPORTED_FILTER", "message": "UNSUPPORTED_FILTER: 'rootObjectId' is not filterable on 'storages'. Its Bitrix24 method (disk.storage.getlist) filters by exact match only. Filterable: id, name, code, entityType, entityId." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSUPPORTED_FILTER` | Оператор или неподдерживаемое поле в фильтре. Фильтруйте точным равенством или `$in` по `id`, `name`, `code`, `entityType`, `entityId` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `disk` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Выборки больше 5000 записей.** За один ответ возвращается до 5000 хранилищ. Общее число записей под фильтром приходит в `meta.total`, признак наличия продолжения — в `meta.hasMore`. Если под фильтр попадает больше 5000 записей, читайте продолжение параметром `offset`, увеличивая его на размер полученной порции. ## Смотрите также - [Получить хранилище](/docs/entities/storages/get) - [Поля хранилища](/docs/entities/storages/fields) - [Хранилища](/docs/entities/storages) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Storages: Search ## Поиск хранилищ `POST /v1/storages/search` Поиск хранилищ с фильтрами. Аналог `GET /v1/storages` с фильтром, но через POST — условия по нескольким полям передаются в теле запроса. Фильтрация по точному совпадению полей, автопагинация при `limit > 50`. **Порядок выдачи.** Без сортировки список приходит по возрастанию `id`. К вашей сортировке `id` добавляется последним ключом, поэтому порядок всегда полный и однозначный, а постраничный обход повторяем: при сортировке по неуникальному полю строка с тем же значением иначе могла на границе страниц попасть в две страницы сразу или пропасть. Если вы сортируете по `id` сами, ваше направление сохраняется. ## Поля запроса (body) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Только точное равенство и `$in` (IN-множество) по полям `id`, `name`, `code`, `entityType`, `entityId`. Операторы (`>`, `>=`, `<`, `<=`, `!`, `%`, `$ne`, `$contains`, `$nin`) и другие поля (например `rootFolderId`) не поддерживаются — вернётся `400 UNSUPPORTED_FILTER`.
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "entityType": "group" }` | | `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` запрос автоматически собирается из нескольких страниц на стороне сервера | | `offset` | number | `0` | Пропустить N записей. Применяется для чтения выборок больше 5000 записей | | `select` | string[] | — | Выборка полей: `["id", "name"]`. Возвращаются только перечисленные поля | | `sort` | string | — | Поле сортировки, минус впереди означает по убыванию: `"-id"`. Порядок меняют `id`, `name`, `entityType`, `entityId`, `rootFolderId` (проверено живьём). Поля `code` и `module` метод принимает, но на проверенных аккаунтах эти колонки одинаковы у всех хранилищ, поэтому порядок по ним не меняется | | `order` | object | — | То же в объектной форме: `{ "id": "desc" }`. При одновременной передаче с `sort` выигрывает `sort` | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/storages/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "entityType": "group" }, "limit": 10 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/storages/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "entityType": "group" }, "limit": 10 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/storages/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { entityType: 'group' }, limit: 10, }), }) const { success, data, meta } = await res.json() console.log(`Всего хранилищ под фильтром: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/storages/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { entityType: 'group' }, limit: 10, }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив хранилищ (см. [Поля хранилища](/docs/entities/storages/fields)) | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа ```json { "success": true, "data": [ { "id": 3, "name": "Закрытая видимая группа", "code": null, "module": "disk", "entityType": "group", "entityId": "1", "rootFolderId": 3 }, { "id": 113, "name": "test111", "code": null, "module": "disk", "entityType": "group", "entityId": "11", "rootFolderId": 787 } ], "meta": { "total": 38, "hasMore": true, "durationMs": 150 } } ``` ## Пример ответа при ошибке 400 — оператор или неподдерживаемое поле в фильтре: ```json { "success": false, "error": { "code": "UNSUPPORTED_FILTER", "message": "UNSUPPORTED_FILTER: operators are not supported on 'storages' (near 'id'). Its Bitrix24 method (disk.storage.getlist) filters by exact match only — operators are silently ignored by Bitrix24. Use exact match (field: value) or $in (field: {$in: [...]}) on: id, name, code, entityType, entityId." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSUPPORTED_FILTER` | Оператор или неподдерживаемое поле в фильтре. Фильтруйте точным равенством или `$in` по `id`, `name`, `code`, `entityType`, `entityId` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `disk` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Выборки больше 5000 записей.** За один ответ возвращается до 5000 хранилищ. Общее число записей под фильтром приходит в `meta.total`, признак наличия продолжения — в `meta.hasMore`. Если под фильтр попадает больше 5000 записей, читайте продолжение параметром `offset`, увеличивая его на размер полученной порции. ## Смотрите также - [Список хранилищ](/docs/entities/storages/list) - [Получить хранилище](/docs/entities/storages/get) - [Поля хранилища](/docs/entities/storages/fields) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Task Comments: Comments Batch ## Пакет операций над комментариями `POST /v1/tasks/:taskId/comments/batch` Массовое создание, обновление или удаление комментариев одной задачи. До 50 элементов за вызов. Каждый элемент обрабатывается независимо — ошибка одного не отменяет остальные. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `taskId` (path) | number | да | ID задачи | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `action` | string | ★ | Тип операции: `create`, `update` или `delete` | | `items` | array | при `create` / `update` | Список элементов (до 50). Для `create`: `[{ message: string }]`. Для `update`: `[{ id: number, message: string }]` | | `ids` | number[] | при `delete` | Идентификаторы комментариев для удаления (до 50) | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/tasks/289/comments/batch" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "action": "create", "items": [ { "message": "Шаг 1: подготовил черновик." }, { "message": "Шаг 2: отправил на ревью." } ] }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/tasks/289/comments/batch" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "action": "create", "items": [ { "message": "Шаг 1: подготовил черновик." }, { "message": "Шаг 2: отправил на ревью." } ] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289/comments/batch', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ action: 'create', items: [ { message: 'Шаг 1: подготовил черновик.' }, { message: 'Шаг 2: отправил на ревью.' }, ], }), }) const { success, data } = await res.json() data.forEach((item) => { if (item.success) console.log(`#${item.index} → id=${item.id}`) else console.log(`#${item.index} → ошибка: ${item.error}`) }) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289/comments/batch', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ action: 'create', items: [ { message: 'Шаг 1: подготовил черновик.' }, { message: 'Шаг 2: отправил на ревью.' }, ], }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` — даже если все элементы упали, верхний уровень success. Смотрите статус каждого в `data[i]` | | `data` | array | Массив результатов в том же порядке, что и `items` / `ids` запроса | | `data[].index` | number | Индекс элемента (0-based) | | `data[].success` | boolean | Результат конкретной операции | | `data[].id` | number \| null | ID комментария при `create` / `update`. Изредка `null` при `success: true` — комментарий создан, но id не восстановился (см. [`POST /v1/tasks/:taskId/comments`](./create.md) «Известные особенности»). Если Битрикс24 вообще не создал комментарий (задача не существует/недоступна) — это отдельный случай, `success: false` + `error: TASK_NOT_FOUND`, id не возвращается | | `data[].error` | string | Код ошибки для упавшего элемента (`GONE`, `BATCH_ITEM_VALIDATION`, `BITRIX_ERROR`, `INVALID_PARAMS`, `TASK_NOT_FOUND`) | | `data[].message` | string | Текст ошибки для упавшего элемента | ## Пример ответа `action: create` на новой карточке — обе записи попали в чат задачи: ```json { "success": true, "data": [ { "index": 0, "success": true, "id": 36571 }, { "index": 1, "success": true, "id": 36573 } ] } ``` `action: update` на новой карточке — каждая попытка обновления превращается в `GONE` (метод недоступен): ```json { "success": true, "data": [ { "index": 0, "success": false, "error": "GONE", "message": "Bitrix24 disabled update/delete for task comments in the new task card. To remove a comment, delete the source task or ask a portal admin to remove the message via the chat UI." } ] } ``` ## Пример ответа при ошибке 400 — некорректное значение `action`: ```json { "success": false, "error": { "code": "INVALID_BATCH_ACTION", "message": "Action must be one of: create, update, delete" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `taskId` не положительное целое | | 400 | `INVALID_BATCH_ACTION` | `action` не равен `create`, `update` или `delete` | | 400 | `BATCH_ITEM_VALIDATION` | `items` (или `ids` при `delete`) пустой или не массив | | 400 | `BATCH_LIMIT_EXCEEDED` | В одном запросе передано более 50 элементов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `task` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Ошибки отдельных элементов приходят внутри `data[i].error`: | Код | Описание | |-----|----------| | `GONE` | Только для `update` / `delete` на новой карточке — операция недоступна на стороне Битрикс24 | | `BATCH_ITEM_VALIDATION` | Элемент не прошёл валидацию (например, нет `id` или `message`, неверный тип) | | `INVALID_PARAMS` | `message` отсутствует или превышает лимит длины | | `BITRIX_ERROR` | Битрикс24 вернул ошибку для конкретного элемента (текст в `message`) | | `TASK_NOT_FOUND` | Только для `create` — задача `taskId` не существует или недоступна ключу, комментарий не создан | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Верхний `success` всегда `true`, если запрос прошёл валидацию.** Несколько упавших элементов внутри не превращают весь ответ в ошибку — это сделано специально, чтобы клиент мог обработать частичный результат. Перед использованием результата всегда проверяйте `data[i].success` для каждого элемента. **`GONE` приходит для каждого элемента отдельно.** На новой карточке `update` / `delete` каждого элемента возвращает `GONE`, но общий ответ остаётся `200 success` — весь пакет не отклоняется. В смешанных сценариях часть элементов на старой карточке проходит, часть на новой возвращает `GONE`. **`create` различает «не создано» и «создано, id неизвестен».** Если задача не существует/недоступна — элемент падает с `TASK_NOT_FOUND` (`success: false`, `id` отсутствует). Если же комментарий реально создан (ушёл в чат задачи), но система не смогла подтвердить его id поиском по последним сообщениям — элемент остаётся `success: true` с `id: null`; повторный вызов создаст дубликат, а не восстановит прежний id. ## Смотрите также - [Создать комментарий](./create.md) - [Обновить комментарий](./update.md) - [Удалить комментарий](./delete.md) - [Универсальный batch](/docs/batch) - [Задачи](/docs/entities/tasks) --- # Task Comments: Create ## Создать комментарий `POST /v1/tasks/:taskId/comments` Добавляет комментарий к задаче. На новой карточке задачи сообщение отправляется в чат, на старой — попадает в блок комментариев в самой карточке. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `taskId` (path) | number | да | ID задачи | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `message` | string | ★ | Текст комментария, до 65 535 символов. Поддерживает BB-код (`[USER=ID]Имя[/USER]`, `[B]...[/B]`, `[QUOTE]...[/QUOTE]`) | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/tasks/289/comments" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "message": "Добавил черновик отчёта — посмотри, пожалуйста." }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/tasks/289/comments" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "message": "Добавил черновик отчёта — посмотри, пожалуйста." }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289/comments', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ message: 'Добавил черновик отчёта — посмотри, пожалуйста.', }), }) const { success, data } = await res.json() console.log('ID нового комментария:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289/comments', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ message: 'Добавил черновик отчёта — посмотри, пожалуйста.', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number \| null | Идентификатор нового комментария. На новой карточке возвращается id чат-сообщения, в редком случае может быть `null` — см. «Известные особенности» | ## Пример ответа HTTP 201 Created: ```json { "success": true, "data": { "id": 36559 } } ``` ## Пример ответа при ошибке 400 — пустой или отсутствующий `message`: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "`message` is required and must be a string" } } ``` 404 — задача не существует или недоступна: ```json { "success": false, "error": { "code": "TASK_NOT_FOUND", "message": "Bitrix24 did not create the comment (returned false). Task 99999999 may not exist or may not be accessible." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `taskId` не положительное целое | | 400 | `INVALID_PARAMS` | Поле `message` отсутствует или не является строкой | | 400 | `INVALID_PARAMS` | `message` превышает лимит длины | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `task` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 404 | `TASK_NOT_FOUND` | Задача `taskId` не существует или недоступна ключу — Битрикс24 не создал комментарий | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`data.id` изредка бывает `null` при успехе (`success: true`).** На новой карточке задачи комментарий уходит в чат (`tasks.task.chat.message.send`), а id восстанавливается отдельным поиском по последним сообщениям чата. Если восстановить id не удалось (сообщение не нашлось в окне поиска), комментарий **уже создан**, но ответ возвращает `id: null` — это не ошибка, повторный запрос создаст дубликат. Если же Битрикс24 в принципе не создал комментарий (задача не существует или недоступна), это отдельный случай — API возвращает `404 TASK_NOT_FOUND`, а не `201` с `id: null`. ## Смотрите также - [Список комментариев](./list.md) - [Получить комментарий](./get.md) - [Пакет операций](./comments-batch.md) - [Задачи](/docs/entities/tasks) - [Лимиты и оптимизация](/docs/optimization) --- # Task Comments: Delete ## Удалить комментарий `DELETE /v1/tasks/:taskId/comments/:id` Удаляет комментарий задачи. Доступно только на порталах со старой карточкой задачи: на новой карточке метод возвращает `410 GONE`. Восстановить удалённый комментарий через API нельзя. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `taskId` (path) | number | да | ID задачи | | `id` (path) | number | да | ID комментария | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/tasks/289/comments/36559" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/tasks/289/comments/36559" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289/comments/36559', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Комментарий удалён') } else if (res.status === 410) { const { error } = await res.json() console.log('Новая карточка — удаление недоступно:', error.message) } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289/comments/36559', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) ``` ## Ответ При успешном удалении на старой карточке возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. На новой карточке вместо `204` приходит `410 GONE` с JSON-телом (см. ниже). ## Пример ответа Старая карточка: ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 410 — новая карточка задачи (метод недоступен): ```json { "success": false, "error": { "code": "GONE", "message": "Bitrix24 disabled update/delete for task comments in the new task card. To remove a comment, delete the source task or ask a portal admin to remove the message via the chat UI.", "hint": "Verified against apidocs.bitrix24.ru on 2026-05-09 — the modern task-chat API accepts only new messages, no edit or delete." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `taskId` или `id` не являются положительными целыми | | 410 | `GONE` | Задача создана на новой карточке — удаление комментария на стороне Битрикс24 недоступно | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `task` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Альтернатива для новой карточки.** Способов программно удалить отправленный комментарий нет. Если содержимое нужно скрыть — удалите задачу целиком ([`DELETE /v1/tasks/:id`](/docs/entities/tasks/delete)), либо попросите администратора портала удалить сообщение через интерфейс чата. ## Смотрите также - [Список комментариев](./list.md) - [Получить комментарий](./get.md) - [Обновить комментарий](./update.md) - [Задачи](/docs/entities/tasks) --- # Task Comments: Fields ## Поля комментария `GET /v1/tasks/:taskId/comments/fields` Возвращает схему полей комментария задачи: для каждого из пяти полей — тип, признак «только для чтения», отображаемое название и описание. Помогает автогенерации кода и подсказкам AI-агентам. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `taskId` (path) | number | да | ID задачи. Значение не проверяется — схема одинакова для любого, включая несуществующую задачу | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/tasks/289/comments/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/tasks/289/comments/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289/comments/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Поля комментария:', Object.keys(data.fields)) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289/comments/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа `data.fields` — объект, ключ которого — имя поля, а значение — `{ type, readonly, label, description }`. | Поле | Тип | RO | Описание | |------|-----|----|---------| | `id` | number | да | Идентификатор комментария. Может прийти `null` в ответе создания на новой карточке | | `taskId` | number | да | Идентификатор родительской задачи. Берётся из пути URL | | `authorId` | number | да | Автор комментария. Список сотрудников: `GET /v1/users` | | `message` | string | | Текст комментария, до 65 535 символов. Единственное записываемое поле, обязателен при создании. Поддерживает BB-код | | `createdAt` | datetime | да | Дата и время создания, UTC ISO 8601 | Поля с отметкой RO (`readonly: true`) заполняются платформой и не принимаются при создании и обновлении. Записывается только `message`. ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "Идентификатор", "description": "Идентификатор комментария.", "nullable": true }, "taskId": { "type": "number", "readonly": true, "label": "Идентификатор задачи", "description": "Идентификатор родительской задачи (из пути запроса)." }, "authorId": { "type": "number", "readonly": true, "label": "Идентификатор автора", "description": "Идентификатор пользователя, оставившего комментарий, — из GET /v1/users." }, "message": { "type": "string", "readonly": false, "label": "Текст", "description": "Текст комментария. Обязателен при создании." }, "createdAt": { "type": "datetime", "readonly": true, "label": "Дата создания", "description": "Дата создания, UTC ISO 8601." } } } } ``` ## Пример ответа при ошибке 403 — у ключа нет скоупа `task`: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'task' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `task` | | 401 | `MISSING_API_KEY` | Заголовок `X-Api-Key` не передан | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список комментариев](./list.md) - [Создать комментарий](./create.md) - [Сотрудники](/docs/entities/users) - [Задачи](/docs/entities/tasks) --- # Task Comments: Get ## Получить комментарий `GET /v1/tasks/:taskId/comments/:id` Возвращает один комментарий задачи по его идентификатору. Работает и для комментариев из чата новой карточки, и для записей в блоке комментариев старой карточки. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `taskId` (path) | number | да | ID задачи | | `id` (path) | number | да | ID комментария (из `GET /v1/tasks/:taskId/comments` или ответа `POST /v1/tasks/:taskId/comments`) | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/tasks/289/comments/36559" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/tasks/289/comments/36559" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289/comments/36559', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log(data.message) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289/comments/36559', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Идентификатор комментария | | `data.taskId` | number | ID родительской задачи | | `data.authorId` | number | Автор. Профиль: `GET /v1/users/:authorId` | | `data.message` | string | Текст комментария (поддерживает BB-код) | | `data.createdAt` | datetime | Дата создания (UTC ISO 8601) | ## Пример ответа ```json { "success": true, "data": { "id": 36559, "taskId": 289, "authorId": 1, "message": "Добавил черновик отчёта в комментарии — посмотри, пожалуйста.", "createdAt": "2026-05-13T12:30:58.000Z" } } ``` ## Пример ответа при ошибке 404 — комментарий не найден: ```json { "success": false, "error": { "code": "NOT_FOUND", "message": "Comment not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `taskId` или `id` не являются положительными целыми числами | | 404 | `NOT_FOUND` | Комментарий с таким `id` не найден ни в чате, ни в блоке комментариев старой карточки | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `task` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Двухступенчатый поиск.** На новой карточке API сначала ищет комментарий среди последних 200 сообщений чата задачи. Если совпадения нет — например, комментарий старше 200 последних или относится к старой карточке — запрос автоматически идёт по старому пути чтения. Это прозрачно для клиента: формат ответа одинаковый. ## Смотрите также - [Список комментариев](./list.md) - [Создать комментарий](./create.md) - [Обновить комментарий](./update.md) - [Удалить комментарий](./delete.md) - [Задачи](/docs/entities/tasks) --- # Task Comments: List ## Список комментариев `GET /v1/tasks/:taskId/comments` Возвращает комментарии конкретной задачи. На новой карточке задачи список читается из чата, системные сообщения отфильтрованы. На старой — из блока комментариев в самой карточке. ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `taskId` (path) | number | да | — | ID родительской задачи | | `limit` (query) | number | | `50` | Размер страницы (до 200) | | `offset` (query) | number | | `0` | Сколько подошедших комментариев пропустить перед выдачей. Учитывается на новой карточке при запросе с `filter` или сортировкой не по `ID`, на остальных путях чтения игнорируется | | `sort` (query) | string | | `id:desc` | Сортировка: поле `ID`, `AUTHOR_ID` или `POST_DATE` и направление `asc` либо `desc` — `?sort=post_date:desc`. Имя поля регистронезависимо. Сортировка по `AUTHOR_NAME` и `AUTHOR_EMAIL` принимается только на старой карточке, на новой возвращает `400 UNSUPPORTED_SORT_FIELD` | | `filter` (query) | object | | — | Фильтр по полям `ID`, `AUTHOR_ID`, `POST_DATE`. Передаётся как JSON: `?filter={"AUTHOR_ID":1}`. Перед именем поля допустим префикс `!`, `>`, `>=`, `<` или `<=` — `?filter={">=POST_DATE":"2026-05-01T00:00:00Z"}`. Значение для `POST_DATE` — дата ISO 8601 в UTC, несколько полей объединяются по «и». Фильтр по `AUTHOR_NAME` принимается только на старой карточке, на новой возвращает `400 UNSUPPORTED_FILTER_FIELD` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/tasks/289/comments?limit=20&sort=id:desc" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/tasks/289/comments?limit=20&sort=id:desc" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const url = 'https://vibecode.bitrix24.tech/v1/tasks/289/comments?limit=20&sort=id:desc' const res = await fetch(url, { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Получено ${data.length} комментариев`) ``` ### JavaScript — OAuth-приложение ```javascript const url = 'https://vibecode.bitrix24.tech/v1/tasks/289/comments?limit=20&sort=id:desc' const res = await fetch(url, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив комментариев | | `data[].id` | number | Идентификатор комментария | | `data[].taskId` | number | ID родительской задачи | | `data[].authorId` | number | Автор. Профиль: `GET /v1/users/:authorId` | | `data[].message` | string | Текст комментария (поддерживает BB-код) | | `data[].createdAt` | datetime | Дата создания (UTC ISO 8601) | | `meta.total` | number | Количество комментариев. На новой карточке при запросе с `filter` или сортировкой не по `ID` — точное число подошедших под фильтр в пределах просмотренного окна, на остальных путях чтения — оценка | | `meta.hasMore` | boolean | Есть ли ещё комментарии за пределами `limit` | | `meta.truncated` | boolean | Приходит только со значением `true` и только на новой карточке при запросе с `filter` или сортировкой не по `ID`: просмотрено предельное окно, и часть комментариев осталась за его границей | ## Пример ответа ```json { "success": true, "data": [ { "id": 36559, "taskId": 289, "authorId": 1, "message": "Добавил черновик отчёта в комментарии — посмотри, пожалуйста.", "createdAt": "2026-05-13T12:30:58.000Z" }, { "id": 36557, "taskId": 289, "authorId": 79, "message": "[USER=99]Зуля[/USER], готово, спасибо.", "createdAt": "2026-05-12T15:11:04.000Z" } ], "meta": { "total": 2, "hasMore": false } } ``` ## Пример ответа при ошибке 400 — `taskId` не положительное целое: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "taskId must be a positive integer" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `taskId` некорректен (не целое положительное число) | | 400 | `INVALID_SORT_FIELD` | Сортировка по неподдерживаемому полю или направлению. Поддерживаются `ID`, `AUTHOR_ID`, `AUTHOR_NAME`, `AUTHOR_EMAIL`, `POST_DATE` с направлением `asc` или `desc`. На новой карточке `AUTHOR_NAME` и `AUTHOR_EMAIL` отвечают `UNSUPPORTED_SORT_FIELD` | | 400 | `UNSUPPORTED_SORT_FIELD` | Только новая карточка: сортировка по `AUTHOR_NAME` или `AUTHOR_EMAIL`. Отсортируйте по `ID`, `AUTHOR_ID` или `POST_DATE` | | 400 | `INVALID_FILTER` | Параметр `filter` не является корректным JSON. Только новая карточка: `filter` — скаляр или пустой массив вместо объекта (`0`, `false`, `""`, `[]`), значение поля `ID` или `AUTHOR_ID` не число, значение `POST_DATE` не разбирается как дата, либо значение поля — объект или массив вместо скаляра. Непустой массив или непустая строка в `filter` дают `UNKNOWN_FILTER_FIELD` — их индексы разбираются как имена полей | | 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по неподдерживаемому полю. Поддерживаются `ID`, `AUTHOR_ID`, `AUTHOR_NAME`, `POST_DATE`. На новой карточке `AUTHOR_NAME` отвечает `UNSUPPORTED_FILTER_FIELD` | | 400 | `UNSUPPORTED_FILTER_FIELD` | Только новая карточка: фильтр по `AUTHOR_NAME`. Отфильтруйте по `ID`, `AUTHOR_ID` или `POST_DATE`, идентификатор сотрудника по имени — `GET /v1/users` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `task` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Окно просмотра при фильтрации.** На новой карточке запрос с `filter` или сортировкой не по `ID` просматривает до 2000 самых новых сообщений чата задачи, включая системные уведомления, и отбирает подошедшие комментарии из них. Если история задачи длиннее или ограничена тарифом портала, приходит `meta.truncated: true`: за границей окна остались комментарии, которых нет в ответе, а `meta.total` считает только попавшие в окно. Это не признак следующей страницы — `offset` окно не сдвинет. Сузьте выборку фильтром по `POST_DATE` или `AUTHOR_ID`. По той же причине `?sort=post_date:asc` на такой задаче вернёт самые старые комментарии в пределах окна, а не самые старые в задаче. **Фильтр и сортировка по автору — через `AUTHOR_ID`.** Поля `AUTHOR_NAME` и `AUTHOR_EMAIL` принимаются на старой карточке и возвращают `400` на новой, поэтому запрос по имени автора работает не на каждом портале. Чтобы выборка не зависела от того, как настроен портал, найдите сотрудника через `GET /v1/users` и фильтруйте или сортируйте по `AUTHOR_ID`. **Пустая страница при `meta.hasMore: true`.** Системные уведомления о постановке задачи, смене срока и назначении исполнителя отфильтровываются на стороне API. На запросе без `filter` и с сортировкой по `ID`, если весь текущий срез состоит из них, `data` приходит пустым при `meta.hasMore: true`. На этом пути чтения `meta.total` — оценка, и в таком срезе она приходит равной `1` при пустом `data`. Это не ошибка: ведите пагинацию по `meta.hasMore` и содержимому `data`, а не по `meta.total` — запросите следующую страницу или увеличьте `limit`. ## Смотрите также - [Получить комментарий](./get.md) - [Создать комментарий](./create.md) - [Пакет операций](./comments-batch.md) - [Задачи](/docs/entities/tasks) - [Лимиты и оптимизация](/docs/optimization) --- # Task Comments: Update ## Обновить комментарий `PATCH /v1/tasks/:taskId/comments/:id` Изменяет текст существующего комментария задачи. Доступно только на порталах со старой карточкой задачи: на новой карточке метод возвращает `410 GONE` с пояснением. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `taskId` (path) | number | да | ID задачи | | `id` (path) | number | да | ID комментария | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `message` | string | ★ | Новый текст комментария, до 65 535 символов | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/tasks/289/comments/36559" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "message": "Уточнил формулировку в комментарии." }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/tasks/289/comments/36559" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "message": "Уточнил формулировку в комментарии." }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289/comments/36559', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ message: 'Уточнил формулировку в комментарии.', }), }) const { success, data, error } = await res.json() if (res.status === 410) console.log('Новая карточка — обновление недоступно:', error.message) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289/comments/36559', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ message: 'Уточнил формулировку в комментарии.', }), }) const { success, data, error } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | `true` при успешном обновлении на старой карточке | | `data.id` | number | Идентификатор обновлённого комментария | ## Пример ответа Старая карточка — обновление применилось: ```json { "success": true, "data": { "id": 36559 } } ``` ## Пример ответа при ошибке 410 — новая карточка задачи (метод недоступен): ```json { "success": false, "error": { "code": "GONE", "message": "Bitrix24 disabled update/delete for task comments in the new task card. To remove a comment, delete the source task or ask a portal admin to remove the message via the chat UI.", "hint": "Verified against apidocs.bitrix24.ru on 2026-05-09 — the modern task-chat API accepts only new messages, no edit or delete." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `taskId` или `id` не являются положительными целыми | | 410 | `GONE` | Задача создана на новой карточке — обновление комментария на стороне Битрикс24 недоступно | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `task` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Альтернатива для новой карточки.** Способов программно изменить отправленный комментарий нет. Если содержимое критично — удалите задачу целиком ([`DELETE /v1/tasks/:id`](/docs/entities/tasks/delete)) и создайте новую, либо попросите администратора портала удалить сообщение через интерфейс чата. ## Смотрите также - [Получить комментарий](./get.md) - [Создать комментарий](./create.md) - [Удалить комментарий](./delete.md) - [Задачи](/docs/entities/tasks) --- # Tasks: Aggregate ## Агрегация задач `POST /v1/tasks/aggregate` Подсчёт количества задач с фильтрацией и группировкой. Числовые функции работают по числовым полям задачи и пользовательским полям подходящих типов. **Стандартные поля:** - `status` — статус задачи (для `groupBy`, для числовых функций смысла нет — это категориальный код). `groupBy: "status"` группирует по **фактическому сохранённому** статусу — это значение поля `status` в ответе, а не виртуальная мета-ось фильтра `filter[status]` - `priority` — приоритет (для `groupBy`) - `responsibleId` — ответственный (для `groupBy`, идентификатор) - `groupId` — рабочая группа (для `groupBy`, идентификатор) Все стандартные `aggregatable` поля — идентификаторы или категориальные коды, поэтому по ним работают `count` и `groupBy`. Для числовых функций (`sum`/`avg`/`min`/`max`) подходящие встроенные кандидаты — `timeEstimate` (оценка трудозатрат в секундах), `timeSpentInLogs` (фактически затраченное время в секундах) или пользовательские поля. В `groupBy` эти два поля не принимаются — из встроенных там доступны только четыре перечисленных выше. > **Ограничение выборки по статусу.** Чтобы посчитать только открытые/завершённые задачи, добавьте в `filter` поле `realStatus` (фактический статус): `{"filter": {"realStatus": 2}}`. `filter[status]` здесь тоже виртуальный (мета-ось `−1/−2/−3`), а не число из ответа. Само `realStatus` — только для `filter`/`sort`, в `groupBy` его нет: для разбивки по статусу используйте `groupBy: "status"` (он группирует по фактическому статусу, см. выше). **Пользовательские поля (UF):** UF-поля типов `integer`, `double`, `money` принимаются в числовых функциях. UF любого типа — в `groupBy`. Полный список UF-полей конкретного портала приходит в тексте ошибки `INVALID_PARAMS`, если передать несуществующее имя. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций. Каждый элемент: `{ "field": "timeEstimate", "function": "sum" }`. Функции: `count`, `sum`, `avg`, `min`, `max`. Для `count` поле — `"*"`. Без параметра — только count | | `filter` | object | нет | Фильтрация по полям `GET /v1/tasks/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `{"responsibleId": 1}` | | `groupBy` | string \| string[] | нет | Поле или массив полей для группировки (максимум 5). Принимает UF-поля любого типа | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/tasks/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "timeEstimate", "function": "sum" } ], "groupBy": "status" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/tasks/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "timeEstimate", "function": "sum" } ], "groupBy": "status" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [{ field: 'timeEstimate', function: 'sum' }], groupBy: 'status', }), }) const { success, data } = await res.json() console.log('Всего задач:', data.count) console.log('По статусам:', data.groups) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [{ field: 'timeEstimate', function: 'sum' }], groupBy: 'status', }), }) const { success, data } = await res.json() ``` > Для группировки по нескольким полям передайте массив: `"groupBy": ["status", "responsibleId"]` (максимум 5). ## Другие сценарии Подсчёт записей — `count` с полем `"*"`, самый быстрый запрос без выгрузки записей. Без массива `aggregate` результат тот же: ```json { "aggregate": [{ "field": "*", "function": "count" }] } ``` Сколько задач у каждого ответственного: ```json { "groupBy": "responsibleId" } ``` Сумма по UF-полю числового типа в разрезе приоритета: ```json { "aggregate": [{ "field": "UF_CRM_TASK_BUDGET", "function": "sum" }], "groupBy": "priority" } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Количество записей, соответствующих фильтру | | `data.aggregates` | object | Результаты агрегаций. Без `aggregate` — пустой объект | | `data.groups` | array | Группы (только при `groupBy`). Каждый элемент: поля группировки + `count` + `aggregates` | | `data.meta.totalRecords` | number | Общее количество записей | | `data.meta.recordsProcessed` | number | Сколько записей реально обработано | | `data.meta.truncated` | boolean | `true`, если попали в ограничение 5000 — агрегация и группы построены по первым 5000 записям | | `data.meta.groupTotal` | number | Общее количество групп (только при `groupBy`) | | `data.meta.groupsTruncated` | boolean | Был ли список групп ограничен `groupLimit` | ## Пример ответа Ответ на основной запрос (`aggregate: [{field: "timeEstimate", function: "sum"}]` + `groupBy: "status"`): ```json { "success": true, "data": { "count": 599, "aggregates": { "timeEstimate": { "sum": 54000 } }, "groups": [ { "status": "2", "count": 247, "aggregates": { "timeEstimate": { "sum": 18000 } } }, { "status": "5", "count": 341, "aggregates": { "timeEstimate": { "sum": 32400 } } }, { "status": "3", "count": 7, "aggregates": { "timeEstimate": { "sum": 2400 } } }, { "status": "4", "count": 4, "aggregates": { "timeEstimate": { "sum": 1200 } } } ], "meta": { "totalRecords": 599, "recordsProcessed": 599, "truncated": false, "groupTotal": 4, "groupsTruncated": false } } } ``` Без `groupBy` поле `data.groups` в ответе отсутствует. ## Пример ответа при ошибке 400 — несуществующее поле: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "Unknown field 'noSuchField'. Available: status, priority, responsibleId, groupId, UF_CRM_TASK_BUDGET, …" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Неизвестная функция или несуществующее поле — сообщение содержит список допустимых (стандартных + UF) | | 400 | `INVALID_PARAMS` | UF-поле нечислового типа (`string`, `enumeration`, `date`) в `sum`/`avg`/`min`/`max` — сообщение называет тип | | 400 | `INVALID_PARAMS` | `groupBy` по стандартному полю вне списка `aggregatable` | | 400 | `INVALID_PARAMS` | Больше 5 полей в `groupBy` | | 400 | `INVALID_PARAMS` | Зарезервированные ключевые слова в `groupBy`: `count`, `aggregates`, `meta`, `groups` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `tasks` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`count` против числовых функций.** `count` считается одним вызовом и работает на любом объёме. `sum`/`avg`/`min`/`max` подгружают записи постранично (максимум 5000) и считают на стороне API. При выборках свыше 5000 — `meta.truncated: true`, агрегация по первым 5000. Для точных счётчиков на больших выборках используйте `count` или сужайте фильтр. ## Смотрите также - [Список задач](./list.md) - [Поиск задач](./search.md) - [Поля задачи](./fields.md) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Tasks: Chat # Чат задачи `GET /v1/tasks/:taskId/chat/messages` Читает ленту чата задачи — новые сообщения первыми. У каждой задачи в Битрикс24 есть групповой чат, и эндпоинт сам определяет чат по ID задачи — знать ID чата не нужно. Типичный сценарий — выгрузка финальных сообщений по закрытой задаче. Битрикс24 API: `im.v2.Chat.Message.tail` (на старых порталах — `im.dialog.messages.get`) Скоуп: `task`, `im` ## Параметры запроса (query) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `limit` | number | | Сообщений на страницу, 1..200, по умолчанию 50 | | `lastId` | number | | Курсор: вернуть сообщения старше этого `id`. Для следующей страницы передайте минимальный `id` из текущей | ## Пример ```bash curl "https://vibecode.bitrix24.tech/v1/tasks/53/chat/messages?limit=50" \ -H "X-Api-Key: YOUR_API_KEY" ``` Ответ: ```json { "success": true, "data": { "messages": [ { "id": 9123, "authorId": 20294, "text": "Релиз 24.500.0 готов", "createdAt": "2026-06-10T14:51:00+02:00", "isSystem": false } ], "hasNextPage": true } } ``` ## Поля сообщения | Поле | Описание | |------|---------| | `id` | ID сообщения — используйте минимальный из страницы как `lastId` для следующей | | `authorId` | Автор (`0` у системных сообщений) | | `text` | Текст сообщения. Может содержать BB-коды Битрикс24 | | `createdAt` | Дата создания, ISO 8601 | | `isSystem` | Системное сообщение («задача поставлена», «срок изменён», …) — фильтруйте по этому флагу, если нужны только реплики людей | ## Что нужно знать перед работой 1. **Нужен скоуп `im` на стороне Битрикс24.** Эндпоинт читает чат через `im.*`-методы Битрикс24 — вебхук или OAuth-грант ключа должен включать скоуп `im` помимо `task`, иначе портал вернёт `insufficient_scope`. 2. **Доступ — по членству в чате.** Битрикс24 отдаёт сообщения, только если пользователь, от имени которого работает ключ, — участник чата задачи (постановщик, исполнитель, наблюдатель) или администратор портала. 3. **Сообщения идут от новых к старым.** Первый элемент — самое свежее сообщение. Пагинация курсором `lastId` уходит вглубь истории. 4. **404, если чата ещё нет.** Битрикс24 создаёт чат задачи не сразу — у задачи без единого сообщения чата может не быть (`TASK_CHAT_NOT_FOUND`). 5. **Старые порталы.** На порталах без современной `im.v2`-поверхности API прозрачно переключается на устаревший метод: страница там ограничена 50 сообщениями, а `hasNextPage` вычисляется по заполненности страницы. 6. **Комментарии и чат.** [`GET /v1/tasks/:taskId/comments`](../task-comments.md) возвращает только пользовательские комментарии. Этот эндпоинт — сырую ленту чата целиком, включая системные сообщения. ## Ошибки | HTTP | Код | Причина | |------|-----|---------| | 400 | `INVALID_PARAMS` | Нечисловой `taskId`, нечисловой или неположительный `limit` либо `lastId`. Значение `limit` больше 200 не ошибка — оно ограничивается до 200 | | 403 | `SCOPE_DENIED` | У ключа нет скоупа `task` | | 404 | `TASK_CHAT_NOT_FOUND` | У задачи нет чата (или задачи не существует) | | 422 | `BITRIX_ERROR` | Ошибка Битрикс24: `insufficient_scope` (нет `im`), `ACCESS_ERROR` (не участник чата) | ## Смотрите также - [Задачи](../tasks.md) - [Комментарии задач](../task-comments.md) - [Scrum](/docs/scrum) --- # Tasks: Checklist # Чек-лист задачи Пункты чек-листа задачи — вложенный ресурс задачи. У каждого пункта есть название, статус выполнения, признак важности, порядок сортировки, участники и (опционально) родительский пункт для вложенных чек-листов. Базовый путь — `/v1/tasks/:taskId/checklist`. Все операции адресуются идентификатором задачи `:taskId`. Битрикс24 API: `task.checklistitem.*` Скоуп: `task` > **Почему отдельный ресурс.** Битрикс24 **не принимает** поле `CHECKLIST` внутри `POST /v1/tasks` (`tasks.task.add`) — чек-лист нельзя создать вместе с задачей. Единственный поддерживаемый способ управлять пунктами — это методы семейства `task.checklistitem.*`, которые и оборачивает данный ресурс. Сначала создайте задачу, затем добавляйте пункты по одному. ## Операции - [Список пунктов](./checklist/list.md) — `GET /v1/tasks/:taskId/checklist` - [Получить пункт](./checklist/get.md) — `GET /v1/tasks/:taskId/checklist/:itemId` - [Добавить пункт](./checklist/create.md) — `POST /v1/tasks/:taskId/checklist` - [Обновить пункт](./checklist/update.md) — `PATCH /v1/tasks/:taskId/checklist/:itemId` - [Удалить пункт](./checklist/delete.md) — `DELETE /v1/tasks/:taskId/checklist/:itemId` - [Отметить выполненным](./checklist/complete.md) — `POST /v1/tasks/:taskId/checklist/:itemId/complete` - [Вернуть в работу](./checklist/renew.md) — `POST /v1/tasks/:taskId/checklist/:itemId/renew` ## Поля пункта | Поле | Тип | Только чтение | Описание | |------|-----|:---:|---------| | `title` | string | | Текст пункта. **Обязателен при создании.** Если `parentId = 0`, то `title` — название нового чек-листа | | `sortIndex` | integer | | Индекс сортировки. Чем меньше значение, тем выше пункт в списке | | `isComplete` | boolean / `Y`,`N` | | Статус выполнения. При записи принимает `true`/`false` или `"Y"`/`"N"`. В ответе — `"Y"`/`"N"` | | `isImportant` | boolean / `Y`,`N` | | Признак важности. Формат — как у `isComplete` | | `parentId` | integer | | ID родительского пункта для вложенных чек-листов. **`0` создаёт новый чек-лист** в задаче | | `members` | object (запрос) / array (ответ) | | Участники пункта — разный формат на запись и на чтение, см. «Известные особенности» ниже | | `id` | string | да | ID пункта | | `taskId` | string | да | ID родительской задачи | | `createdBy` | string | да | Автор пункта | | `toggledBy` | string | да | Кто последним менял статус выполнения | | `toggledDate` | string | да | Когда статус менялся последний раз | | `attachments` | array | да | Прикреплённые файлы (заполняются в UI Битрикс24) | ## Известные особенности - **Отсутствие задачи проверяется не на всех операциях.** Список пунктов и получение одного пункта отвечают `422`, когда задачи `:taskId` на портале нет. Обновление, отметка выполнения, возврат в работу и удаление в этом случае отвечают успехом и ничего не меняют, поэтому успешный статус этих четырёх операций не подтверждает, что задача и пункт существуют. - **Регистр и типы в ответе.** Ответы приходят в camelCase (`id`, `taskId`, `sortIndex`, `isComplete`). Числовые значения Битрикс24 сериализует **строками** (`"id": "477"`, `"sortIndex": "2"`) — для арифметики приводите через `Number(value)`. Флаги `isComplete` / `isImportant` — это строки `"Y"` / `"N"`, а не булевы значения. - **`members` — разные форматы на запись и на чтение.** При создании/обновлении пункта `members` — объект вида `{ "": { "type": "A" | "U" } }` (`A` — соисполнитель, `U` — наблюдатель, список сотрудников — [`GET /v1/users`](/docs/entities/users)). В ответе (список, получение) `members` — **массив** обогащённых объектов участников: `[{ "id", "type", "name", "personalPhoto", "personalGender", "image", "isCollaber" }]`. Код, который читает участников из ответа, не должен ожидать формат запроса. - **Пункт без указанного `parentId` может лечь в существующий чек-лист автоматически.** Если в задаче уже есть чек-лист-контейнер (пункт с `parentId: 0`), Битрикс24 подставляет его пунктам, созданным без явного `parentId`, вместо того чтобы оставить их на верхнем уровне. ## Типичный сценарий 1. Создать задачу: [`POST /v1/tasks`](../tasks/create.md). 2. (Опционально) создать чек-лист-контейнер: [`POST /v1/tasks/:taskId/checklist`](./checklist/create.md) с `parentId: 0`. 3. Добавить пункты: [`POST /v1/tasks/:taskId/checklist`](./checklist/create.md) (по одному). 4. Отметить пункт выполненным: [`POST /v1/tasks/:taskId/checklist/:itemId/complete`](./checklist/complete.md). 5. Посмотреть прогресс: [`GET /v1/tasks/:taskId/checklist`](./checklist/list.md). ## Смотрите также - [Задачи](../tasks.md) - [Учёт времени](./time.md) - [Комментарии задач](/docs/entities/task-comments) - [Сотрудники](/docs/entities/users) - [Лимиты и оптимизация](/docs/optimization) --- # Tasks: Complete ## Отметить пункт выполненным `POST /v1/tasks/:taskId/checklist/:itemId/complete` Отмечает пункт чек-листа выполненным. Эквивалентно [`PATCH`](./update.md) с телом `{ "isComplete": true }`, но не требует передавать остальные поля. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `taskId` (path) | integer | да | ID задачи | | `itemId` (path) | integer | да | ID пункта чек-листа | Тело запроса не требуется. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/tasks/3943/checklist/213/complete" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/tasks/3943/checklist/213/complete" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch("https://vibecode.bitrix24.tech/v1/tasks/3943/checklist/213/complete", { method: "POST", headers: { "X-Api-Key": "YOUR_API_KEY" }, }); const { data } = await res.json(); ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch("https://vibecode.bitrix24.tech/v1/tasks/3943/checklist/213/complete", { method: "POST", headers: { "X-Api-Key": "YOUR_APP_KEY", "Authorization": "Bearer USER_SESSION_TOKEN", }, }); const { data } = await res.json(); ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | ID пункта | | `data.isComplete` | string | Всегда `"Y"` после успешного вызова | ## Пример ответа ```json { "success": true, "data": { "id": 213, "isComplete": "Y" } } ``` ## Пример ответа при ошибке `400` — некорректный `itemId`: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "taskId and itemId must be positive integers" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `taskId` или `itemId` не положительное целое | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `task` | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ в режиме «только чтение» — переключите на чтение+запись в [/keys](/keys) | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Несуществующие `itemId` и `taskId` тоже дают `200`.** В ответе приходит переданный `itemId` и `isComplete: "Y"`, даже если такого пункта нет — и даже если нет самой задачи. Успешный статус не подтверждает, что пункт существует и что отметка проставлена. Проверить наличие можно через [«Получить пункт»](./get.md), он отвечает `422` и на отсутствующий пункт, и на отсутствующую задачу. ## Смотрите также - [Вернуть в работу](./renew.md) - [Обновить пункт](./update.md) - [Список пунктов](./list.md) - [Задачи](/docs/entities/tasks) --- # Tasks: Create ## Добавить пункт чек-листа `POST /v1/tasks/:taskId/checklist` Добавляет пункт в чек-лист задачи. `title` обязателен. Возвращает `id` нового пункта. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `taskId` (path) | integer | да | ID задачи | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `title` | string | да | Текст пункта. Если `parentId: 0`, становится названием нового чек-листа | | `sortIndex` | integer | нет | Индекс сортировки. Чем меньше значение, тем выше пункт в списке | | `isImportant` | boolean / `Y`,`N` | нет | Признак важности | | `isComplete` | boolean / `Y`,`N` | нет | Статус выполнения при создании | | `parentId` | integer | нет | ID родительского пункта. `0` создаёт новый чек-лист-контейнер в задаче | | `members` | object | нет | Участники пункта: `{ "": { "type": "A" \| "U" } }`. `A` — соисполнитель, `U` — наблюдатель. Список сотрудников — [`GET /v1/users`](/docs/entities/users) | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/tasks/3943/checklist" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Собрать и проверить документы", "sortIndex": 100, "isImportant": true }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/tasks/3943/checklist" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Собрать и проверить документы", "sortIndex": 100, "isImportant": true }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch("https://vibecode.bitrix24.tech/v1/tasks/3943/checklist", { method: "POST", headers: { "X-Api-Key": "YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ title: "Собрать и проверить документы", sortIndex: 100, isImportant: true, }), }); const { data } = await res.json(); ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch("https://vibecode.bitrix24.tech/v1/tasks/3943/checklist", { method: "POST", headers: { "X-Api-Key": "YOUR_APP_KEY", "Authorization": "Bearer USER_SESSION_TOKEN", "Content-Type": "application/json", }, body: JSON.stringify({ title: "Собрать и проверить документы", sortIndex: 100, isImportant: true, }), }); const { data } = await res.json(); ``` Чтобы создать **новый чек-лист** (контейнер верхнего уровня), передайте `parentId: 0` — в этом случае `title` становится названием чек-листа: ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/tasks/3943/checklist" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Документы", "parentId": 0 }' ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | ID нового пункта | ## Пример ответа ```json { "success": true, "data": { "id": 221 } } ``` ## Пример ответа при ошибке `400` — не передан обязательный `title`: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "`title` is required" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Не передан `title`, `taskId` не положительное целое, неизвестный формат `members`, либо `parentId` отрицательный | | 404 | `TASK_NOT_FOUND` | Задача `taskId` не существует или недоступна ключу — перед добавлением пункта Вайбкод проверяет родительскую задачу отдельным вызовом | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `task` | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ в режиме «только чтение» — переключите на чтение+запись в [/keys](/keys) | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **`parentId: 0` создаёт новый чек-лист-контейнер**, а не обычный пункт — `title` в этом случае становится названием контейнера. - **Пункт без указанного `parentId` может лечь в уже существующий чек-лист.** Если в задаче уже есть контейнер (`parentId: 0`), Битрикс24 подставляет его новым пунктам вместо того, чтобы оставить их на верхнем уровне — если нужен независимый контейнер, создавайте его явно через `parentId: 0`. - **`members` на запись — объект по `userId`**, не массив. Формат ответа (в `GET`) отличается — см. [«Список пунктов»](./list.md). ## Смотрите также - [Список пунктов](./list.md) - [Обновить пункт](./update.md) - [Сотрудники](/docs/entities/users) - [Задачи](/docs/entities/tasks) --- # Tasks: Delete ## Удалить пункт чек-листа `DELETE /v1/tasks/:taskId/checklist/:itemId` Удаляет пункт чек-листа. Восстановить удалённый пункт через API нельзя — создавайте новый при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `taskId` (path) | integer | да | ID задачи | | `itemId` (path) | integer | да | ID пункта чек-листа | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/tasks/3943/checklist/213" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/tasks/3943/checklist/213" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch("https://vibecode.bitrix24.tech/v1/tasks/3943/checklist/213", { method: "DELETE", headers: { "X-Api-Key": "YOUR_API_KEY" }, }); if (res.status === 204) { console.log("Удалено"); } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch("https://vibecode.bitrix24.tech/v1/tasks/3943/checklist/213", { method: "DELETE", headers: { "X-Api-Key": "YOUR_APP_KEY", "Authorization": "Bearer USER_SESSION_TOKEN", }, }); if (res.status === 204) { console.log("Удалено"); } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом. Признак успеха — код ответа, не содержимое. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке `400` — некорректный `itemId`: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "taskId and itemId must be positive integers" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `taskId` или `itemId` не положительное целое | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `task` | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ в режиме «только чтение» — переключите на чтение+запись в [/keys](/keys) | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Удаление несуществующего пункта тоже возвращает `204`.** Ответ не отличает удалённый пункт от `itemId`, которого никогда не было, и повторное удаление того же пункта снова даёт `204`. Тот же `204` приходит, когда нет самой задачи `taskId`. Если нужно убедиться, что пункт существовал, прочитайте его до удаления через [«Получить пункт»](./get.md) — он отвечает `422` и на отсутствующий пункт, и на отсутствующую задачу. ## Смотрите также - [Список пунктов](./list.md) - [Получить пункт](./get.md) - [Добавить пункт](./create.md) - [Задачи](/docs/entities/tasks) --- # Tasks: Get ## Получить пункт чек-листа `GET /v1/tasks/:taskId/checklist/:itemId` Возвращает один пункт чек-листа по ID. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `taskId` (path) | integer | да | ID задачи | | `itemId` (path) | integer | да | ID пункта чек-листа. Список пунктов — [`GET /v1/tasks/:taskId/checklist`](./list.md) | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/tasks/3943/checklist/213" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/tasks/3943/checklist/213" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch( "https://vibecode.bitrix24.tech/v1/tasks/3943/checklist/213", { headers: { "X-Api-Key": "YOUR_API_KEY" } } ); const { data } = await res.json(); ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( "https://vibecode.bitrix24.tech/v1/tasks/3943/checklist/213", { headers: { "X-Api-Key": "YOUR_APP_KEY", "Authorization": "Bearer USER_SESSION_TOKEN", }, } ); const { data } = await res.json(); ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | string | ID пункта | | `data.taskId` | string | ID родительской задачи | | `data.parentId` | integer / string | ID родительского пункта. `0` — пункт верхнего уровня | | `data.title` | string | Текст пункта | | `data.sortIndex` | string | Индекс сортировки | | `data.isComplete` | string | Статус выполнения — `"Y"` / `"N"` | | `data.isImportant` | string | Признак важности — `"Y"` / `"N"` | | `data.createdBy` | string | Автор пункта | | `data.toggledBy` | string \| null | Кто последним менял статус выполнения | | `data.toggledDate` | string | Когда статус менялся последний раз. Пустая строка, если не менялся | | `data.members` | array | Участники пункта — объекты `{ id, type, name, personalPhoto, personalGender, image, isCollaber }` | | `data.attachments` | array | Прикреплённые файлы | ## Пример ответа ```json { "success": true, "data": { "id": "213", "taskId": "3943", "parentId": "211", "createdBy": "1317", "title": "Собрать и проверить документы", "sortIndex": "100", "isComplete": "N", "isImportant": "Y", "toggledBy": null, "toggledDate": "", "members": [ { "id": "1317", "type": "A", "name": "Иван Петров", "personalPhoto": "35959", "personalGender": "", "image": "https://example.bitrix24.ru/...", "isCollaber": false } ], "attachments": [] } } ``` ## Пример ответа при ошибке `422` — пункт не найден или недоступен: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "TASKS_ERROR_EXCEPTION_#512; Check listitem not found or not accessible; 512/TE/ITEM_NOT_FOUND_OR_NOT_ACCESSIBLE", "b24Code": "ERROR_CORE" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `taskId` или `itemId` не положительное целое | | 422 | `BITRIX_ERROR` | Пункт с указанным `itemId` удалён, никогда не существовал либо недоступен ключу — Битрикс24 бросил исключение. Тот же код приходит, когда нет самой задачи `taskId` | | 404 | `NOT_FOUND` | Битрикс24 вернул пустой результат без исключения — запасная ветка обработчика | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `task` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Отсутствующий пункт возвращает `422`, а не `404`.** Битрикс24 бросает исключение на несуществующий или удалённый `itemId` — в ответе нет чистого кода `NOT_FOUND`, ориентируйтесь на текст `ITEM_NOT_FOUND_OR_NOT_ACCESSIBLE`. Если Битрикс24 вернёт пустой результат без исключения — придёт `404 NOT_FOUND`. ## Смотрите также - [Список пунктов](./list.md) - [Обновить пункт](./update.md) - [Задачи](/docs/entities/tasks) --- # Tasks: List ## Список пунктов чек-листа `GET /v1/tasks/:taskId/checklist` Возвращает все пункты чек-листа задачи, включая вложенные (дочерние) пункты. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `taskId` (path) | integer | да | ID задачи | | `sort` (query) | string | нет | Сортировка в формате `поле:направление`, например `sortIndex:asc`. Поля: `id`, `parentId`, `createdBy`, `title`, `sortIndex`, `isComplete`, `isImportant`, `toggledBy`, `toggledDate`. Направление — `asc` / `desc` (по умолчанию `asc`). Без параметра Битрикс24 сортирует по `id` по убыванию | | `start` (query) | integer | нет | Смещение в выборке. Битрикс24 отдаёт страницами по 50 пунктов — для следующей страницы передайте `start=50`, затем `100` и так далее | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/tasks/3943/checklist?sort=sortIndex:asc" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/tasks/3943/checklist?sort=sortIndex:asc" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch( "https://vibecode.bitrix24.tech/v1/tasks/3943/checklist?sort=sortIndex:asc", { headers: { "X-Api-Key": "YOUR_API_KEY" } } ); const { data } = await res.json(); ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( "https://vibecode.bitrix24.tech/v1/tasks/3943/checklist?sort=sortIndex:asc", { headers: { "X-Api-Key": "YOUR_APP_KEY", "Authorization": "Bearer USER_SESSION_TOKEN", }, } ); const { data } = await res.json(); ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив пунктов чек-листа | | `data[].id` | string | ID пункта | | `data[].taskId` | string | ID родительской задачи | | `data[].parentId` | integer / string | ID родительского пункта. `0` — пункт верхнего уровня (сам является чек-листом) | | `data[].title` | string | Текст пункта | | `data[].sortIndex` | string | Индекс сортировки | | `data[].isComplete` | string | Статус выполнения — `"Y"` / `"N"` | | `data[].isImportant` | string | Признак важности — `"Y"` / `"N"` | | `data[].createdBy` | string | Автор пункта | | `data[].toggledBy` | string \| null | Кто последним менял статус выполнения | | `data[].toggledDate` | string | Когда статус менялся последний раз. Пустая строка, если не менялся | | `data[].members` | array | Участники пункта — объекты `{ id, type, name, personalPhoto, personalGender, image, isCollaber }` | | `data[].attachments` | array | Прикреплённые файлы | | `meta.total` | number | Общее число пунктов в выборке | ## Пример ответа ```json { "success": true, "data": [ { "id": "211", "taskId": "3943", "parentId": 0, "createdBy": "1317", "title": "Документы", "sortIndex": "1", "isComplete": "N", "isImportant": "N", "toggledBy": null, "toggledDate": "", "members": [], "attachments": [] }, { "id": "213", "taskId": "3943", "parentId": "211", "createdBy": "1317", "title": "Собрать и проверить документы", "sortIndex": "100", "isComplete": "N", "isImportant": "Y", "toggledBy": null, "toggledDate": "", "members": [ { "id": "1317", "type": "A", "name": "Иван Петров", "personalPhoto": "35959", "personalGender": "", "image": "https://example.bitrix24.ru/...", "isCollaber": false } ], "attachments": [] } ], "meta": { "total": 2 } } ``` ## Пример ответа при ошибке `422` — задача не найдена или недоступна: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "TASKS_ERROR_EXCEPTION_#8; Action failed; 8/TE/ACTION_FAILED_TO_BE_PROCESSED", "b24Code": "ERROR_CORE" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `taskId` не положительное целое, либо неизвестное поле сортировки | | 422 | `BITRIX_ERROR` | Задача с указанным `taskId` не существует или недоступна ключу — Битрикс24 бросил исключение. Существующая задача без пунктов отвечает `200` с пустым массивом | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `task` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **`parentId: 0` — пункт верхнего уровня, сам являющийся чек-листом.** Дочерние пункты ссылаются на его `id` через свой `parentId`. - **Числовые значения и флаги — строки.** `id`, `taskId`, `sortIndex` приходят строками. `isComplete` / `isImportant` — строками `"Y"`/`"N"`, не булевыми значениями. ## Смотрите также - [Получить пункт](./get.md) - [Добавить пункт](./create.md) - [Задачи](/docs/entities/tasks) --- # Tasks: Renew ## Вернуть пункт в работу `POST /v1/tasks/:taskId/checklist/:itemId/renew` Снимает отметку о выполнении пункта чек-листа. Эквивалентно [`PATCH`](./update.md) с телом `{ "isComplete": false }`, но не требует передавать остальные поля. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `taskId` (path) | integer | да | ID задачи | | `itemId` (path) | integer | да | ID пункта чек-листа | Тело запроса не требуется. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/tasks/3943/checklist/213/renew" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/tasks/3943/checklist/213/renew" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch("https://vibecode.bitrix24.tech/v1/tasks/3943/checklist/213/renew", { method: "POST", headers: { "X-Api-Key": "YOUR_API_KEY" }, }); const { data } = await res.json(); ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch("https://vibecode.bitrix24.tech/v1/tasks/3943/checklist/213/renew", { method: "POST", headers: { "X-Api-Key": "YOUR_APP_KEY", "Authorization": "Bearer USER_SESSION_TOKEN", }, }); const { data } = await res.json(); ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | ID пункта | | `data.isComplete` | string | Всегда `"N"` после успешного вызова | ## Пример ответа ```json { "success": true, "data": { "id": 213, "isComplete": "N" } } ``` ## Пример ответа при ошибке `400` — некорректный `itemId`: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "taskId and itemId must be positive integers" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `taskId` или `itemId` не положительное целое | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `task` | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ в режиме «только чтение» — переключите на чтение+запись в [/keys](/keys) | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Несуществующие `itemId` и `taskId` тоже дают `200`.** В ответе приходит переданный `itemId` и `isComplete: "N"`, даже если такого пункта нет — и даже если нет самой задачи. Успешный статус не подтверждает, что пункт существует и что он возвращён в работу. Проверить наличие можно через [«Получить пункт»](./get.md), он отвечает `422` и на отсутствующий пункт, и на отсутствующую задачу. ## Смотрите также - [Отметить выполненным](./complete.md) - [Обновить пункт](./update.md) - [Список пунктов](./list.md) - [Задачи](/docs/entities/tasks) --- # Tasks: Update ## Обновить пункт чек-листа `PATCH /v1/tasks/:taskId/checklist/:itemId` Частичное обновление пункта чек-листа — передавайте только изменяемые поля. Хотя бы одно поле обязательно. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `taskId` (path) | integer | да | ID задачи | | `itemId` (path) | integer | да | ID пункта чек-листа | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `title` | string | нет | Текст пункта | | `sortIndex` | integer | нет | Индекс сортировки | | `isComplete` | boolean / `Y`,`N` | нет | Статус выполнения | | `isImportant` | boolean / `Y`,`N` | нет | Признак важности | | `parentId` | integer | нет | ID родительского пункта | | `members` | object | нет | Участники пункта: `{ "": { "type": "A" \| "U" } }`. **Полностью заменяет** текущий список — см. «Известные особенности» | Хотя бы одно из перечисленных полей обязательно — пустое тело возвращает `400`. ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/tasks/3943/checklist/213" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Собрать и проверить документы", "isImportant": true }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/tasks/3943/checklist/213" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Собрать и проверить документы", "isImportant": true }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch("https://vibecode.bitrix24.tech/v1/tasks/3943/checklist/213", { method: "PATCH", headers: { "X-Api-Key": "YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ title: "Собрать и проверить документы", isImportant: true }), }); const { data } = await res.json(); ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch("https://vibecode.bitrix24.tech/v1/tasks/3943/checklist/213", { method: "PATCH", headers: { "X-Api-Key": "YOUR_APP_KEY", "Authorization": "Bearer USER_SESSION_TOKEN", "Content-Type": "application/json", }, body: JSON.stringify({ title: "Собрать и проверить документы", isImportant: true }), }); const { data } = await res.json(); ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | ID обновлённого пункта | ## Пример ответа ```json { "success": true, "data": { "id": 213 } } ``` ## Пример ответа при ошибке `400` — пустое тело запроса: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "No updatable fields provided" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Пустое тело, `taskId`/`itemId` не положительное целое, неизвестный формат `members`, либо нарушен тип поля | | 422 | `BITRIX_ERROR` | Пункт с указанным `itemId` не существует или недоступен ключу — Битрикс24 бросил исключение | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `task` | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ в режиме «только чтение» — переключите на чтение+запись в [/keys](/keys) | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Несуществующий `taskId` даёт `200`.** Если задачи с таким идентификатором нет, ответ приходит успешный, с переданным `itemId`, но ничего не обновляется. Отказ `422` приходит только на несуществующий пункт внутри существующей задачи. Проверить задачу можно через [«Получить задачу»](../get.md). - **`members` заменяется целиком.** При обновлении поля `members` Битрикс24 **полностью** перезаписывает список участников пункта. Чтобы сохранить текущих участников, передайте их вместе с новыми в том же запросе. ## Смотрите также - [Получить пункт](./get.md) - [Список пунктов](./list.md) - [Отметить выполненным](./complete.md) - [Задачи](/docs/entities/tasks) --- # Tasks: Create ## Создать задачу `POST /v1/tasks` Создаёт новую задачу. Минимум — название и ответственный. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `title` | string | ★ | Название задачи | | `responsibleId` | number | ★ | Ответственный. Список сотрудников: `GET /v1/users` | | `description` | string | | Описание задачи. Поддерживает BB-код (`[USER=ID]Имя[/USER]`, `[B]...[/B]`, `[QUOTE]...[/QUOTE]`) | | `priority` | number | | Приоритет: `0` — низкий, `1` — обычный (по умолчанию), `2` — высокий | | `status` | number | | Статус. По умолчанию `2` (ждёт выполнения). Полный список значений: `GET /v1/tasks/fields` → `fields.status.enum` | | `deadline` | datetime | | Крайний срок (ISO 8601) | | `startDatePlan` | datetime | | Плановая дата начала | | `endDatePlan` | datetime | | Плановая дата окончания | | `timeEstimate` | number | | Оценка трудозатрат в секундах | | `groupId` | number | | Рабочая группа. Список: `GET /v1/workgroups` | | `parentId` | number | | Родительская задача. Список: `GET /v1/tasks` | | `accomplices` | number[] | | Соисполнители. Список сотрудников: `GET /v1/users` | | `auditors` | number[] | | Наблюдатели. Список сотрудников: `GET /v1/users` | | `tags` | string[] | | Метки задачи (массив строк-имён, принимаются прямо при создании) | | `ufTaskWebdavFiles` | string[] | | Файлы задачи. Массив строк вида `n`, где `id` — идентификатор файла из ответа [`POST /v1/files/upload`](../files/upload.md). Пример — `["n9759"]`. Полное правило для полей-файлов — [Поля задачи](./fields.md) | | `createdBy` | number | | Постановщик. По умолчанию — пользователь ключа, переопределение применяется в пределах прав вызывающего пользователя. Только существующий сотрудник — см. предупреждение под таблицей. Список сотрудников: `GET /v1/users` | | `changedBy` | number | | Служебное поле: кто последним изменил задачу. Принимается на записи — см. раздел под таблицей. Список сотрудников: `GET /v1/users` | | `closedBy` | number | | Служебное поле: кто закрыл задачу. Принимается на записи — см. раздел под таблицей. Список сотрудников: `GET /v1/users` | | `statusChangedBy` | number | | Служебное поле: кто последним сменил статус. Принимается на записи — см. раздел под таблицей. Список сотрудников: `GET /v1/users` | | `createdDate` | datetime | | Служебное поле: дата создания задачи, ISO 8601. Принимается на записи — см. раздел под таблицей | | `changedDate` | datetime | | Служебное поле: дата последнего изменения, ISO 8601. Переданное значение сохраняется вместо текущего времени — см. раздел под таблицей | | `closedDate` | datetime | | Служебное поле: дата закрытия, ISO 8601. Принимается на записи даже у незакрытой задачи — см. раздел под таблицей | Полный список полей — [`GET /v1/tasks/fields`](./fields.md). Поля `id`, `dateStart`, `activityDate`, `realStatus` заполняются системой и в body не передаются. ### Служебные поля задачи можно задавать Кроме `createdBy`, при создании принимаются `changedBy`, `closedBy`, `statusChangedBy`, `createdDate`, `changedDate`, `closedDate`. Битрикс24 сохраняет переданные значения, а Вайбкод — обёртка над ним и не запрещает того, что разрешает платформа. Принимаются оба написания — и `createdBy`, и `CREATED_BY`. Передавайте одно из двух, а не оба сразу: при обоих в одном теле применится то, которое встретится позже. Те же поля принимаются и при [обновлении](./update.md) — там же разобрано, что остаётся в журнале задачи и как ведёт себя дата без часового пояса. > **Передавайте только существующего сотрудника.** Битрикс24 не проверяет идентификатор пользователя на существование ни в `createdBy`, ни в `changedBy`, `closedBy`, `statusChangedBy` — он запишет любое число. Задача с несуществующим постановщиком перестаёт управляться через API: отказ приходит и на дальнейшее обновление, и на удаление, причём даже ключу администратора и напрямую в Битрикс24, минуя нас. Отменить это через API нельзя. Список сотрудников: [`GET /v1/users`](/docs/entities/users). > **Важно:** название длиннее 250 символов Битрикс24 не отклоняет — он молча обрезает его до 250. Эмодзи перед обрезкой заменяются служебной последовательностью, поэтому название с эмодзи обрезается раньше. Проверяйте `title` в ответе, если длина названия важна. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/tasks" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Подготовить отчёт за квартал", "responsibleId": 1, "priority": 2, "deadline": "2026-05-19T18:00:00+03:00" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/tasks" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Подготовить отчёт за квартал", "responsibleId": 1, "priority": 2, "deadline": "2026-05-19T18:00:00+03:00" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Подготовить отчёт за квартал', responsibleId: 1, priority: 2, deadline: '2026-05-19T18:00:00+03:00', }), }) const { success, data } = await res.json() console.log('ID новой задачи:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Подготовить отчёт за квартал', responsibleId: 1, priority: 2, deadline: '2026-05-19T18:00:00+03:00', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Полный объект созданной задачи (как у `GET /v1/tasks/:id`) — см. [Поля задачи](./fields.md) | URL карточки задачи в Битрикс24 строится из `id` и ID сотрудника: ``` https://.bitrix24.ru/company/personal/user//tasks/task/view// ``` `` — ID ответственного (поле `responsibleId` в ответе): задача откроется в его личном кабинете. Сегмент `user/<...>` задаёт, в чьём кабинете отображается страница задач — подставьте ID нужного сотрудника, например текущего. `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": { "id": "3871", "title": "Подготовить отчёт за квартал", "description": "", "status": "2", "priority": "2", "responsibleId": "1", "createdBy": "1", "createdDate": "2026-05-12T11:46:12+03:00", "deadline": "2026-05-19T18:00:00+03:00", "groupId": "0", "accomplices": [], "auditors": [], "creator": { "id": "1", "name": "Текущий пользователь", "link": "/company/personal/user/1/" }, "responsible": { "id": "1", "name": "Текущий пользователь", "link": "/company/personal/user/1/" } } } ``` ## Пример ответа при ошибке 422 — не указан ответственный: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Не указан исполнитель" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Битрикс24 отклонил создание задачи — например, не передано обязательное поле `title` или `responsibleId`, либо переданное значение отклонено порталом | | 400 | `READONLY_FIELD` | В теле запроса передано поле, доступное только на чтение (`id`, `dateStart`, `activityDate`, `realStatus`) | | 400 | `INVALID_DISK_ATTACHMENT_VALUE` | Значение поля-файла передано не массивом строк вида `n` — числом, строкой без префикса или одиночной строкой вместо массива | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `tasks` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Поля задачи](./fields.md) - [Получить задачу](./get.md) - [Обновить задачу](./update.md) - [Список задач](./list.md) - [Загрузить файл](../files/upload.md) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Tasks: Delete ## Удалить задачу `DELETE /v1/tasks/:id` Удаляет задачу. Восстановить удалённую задачу через API нельзя — создавайте новую при необходимости. Вместе с задачей становятся недоступными её комментарии и записи учёта времени. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID задачи | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/tasks/3871" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/tasks/3871" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/3871', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Задача удалена') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/3871', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — задача не найдена (или уже удалена): ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "task 999999999 not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Задача с таким ID не найдена (в том числе если она уже была удалена) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `tasks` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Каскадное удаление вложенных ресурсов.** После удаления задачи становятся недоступными её комментарии и записи учёта времени — отдельный `DELETE` для каждого из них не нужен. Попытка обратиться к ним по прежнему ID вернёт `422 BITRIX_ERROR` с сообщением `ITEM_NOT_FOUND_OR_NOT_ACCESSIBLE`. ## Смотрите также - [Список задач](./list.md) - [Получить задачу](./get.md) - [Обновить задачу](./update.md) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Tasks: Favorite ## Добавить задачу в избранное `POST /v1/tasks/:taskId/favorite` Добавляет задачу в личный список избранного пользователя, от имени которого действует ключ. Действие доступно участнику с доступом к задаче на просмотр — права на редактирование задачи не нужны, в отличие от [`PATCH /v1/tasks/:id`](./update.md). ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `taskId` | path | integer | да | ID задачи. Список: `GET /v1/tasks` | Тело запроса пустое. ## Примеры ### curl — личный ключ ```bash curl -X POST -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/tasks/289/favorite ``` ### curl — OAuth-приложение ```bash curl -X POST -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ https://vibecode.bitrix24.tech/v1/tasks/289/favorite ``` ### JavaScript — личный ключ ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/tasks/${taskId}/favorite`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY' } } ) const body = await res.json() console.log(body.data.favorite) // true ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/tasks/${taskId}/favorite`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, } ) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | `true` при успешном добавлении | | `data.taskId` | integer | ID задачи | | `data.favorite` | boolean | `true` — задача в избранном | ## Пример ответа ```json { "success": true, "data": { "taskId": 289, "favorite": true } } ``` ## Пример ответа при ошибке 404 — задача не найдена или недоступна: ```json { "success": false, "error": { "code": "TASK_NOT_FOUND", "message": "Task 99999999 not found or not accessible." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_PARAMS` | `taskId` в пути не является положительным целым числом | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный ключ | | 401 | `TOKEN_MISSING` | У ключа нет привязанных токенов авторизации | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `task` | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ с доступом только на чтение — действие меняет данные и заблокировано | | 404 | `TASK_NOT_FOUND` | Задача не найдена или недоступна пользователю | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Список избранного у каждого пользователя свой.** Избранное привязано к пользователю, от имени которого действует ключ. Одна и та же задача может быть в избранном у одного сотрудника и отсутствовать у другого. - **Ответ — краткое подтверждение, а не карточка задачи.** Полные поля задачи читайте через [`GET /v1/tasks/:id`](./get.md). ## Смотрите также - [Убрать задачу из избранного](./unfavorite.md) - [Закрепить задачу](./pin.md) - [Задачи](../tasks.md) --- # Tasks: Fields ## Поля задачи `GET /v1/tasks/fields` Возвращает схему полей задачи: типы, флаги «только чтение», признак `nullable`, понятные человеку `label` и `description`, перечисления значений для `status`, `priority`, `mark` и `durationType`, а для полей, которые портал отдаёт динамически, — словарь допустимых значений `values` и значение по умолчанию `default`. Имена полей здесь те же, что в ответах [списка](./list.md) и [карточки](./get.md), а типы соответствуют приходящим значениям: объявленное `number` приходит числом, `boolean` — значениями `true`/`false`. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/tasks/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/tasks/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data.fields).length) console.log('Значения status:', data.fields.status.enum) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа Все поля задачи описаны в camelCase — теми же именами, под которыми они приходят в ответе. Сырых имён верхним регистром в схеме больше нет. Исключения два и они ожидаемы: пользовательские поля портала (`UF_*`) и `CHECKLIST` — их состав зависит от портала, поэтому они приходят динамически (см. [Динамические поля портала](#динамические-поля-портала)). Столбец «Битрикс24» — имя, под которым поле принимается в `filter`, `sort` и `select`. Столбец «null» — приходит ли поле пустым. | Поле | Битрикс24 | Тип | RO | null | Описание | |------|----------|-----|:--:|:--:|---------| | `id` | `ID` | number | да | | Идентификатор задачи | | `title` | `TITLE` | string | | | Название задачи | | `description` | `DESCRIPTION` | string | | да | Описание (поддерживает BB-код) | | `responsibleId` | `RESPONSIBLE_ID` | number | | | Ответственный. Список: `GET /v1/users` | | `createdBy` | `CREATED_BY` | number | | | Постановщик. По умолчанию — пользователь ключа. Задаётся и при создании, и в PATCH — Битрикс24 применяет значение в пределах прав вызывающего пользователя. Передавайте только существующего сотрудника, иначе задача перестанет управляться через API (см. [PATCH /v1/tasks/:id](./update.md)). Список: `GET /v1/users` | | `status` | `STATUS` | number | | | Статус задачи. Допустимые значения в `fields.status.enum`. **`filter[status]` — виртуальный (мета-)фильтр**: Битрикс24 понимает здесь `−1` (просрочена), `−2` (не просмотрена), `−3` (почти просрочена), а не число из поля `status` ответа — поэтому `filter[status]=2` НЕ вернёт все задачи со статусом `2`. Для фильтра по фактическому статусу используйте `realStatus` | | `realStatus` | `REAL_STATUS` | number | да | | Реальный (фактически сохранённый) статус задачи — совпадает со значением поля `status` в ответе. Только для `filter`/`sort`: `?filter[realStatus]=2`, `?sort=realStatus` — в отличие от виртуального `filter[status]`, фильтрует по хранимому статусу. Значения те же, что у `status` (см. `fields.status.enum`). В теле ответа отдельно не возвращается (реальный статус уже есть в `status`) — в схеме это помечено признаком `notReturned`. Менять статус — через `status` | | `priority` | `PRIORITY` | number | | | Приоритет задачи. Допустимые значения в `fields.priority.enum` | | `groupId` | `GROUP_ID` | number | | | Рабочая группа. Список: `GET /v1/workgroups` | | `parentId` | `PARENT_ID` | number | | да | Родительская задача. Список: `GET /v1/tasks` | | `deadline` | `DEADLINE` | datetime | | да | Крайний срок (ISO 8601) | | `dateStart` | `DATE_START` | datetime | да | да | Фактическая дата начала работы над задачей. Фильтруется: `?filter[>=dateStart]=2026-05-01T00:00:00` | | `startDatePlan` | `START_DATE_PLAN` | datetime | | да | Плановая дата начала | | `endDatePlan` | `END_DATE_PLAN` | datetime | | да | Плановая дата окончания | | `timeEstimate` | `TIME_ESTIMATE` | number | | | Оценка трудозатрат в секундах | | `timeSpentInLogs` | `TIME_SPENT_IN_LOGS` | number | да | да | Фактически затраченное время в секундах — сумма записей учёта времени, см. [Учёт времени задач](./time.md). Пока таких записей нет, приходит `null`. Выбирается через `?select=timeSpentInLogs`, сортируется через `?sort=-timeSpentInLogs`. Фильтр по этому полю **молча игнорируется** — запрос вернёт тот же набор, что и без него. Сумму по выборке даёт [агрегация](./aggregate.md) | | `tags` | `TAGS` | object \| array | | | Метки задачи. У задачи С метками — объект-словарь `{ "": { "id": , "title": "<метка>" } }`. У задачи БЕЗ меток приходит пустой массив `[]` (а не пустой объект) — тип зависит от данных, проверяйте `Array.isArray()` перед обращением по ключу. Фильтр по одной метке: `?filter[tags]=метка` (транслируется в B24 `TAG`) | | `accomplices` | `ACCOMPLICES` | array | | | Соисполнители. Список: `GET /v1/users`. Фильтр по одному пользователю: `?filter[accomplices]=25` (транслируется в B24 `ACCOMPLICE`) | | `auditors` | `AUDITORS` | array | | | Наблюдатели. Список: `GET /v1/users`. Фильтр по одному пользователю: `?filter[auditors]=25` (транслируется в B24 `AUDITOR`) | | `closedDate` | `CLOSED_DATE` | datetime | | да | Дата закрытия (заполняется при переводе в статус `5` или `6`). Служебное поле, но принимается на записи — см. [PATCH /v1/tasks/:id](./update.md) | | `createdDate` | `CREATED_DATE` | datetime | | | Дата создания. Служебное поле, но принимается на записи — см. [PATCH /v1/tasks/:id](./update.md) | | `changedDate` | `CHANGED_DATE` | datetime | | | Дата последнего изменения. Служебное поле, но принимается на записи — переданное значение сохраняется вместо текущего времени, см. [PATCH /v1/tasks/:id](./update.md) | | `changedBy` | `CHANGED_BY` | number | | | ID пользователя, последним изменившего задачу. Служебное поле, но принимается на записи — см. [PATCH /v1/tasks/:id](./update.md). Список: `GET /v1/users` | | `closedBy` | `CLOSED_BY` | number | | да | ID пользователя, закрывшего задачу. Служебное поле, но принимается на записи — см. [PATCH /v1/tasks/:id](./update.md). Список: `GET /v1/users` | | `statusChangedBy` | `STATUS_CHANGED_BY` | number | | да | ID пользователя, последним изменившего статус задачи. Служебное поле, но принимается на записи — см. [PATCH /v1/tasks/:id](./update.md). Список: `GET /v1/users` | | `activityDate` | `ACTIVITY_DATE` | datetime | да | | Дата последней активности (учитывает комментарии, в отличие от `changedDate`). Возвращается всегда и выбирается через `?select=activityDate`. Важно: не фильтруется на стороне Битрикс24 — для фильтра используйте `changedDate` | | `mark` | `MARK` | string | | да | Оценка задачи руководителем. Значения — в `fields.mark.enum` (`P` — положительная, `N` — отрицательная). Пока оценки нет — `null` | | `multitask` | `MULTITASK` | boolean | | | У задачи несколько ответственных | | `notViewed` | `NOT_VIEWED` | boolean | да | | Ответственный ещё не открывал задачу. Индивидуально для пользователя ключа | | `replicate` | `REPLICATE` | boolean | | | Задача — шаблон повторяемой задачи | | `stageId` | `STAGE_ID` | number | | | Стадия канбана. `0`, если задача не на доске | | `sprintId` | `SPRINT_ID` | number | | да | Спринт Скрама | | `backlogId` | `BACKLOG_ID` | number | | да | Бэклог Скрама | | `statusChangedDate` | `STATUS_CHANGED_DATE` | datetime | да | | Когда последний раз менялся статус. Важно: не фильтруется на стороне Битрикс24 — используйте `changedDate` | | `guid` | `GUID` | string | да | | Глобальный идентификатор в фигурных скобках, сохраняется при экспорте и импорте. Для запросов используйте `id` | | `xmlId` | `XML_ID` | string | | да | Произвольный код для сопоставления с внешней системой | | `commentsCount` | `COMMENTS_COUNT` | number | да | да | Всего комментариев к задаче | | `serviceCommentsCount` | `SERVICE_COMMENTS_COUNT` | number | да | да | Сколько автоматических комментариев добавил сам Битрикс24 — например, о смене статуса | | `newCommentsCount` | `NEW_COMMENTS_COUNT` | number | да | | Непрочитанных комментариев. Индивидуально для пользователя ключа | | `allowChangeDeadline` | `ALLOW_CHANGE_DEADLINE` | boolean | | | Ответственный может сам переносить `deadline` | | `allowTimeTracking` | `ALLOW_TIME_TRACKING` | boolean | | | Включён учёт затраченного времени. Записи — `GET /v1/tasks/{taskId}/time` | | `chatId` | `CHAT_ID` | number | да | да | Чат обсуждения задачи. Сообщения — `GET /v1/tasks/{taskId}/chat/messages` | | `durationPlan` | `DURATION_PLAN` | number | | да | Плановые трудозатраты в единицах `durationType` | | `durationFact` | `DURATION_FACT` | number | да | да | Фактические трудозатраты в единицах `durationType` | | `durationType` | `DURATION_TYPE` | string | | | Единица измерения `durationPlan` и `durationFact`. Значения — в `fields.durationType.enum` | | `favorite` | `FAVORITE` | boolean | да | | В избранном. Индивидуально для пользователя ключа. Управление — `POST/DELETE /v1/tasks/{taskId}/favorite` | | `sorting` | `SORTING` | number | да | да | Вес ручной сортировки внутри списка | | `isMuted` | `IS_MUTED` | boolean | да | | Уведомления отключены. Индивидуально для пользователя ключа | | `isPinned` | `IS_PINNED` | boolean | да | | Закреплена в списке задач. Индивидуально для пользователя ключа. Управление — `POST/DELETE /v1/tasks/{taskId}/pin` | | `isPinnedInGroup` | `IS_PINNED_IN_GROUP` | boolean | да | | Закреплена внутри списка своей рабочей группы | | `flowId` | `FLOW_ID` | number | да | да | Поток, в котором создана задача | | `siteId` | `SITE_ID` | string | да | | Сайт портала, к которому относится задача | | `forumId` | `FORUM_ID` | number | да | да | Служебное хранилище комментариев | | `forumTopicId` | `FORUM_TOPIC_ID` | number | да | да | Служебное хранилище комментариев | | `exchangeId` | `EXCHANGE_ID` | number | да | да | Идентификатор в Microsoft Exchange. Заполняется только на порталах с синхронизацией | | `exchangeModified` | `EXCHANGE_MODIFIED` | datetime | да | да | Когда задача последний раз менялась на стороне Microsoft Exchange | | `outlookVersion` | `OUTLOOK_VERSION` | number | да | | Счётчик ревизии синхронизации с Microsoft Outlook | | `viewedDate` | `VIEWED_DATE` | datetime | да | да | Когда пользователь ключа последний раз открывал задачу | | `subordinate` | `SUBORDINATE` | boolean | да | | Задача принадлежит подчинённому пользователя ключа | | `taskControl` | `TASK_CONTROL` | boolean | | | После завершения задача уходит постановщику на приёмку | | `addInReport` | `ADD_IN_REPORT` | boolean | | | Задача учитывается в отчётах по эффективности | | `matchWorkTime` | `MATCH_WORK_TIME` | boolean | | | Расчёт срока пропускает выходные и праздники | | `forkedByTemplateId` | `FORKED_BY_TEMPLATE_ID` | number | да | да | Шаблон, из которого создана задача. `null` при ручном создании | | `descriptionInBbcode` | `DESCRIPTION_IN_BBCODE` | boolean | да | | Поле `description` содержит BB-код, а не обычный текст | | `creator` | — | object | да | | Карточка постановщика: имя, ссылка, аватар. Не фильтруется и не выбирается через `select` | | `responsible` | — | object | да | | Карточка ответственного. Не фильтруется и не выбирается через `select` | | `accomplicesData` | — | object | да | | Карточки соисполнителей с ключом по идентификатору пользователя. Без соисполнителей — `{}` | | `auditorsData` | — | object | да | | Карточки наблюдателей с ключом по идентификатору пользователя. Без наблюдателей — `{}` | | `group` | — | object | да | | Карточка рабочей группы: название, изображение. Без группы — `{}` | **Расшифровка `status`** — поле `fields.status.enum`: | Значение | Метка | Описание | |----------|-------|----------| | `1` | New | Начальное состояние. Новые задачи создаются со статусом `2`. Значение `1` встречается у задач, импортированных из внешних систем или мигрированных со старых версий портала | | `2` | Pending | Ждёт выполнения. Статус по умолчанию для новых задач | | `3` | In Progress | Выполняется | | `4` | Awaiting Control | Ожидает контроля. Исполнитель пометил задачу как сделанную, постановщик должен подтвердить | | `5` | Completed | Завершена | | `6` | Deferred | Отложена | | `7` | Declined | Отклонена | **Расшифровка `priority`** — поле `fields.priority.enum`: | Значение | Метка | |----------|-------| | `0` | Низкий | | `1` | Обычный | | `2` | Высокий | **Пользовательские поля (`UF_*`)** принимаются при создании/обновлении и в фильтрах в обоих написаниях — `ufCrmTask` и `UF_CRM_TASK` (camelCase конвертируется автоматически). Важно: `UF_CRM_TASK` (привязка к CRM) принимает **массив** идентификаторов привязок — `["D_123"]` (сделка), `["C_45"]` (контакт), `["CO_7"]` (компания), `["L_9"]` (лид). Строка вместо массива (`"D_123"`) молча игнорируется Битрикс24 — значение не сохранится (проверено на живом портале). **Поля-файлы** принимают массив строк вида `n`, где `id` — идентификатор файла из ответа [`POST /v1/files/upload`](../files/upload.md). Стандартное поле-файл у задачи одно — `ufTaskWebdavFiles`, к нему добавляются пользовательские поля типа «файл», заведённые администратором портала. Пример значения — `["n9759"]`. Значение другого вида — число, строка без префикса, одиночная строка вместо массива — отклоняется с `400 INVALID_DISK_ATTACHMENT_VALUE`, вложение при этом не создаётся. Запись заменяет весь список вложений задачи, пустой массив `[]` снимает все вложения. На чтении поле возвращает не те номера, которые передавались на записи: приходят идентификаторы вложений, они меняются при каждой перезаписи поля и не совпадают с идентификаторами файлов на Диске. Чтобы обратиться к самому файлу, храните `id` из ответа загрузки. ## Динамические поля портала Кроме объявленных полей выше `GET /v1/tasks/fields` отдаёт то, что зависит от конкретного портала и потому не может быть описано заранее: - **пользовательские поля** (`UF_*` / `uf*`) — их набор задаёт администратор портала. - **`CHECKLIST`** — пункты чек-листа, здесь только для чтения. Управление — `GET/POST /v1/tasks/{taskId}/checklist`. У таких полей `type` приходит от портала, а вместе с ним — словарь допустимых значений `values` и значение по умолчанию `default`: ```json { "CHECKLIST": { "type": "enum", "readonly": false, "label": "Чек-лист", "description": "Пункты чек-листа задачи. Здесь только для чтения — пункты создаются и меняются через эндпоинты чек-листа задачи.", "values": [ { "value": "Y", "label": "Да" }, { "value": "N", "label": "Нет" } ], "default": "N" } } ``` `label` у элементов словаря приходит от портала и локализован его настройками. Там, где портал отдаёт только коды без подписей, `label` у элемента отсутствует. **Шесть полей индивидуальны, а не общие для задачи.** `favorite`, `isMuted`, `isPinned`, `newCommentsCount`, `notViewed` и `viewedDate` описывают отношение к задаче того пользователя, от имени которого работает ключ, — другой ключ на том же портале увидит здесь другие значения. Не кэшируйте их как свойство задачи. **Опечатка `monts` в `durationType` — со стороны Битрикс24.** Мы передаём словарь как есть, потому что портал принимает именно это написание. «Исправленное» `months` он не поймёт. **`values` и `items` — разные ключи и разные форматы.** `values` — нормализованный словарь выше. `items` — сырой перечислимый справочник Битрикс24 у полей типа `enumeration`, он приходит как есть: `[{ "ID": "1", "VALUE": "Первый" }]`. Гарантия — на уровне ключа: у каждого из них всегда своя форма. Читайте тот, который вам нужен, по имени, а не «первый попавшийся словарь» — на сегодняшних порталах у одного поля бывает только один из двух, но одновременное присутствие мы не запрещаем. **Нульность.** Поля, которые реально приходят пустыми, помечены в схеме признаком `nullable: true` и колонкой «null» в таблице выше — сегодня их 27. Типобезопасным клиентам (TS) объявляйте такие поля как `T | null`. Пустые `accomplices` и `auditors` приходят как `[]` — это списки. Пустые `tags`, `group`, `accomplicesData` и `auditorsData` приходят как `{}` — это словари. **Списки и карточки различаются составом ключей.** Это свойство Битрикс24, а не нашей обёртки, поэтому такие поля намеренно не описаны в схеме: `subStatus` приходит только в [списке](./list.md), а `action`, `checklist`, `checkListTree` и `checkListCanAdd` — только в [карточке](./get.md). Они по-прежнему возвращаются в ответе. ## Пример ответа Показаны несколько полей для примера. Полный ответ содержит все объявленные поля, а также пользовательские поля портала. ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true }, "title": { "type": "string", "readonly": false }, "description": { "type": "string", "readonly": false }, "responsibleId": { "type": "number", "readonly": false }, "createdBy": { "type": "number", "readonly": false }, "status": { "type": "number", "readonly": false, "enum": [ { "value": 1, "label": "New", "labelRu": "Новая" }, { "value": 2, "label": "Pending", "labelRu": "Ждёт выполнения" }, { "value": 3, "label": "In Progress", "labelRu": "Выполняется" }, { "value": 4, "label": "Awaiting Control", "labelRu": "Ожидает контроля" }, { "value": 5, "label": "Completed", "labelRu": "Завершена" }, { "value": 6, "label": "Deferred", "labelRu": "Отложена" }, { "value": 7, "label": "Declined", "labelRu": "Отклонена" } ] }, "priority": { "type": "number", "readonly": false, "enum": [ { "value": 0, "label": "Low", "labelRu": "Низкий" }, { "value": 1, "label": "Normal", "labelRu": "Обычный" }, { "value": 2, "label": "High", "labelRu": "Высокий" } ] }, "deadline": { "type": "datetime", "readonly": false }, "createdDate": { "type": "datetime", "readonly": false }, "changedDate": { "type": "datetime", "readonly": false } } } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'tasks' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `tasks` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать задачу](./create.md) - [Обновить задачу](./update.md) - [Список задач](./list.md) - [Поиск задач](./search.md) - [Агрегация задач](./aggregate.md) - [Entity API](/docs/entity-api) --- # Tasks: Get ## Получить задачу `GET /v1/tasks/:id` Возвращает одну задачу со всеми полями. Дополнительно к полям списка приходят встроенные объекты постановщика и ответственного, чек-лист, разрешённые действия и расширенная информация о соисполнителях и наблюдателях. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID задачи | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/tasks/289" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/tasks/289" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log(data.title, '— статус:', data.status) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект задачи. Базовые поля — см. [Поля задачи](./fields.md). Дополнительные блоки описаны ниже | **Дополнительные блоки одиночного ответа:** | Поле | Тип | Описание | |------|-----|---------| | `data.creator` | object | Постановщик: `{ id, name, link, icon, workPosition }` | | `data.responsible` | object | Ответственный: тот же формат, что и `creator` | | `data.accomplicesData` | object[] | Подробности по соисполнителям (тот же формат, что и `creator`) | | `data.auditorsData` | object[] | Подробности по наблюдателям (тот же формат, что и `creator`) | | `data.action` | object | Карта разрешённых действий (boolean): `complete`, `start`, `pause`, `delegate`, `remove`, `edit`, `defer`, `changeDeadline`, `checklistAddItems` и другие | | `data.checklist` | array | Пункты чек-листа (пустой массив, если чек-лист не заполнен) | | `data.checkListTree` | object | Дерево чек-листа с метаданными | | `data.newCommentsCount` | number | Количество непрочитанных комментариев | ## Пример ответа ```json { "success": true, "data": { "id": 289, "title": "Подготовить отчёт за квартал", "description": "", "status": 2, "priority": 1, "groupId": 0, "responsibleId": 79, "createdBy": 99, "createdDate": "2026-05-12T09:11:18+03:00", "changedDate": "2026-05-12T09:11:18+03:00", "deadline": "2026-05-19T18:00:00+03:00", "accomplices": [], "auditors": [], "checklist": [], "creator": { "id": "99", "name": "Анна Соколова", "link": "/company/personal/user/99/", "icon": "https://example.bitrix24.ru/.../avatar.png", "workPosition": null }, "responsible": { "id": "79", "name": "Дмитрий Орлов", "link": "/company/personal/user/79/", "icon": "/bitrix/images/tasks/default_avatar.png", "workPosition": null }, "newCommentsCount": 0, "action": { "complete": true, "start": true, "delegate": true, "edit": true, "remove": true, "defer": true, "changeDeadline": true } } } ``` ## Пример ответа при ошибке 404 — задача не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "task 999999999 not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Задача с таким ID не найдена | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `tasks` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Встроенные данные пользователей.** Поля `creator` и `responsible` приходят вложенным объектом с именем, ссылкой на профиль и аватаркой. Отдельный `GET /v1/users/:id` для отображения автора задачи не требуется. **Приведение типов работает на верхнем уровне, внутрь объектов не заходит.** Поля-карточки (`creator`, `responsible`, `group`, `accomplicesData`, `auditorsData`) объявлены объектами и приходят от Битрикс24 как есть — значения внутри них остаются в том виде, в каком их отдал портал, в том числе `creator.id` строкой (`"99"`). Это не то же самое, что верхнеуровневый `createdBy`, который приходит числом. Для арифметики по вложенному идентификатору приводите через `Number()`. **Типы значений соответствуют схеме.** Поля, объявленные в [схеме](./fields.md) числами, приходят числами — включая `commentsCount`, `serviceCommentsCount` и `chatId`, который раньше был строкой в списке и числом в карточке. Признаки «да/нет» приходят значениями `true`/`false`, пустые `tags`, `group`, `accomplicesData`, `auditorsData` — пустым объектом `{}`. Приведение через `Number(value)` больше не требуется. ## Смотрите также - [Список задач](./list.md) - [Поля задачи](./fields.md) - [Обновить задачу](./update.md) - [Удалить задачу](./delete.md) - [Комментарии задачи](/docs/entities/task-comments) - [Учёт времени](./time.md) - [Чек-лист задачи](./checklist.md) - [Лимиты и оптимизация](/docs/optimization) --- # Tasks: List ## Список задач `GET /v1/tasks` Возвращает список задач портала с поддержкой фильтрации, сортировки и авто-пагинации. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` API автоматически запрашивает несколько страниц | | `offset` | number | `0` | Пропустить N записей. При `offset > 0` рекомендуется `limit ≤ 500` | | `select` | string | — | Выборка полей: `?select=id,title,status,responsibleId` | | `order` | object | `id desc` | Сортировка: `?order[id]=desc`, `?order[createdDate]=desc` | | `filter` | object | — | Фильтрация по полям `GET /v1/tasks/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[status]=2&filter[responsibleId]=1` | | `withTotal` | string | — | Нужно ли количество: `true` или `false`. `false` — убрать количество из ответа. Это единственный способ гарантированно убрать `meta.total`. При `limit` больше 50 подсчёт платформе всё равно нужен для плана обхода, поэтому параметр убирает число, а не нагрузку. Без параметра — настройка ключа, затем платформенное умолчание. [Листание и количество](/docs/entity-api#листание-и-количество-записей) | > **Какие даты фильтруются.** B24 `tasks.task.list` поддерживает фильтры по `createdDate`, `changedDate`, `closedDate`, `deadline`, `dateStart`. Поля `statusChangedDate` и `activityDate` **не фильтруются** на стороне Bitrix24 (их нет в списке фильтруемых полей метода) — такой фильтр будет молча проигнорирован. Используйте `changedDate` как ближайшую замену. Так же молча игнорируется фильтр по `timeSpentInLogs` — фактически затраченное время отбором не сужается, сумму по выборке даёт [агрегация](./aggregate.md). Соисполнители/наблюдатели фильтруются по одному пользователю: `?filter[accomplices]=25`, `?filter[auditors]=25`. Метки — `?filter[tags]=метка`. > **`status` vs `realStatus`.** `filter[status]` в Bitrix24 — **виртуальный (мета-)фильтр**: значения `−1` (просрочена), `−2` (не просмотрена), `−3` (почти просрочена), а не число из поля `status` ответа — поэтому `filter[status]=2` не вернёт задачи со статусом `2`. Для фильтра и сортировки по фактическому статусу используйте `realStatus`: `?filter[realStatus]=2` (ждёт выполнения), `?filter[realStatus]=5` (завершена), `?sort=realStatus`. Значение `realStatus` совпадает с полем `status` в ответе. > **`meta.total` приходит не на каждый вызов.** При `limit` не больше 50 и `offset`, равном нулю, подсчёт можно не заказывать: если страница пришла короче `limit`, `meta.total` всё равно придёт с точным числом — коллекция на такой странице закончилась (пустой результат даёт `0`). Если страница пришла полной, поля не будет. При `limit` больше 50 `meta.total` приходит — подсчёт платформа выполняет, только когда без него не обойтись, — и убрать его оттуда можно явным `withTotal=false`. Проверяйте наличие поля в конкретном ответе, а листайте по `meta.hasMore`. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/tasks?limit=10&filter[status]=2&order[id]=desc" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/tasks?limit=10&filter[status]=2&order[id]=desc" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const url = 'https://vibecode.bitrix24.tech/v1/tasks?limit=10&filter[status]=2&order[id]=desc' const res = await fetch(url, { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Получено ${data.length} из ${meta.total} задач`) ``` ### JavaScript — OAuth-приложение ```javascript const url = 'https://vibecode.bitrix24.tech/v1/tasks?limit=10&filter[status]=2&order[id]=desc' const res = await fetch(url, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив задач (все поля — см. [Поля задачи](./fields.md)) | | `meta.total` | number | Общее количество записей, соответствующих фильтру. Необязательное поле — см. заметку выше | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | URL карточки любой задачи из массива `data` строится из её `id` и ID сотрудника: ``` https://.bitrix24.ru/company/personal/user//tasks/task/view// ``` `` — ID ответственного (поле `responsibleId` каждого элемента): задача откроется в его личном кабинете. Сегмент `user/<...>` задаёт, в чьём кабинете отображается страница задач — подставьте ID нужного сотрудника, например текущего. `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 289, "title": "Подготовить отчёт за квартал", "status": 2, "priority": 1, "responsibleId": 79, "createdBy": 99, "createdDate": "2026-05-12T09:11:18+03:00", "deadline": "2026-05-19T18:00:00+03:00", "groupId": 0, "accomplices": [], "auditors": [], "tags": {}, "notViewed": false, "chatId": 3567, "creator": { "id": "99", "name": "Анна Соколова", "link": "/company/personal/user/99/" }, "responsible": { "id": "79", "name": "Дмитрий Орлов", "link": "/company/personal/user/79/" } } ], "meta": { "total": 184, "hasMore": true } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'tasks' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `tasks` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Передан некорректный или несуществующий ключ | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Когда переходить на `POST /v1/tasks/search`.** Если у запроса много условий фильтра или нужна выгрузка по большому диапазону дат, выбирайте `POST /v1/tasks/search` — параметры передаются в body, плюс доступно автоматическое разбиение запроса по временны́м окнам для выборок свыше 5000 записей. См. [Поиск задач](./search.md). **Приведение типов работает на верхнем уровне, внутрь объектов не заходит.** Поля-карточки (`creator`, `responsible`, `group`, `accomplicesData`, `auditorsData`) объявлены объектами и приходят от Битрикс24 как есть — значения внутри них остаются в том виде, в каком их отдал портал, в том числе `creator.id` строкой (`"99"`). Это не то же самое, что верхнеуровневый `createdBy`, который приходит числом. Для арифметики по вложенному идентификатору приводите через `Number()`. **Типы значений соответствуют схеме.** Поля, объявленные в [схеме](./fields.md) числами (`id`, `status`, `priority`, `responsibleId`, `createdBy`, `groupId`, `chatId` и подобные), приходят числами. Признаки «да/нет» приходят значениями `true`/`false`. Пустые `tags`, `group`, `accomplicesData`, `auditorsData` — пустым объектом `{}`. Приведение через `Number(value)` больше не требуется. Раньше эти значения приходили строками — если ваш код сравнивает их со строкой (`status === "2"`), его нужно поправить. ## Смотрите также - [Получить задачу](./get.md) - [Поиск задач](./search.md) - [Поля задачи](./fields.md) - [Агрегация задач](./aggregate.md) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Tasks: Pin ## Закрепить задачу `POST /v1/tasks/:taskId/pin` Закрепляет задачу в верхней части личного списка задач пользователя, от имени которого действует ключ. Действие доступно участнику с доступом к задаче на просмотр — права на редактирование задачи не нужны, в отличие от [`PATCH /v1/tasks/:id`](./update.md). ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `taskId` | path | integer | да | ID задачи. Список: `GET /v1/tasks` | Тело запроса пустое. ## Примеры ### curl — личный ключ ```bash curl -X POST -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/tasks/289/pin ``` ### curl — OAuth-приложение ```bash curl -X POST -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ https://vibecode.bitrix24.tech/v1/tasks/289/pin ``` ### JavaScript — личный ключ ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/tasks/${taskId}/pin`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY' } } ) const body = await res.json() console.log(body.data.pinned) // true ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/tasks/${taskId}/pin`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, } ) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | `true` при успешном закреплении | | `data.taskId` | integer | ID задачи | | `data.pinned` | boolean | `true` — задача закреплена | ## Пример ответа ```json { "success": true, "data": { "taskId": 289, "pinned": true } } ``` ## Пример ответа при ошибке 404 — задача не найдена или недоступна: ```json { "success": false, "error": { "code": "TASK_NOT_FOUND", "message": "Task 99999999 not found or not accessible." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_PARAMS` | `taskId` в пути не является положительным целым числом | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный ключ | | 401 | `TOKEN_MISSING` | У ключа нет привязанных токенов авторизации | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `task` | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ с доступом только на чтение — действие меняет данные и заблокировано | | 404 | `TASK_NOT_FOUND` | Задачи с указанным `taskId` нет или она недоступна пользователю | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Ответ — краткое подтверждение, а не карточка задачи.** Полные поля задачи читайте через [`GET /v1/tasks/:id`](./get.md). ## Смотрите также - [Открепить задачу](./unpin.md) - [Добавить задачу в избранное](./favorite.md) - [Задачи](../tasks.md) --- # Tasks: Search ## Поиск задач `POST /v1/tasks/search` Поиск задач с фильтрами и сортировкой. Аналог `GET /v1/tasks`, но параметры передаются в теле запроса — подходит для длинных и сложных фильтров. Дополнительно автоматически разбивает выборку по недельным окнам при фильтре по диапазону дат шире 14 дней — так обходится потолок в 5000 записей на один вызов Битрикс24. ## Поля запроса (body) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям `GET /v1/tasks/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `{"status": 2, "responsibleId": 1}` | | `select` | string[] | — | Выборка полей: `["id", "title", "status", "responsibleId"]` | | `order` | object | `id desc` | Сортировка: `{ "createdDate": "desc" }` | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки» | | `autoWindow` | boolean | `true` | Разбивать выборку по недельным окнам при фильтре по диапазону дат шире 14 дней. `false` отключает разбиение | | `withTotal` | boolean | — | Нужно ли количество. `false` — убрать количество из ответа. Это единственный способ гарантированно убрать `meta.total`, и при разбиении на окна он не действует. При `limit` больше 50 подсчёт платформе всё равно нужен для плана обхода, поэтому параметр убирает число, а не нагрузку. Без поля — настройка ключа, затем платформенное умолчание. [Листание и количество](/docs/entity-api#листание-и-количество-записей) | > **`status` vs `realStatus`.** `filter.status` в Bitrix24 — виртуальный (мета-)фильтр (`−1` просрочена, `−2` не просмотрена, `−3` почти просрочена), а не число из поля `status` ответа: `{"filter": {"status": 2}}` не вернёт задачи со статусом `2`. Для фильтра/сортировки по фактическому статусу используйте `realStatus`: `{"filter": {"realStatus": 2}}`, `{"sort": {"realStatus": "asc"}}`. > **`meta.total` приходит не на каждый вызов.** При `limit` не больше 50 и `offset`, равном нулю, подсчёт можно не заказывать: если страница пришла короче `limit`, `meta.total` всё равно придёт с точным числом (пустой результат даёт `0`). На полной странице поля не будет. При `limit` больше 50 `meta.total` приходит — подсчёт платформа выполняет, только когда без него не обойтись, — и убрать его оттуда можно явным `withTotal=false`. При разбиении на окна (`autoWindowed: true`) подсчёт заказывается как раньше, а `withTotal` игнорируется. Проверяйте наличие поля в конкретном ответе, а листайте по `meta.hasMore`. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/tasks/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "status": 2, "responsibleId": 1 }, "select": ["id", "title", "status", "deadline"], "order": { "id": "desc" }, "limit": 50 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/tasks/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "status": 2, "responsibleId": 1 }, "select": ["id", "title", "status", "deadline"], "order": { "id": "desc" }, "limit": 50 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { status: 2, responsibleId: 1 }, select: ['id', 'title', 'status', 'deadline'], order: { id: 'desc' }, limit: 50, }), }) const { success, data, meta } = await res.json() console.log(`Найдено ${data.length} из ${meta.total} задач`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { status: 2, responsibleId: 1 }, select: ['id', 'title', 'status', 'deadline'], order: { id: 'desc' }, limit: 50, }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив задач (все поля — см. [Поля задачи](./fields.md)) | | `meta.total` | number | Сколько записей подошло под фильтр. Необязательное поле — см. заметку выше | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временны́м окнам | | `meta.windowCount` | number | Число окон. Приходит при `autoWindowed: true` | | `meta.batchWaves` | number | Число волн параллельных запросов. Приходит при `autoWindowed: true` | URL карточки любой задачи из массива `data` строится из её `id` и ID сотрудника: ``` https://.bitrix24.ru/company/personal/user//tasks/task/view// ``` `` — ID ответственного (поле `responsibleId` каждого элемента): задача откроется в его личном кабинете. Сегмент `user/<...>` задаёт, в чьём кабинете отображается страница задач — подставьте ID нужного сотрудника, например текущего. `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": "289", "title": "Подготовить отчёт за квартал", "status": "2", "deadline": "2026-05-19T18:00:00+03:00" }, { "id": "311", "title": "Свериться с бухгалтерией", "status": "2", "deadline": "2026-05-15T17:00:00+03:00" } ], "meta": { "total": 182, "hasMore": true, "durationMs": 1226 } } ``` С фильтром по диапазону дат шире 14 дней в `meta` дополнительно приходят `autoWindowed`, `windowCount` и `batchWaves`: ```json { "success": true, "data": [ /* ... */ ], "meta": { "total": 179, "hasMore": true, "autoWindowed": true, "windowCount": 131, "batchWaves": 3, "durationMs": 1543 } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'tasks' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `tasks` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | — | `WINDOWED_SEARCH_FAILED` | Больше не возвращается: при полном отказе окон возвращается реальный код Битрикс24 — `UNKNOWN_FILTER_FIELD` / `INVALID_PARAMS` / `BITRIX_ACCESS_DENIED` / `RATE_LIMITED` / `BITRIX_UNAVAILABLE` / `BITRIX_TIMEOUT` (503) | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Когда выбирать search вместо list.** `GET /v1/tasks` подходит для коротких фильтров в URL. `POST /v1/tasks/search` применяется, когда условий много — вложенные объекты, массивы, диапазоны дат: параметры в теле читаются и собираются проще, чем длинная query-строка. **Разбиение по временны́м окнам.** Фильтр по диапазону дат шире 14 дней автоматически разбивается на недельные окна, которые выполняются параллельными волнами — так выборка обходит потолок в 5000 записей на один вызов. В `meta` тогда приходят `autoWindowed: true`, число окон `windowCount` и число волн `batchWaves`. Отключает разбиение параметр `autoWindow: false`. При активном разбиении `offset` больше нуля отклоняется с `UNSTABLE_OFFSET_PAGINATION`. **Числовые значения как строки.** Поля-идентификаторы и числовые перечисления (`id`, `status`, `priority`, `responsibleId`, `createdBy`, `groupId`) приходят строками. Для арифметики и сравнений приводите через `Number(value)`. ## Смотрите также - [Список задач](./list.md) - [Поля задачи](./fields.md) - [Агрегация задач](./aggregate.md) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Tasks: Time # Учёт времени задач Записи о потраченном на задачу времени — вложенный ресурс задачи. У каждой записи есть длительность, автор, комментарий и время создания. Базовый путь — `/v1/tasks/:taskId/time`, эти операции требуют существующей задачи `:taskId` на портале. Записи со всех задач сразу отдаёт отдельный путь `/v1/task-time`. Битрикс24 API: `task.elapseditem.*` Скоуп: `task` ## Операции - [Добавить запись](./time/create.md) — `POST /v1/tasks/:taskId/time` - [Список записей](./time/list.md) — `GET /v1/tasks/:taskId/time` - [Получить запись](./time/get.md) — `GET /v1/tasks/:taskId/time/:itemId` - [Обновить запись](./time/update.md) — `PATCH /v1/tasks/:taskId/time/:itemId` - [Удалить запись](./time/delete.md) — `DELETE /v1/tasks/:taskId/time/:itemId` - [Список по всему порталу](./time/global-list.md) — `GET /v1/task-time` ## Ключевые поля Эти же поля отдаёт программный справочник `GET /v1/task-time/fields` — тип, признак «только чтение», подпись и описание у каждого. Схема не зависит от задачи, поэтому путь плоский. | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор записи | | `taskId` | number | ID родительской задачи | | `userId` | number | Автор. Список сотрудников: `GET /v1/users` | | `seconds` | number | Длительность в секундах. Основное поле, задаётся при создании | | `minutes` | number | Длительность в минутах, производное от `seconds`, заполняется системой | | `commentText` | string | Комментарий к записи. Если комментарий пуст, приходит `""`, а не `null` | | `source` | string | Источник: `2` — запись создана через REST API | | `createdDate` | datetime | Дата создания записи | | `dateStart`, `dateStop` | datetime | Начало и окончание учтённого интервала. Заполняются автоматически и через текущий API не редактируются | ## Что нужно знать перед работой 1. **Поля ответа — в camelCase.** Записи учёта времени возвращаются в camelCase — `id`, `taskId`, `userId`, `seconds`, `minutes`, `commentText`, `source`, `createdDate`, `dateStart`, `dateStop`, — как и комментарии задач и остальная часть API. 2. **Числовые значения приходят числами, `source` — строкой.** `id`, `taskId`, `userId`, `seconds` и `minutes` сериализуются числами — например `"seconds": 900`. Это верно во всех ответах — и в списках, и в карточке одной записи, — поэтому приводить их через `Number(value)` не нужно. Поле `source` остаётся строкой: `"source": "2"`. 3. **`seconds` — единственная единица измерения при записи.** Параметр `seconds` обязателен. Значение `minutes` система пересчитывает сама. 4. **Записи удаляются вместе с задачей.** Если родительская задача удалена ([`DELETE /v1/tasks/:id`](./delete.md)), её записи учёта времени становятся недоступны — отдельный `DELETE` для каждой не требуется. Попытка обратиться к ним по прежнему ID вернёт `422`. 5. **`dateStart` и `dateStop` через API не редактируются.** Их значения заполняются Битрикс24 автоматически в момент создания записи. Чтобы зафиксировать конкретный интервал, передавайте суммарное время через `seconds` в `POST` или `PATCH`. Битрикс24 систематически проставляет интервал примерно на час впереди `createdDate` — это его собственное автозаполнение, API Вайбкод даты не меняет. 6. **Список может показывать записи, недоступные карточке.** Списки — и глобальный, и по одной задаче — иногда возвращают чужие записи. Обращение к такой записи по её `itemId` отдаёт `422 ITEM_NOT_FOUND_OR_NOT_ACCESSIBLE`. Это рассогласование прав доступа на стороне Битрикс24. 7. **Справочник полей лежит на плоском пути.** Состав полей отдаёт `GET /v1/task-time/fields`. Вложенный `GET /v1/tasks/:taskId/time/fields` возвращает `400 WRONG_PATH` и называет в тексте ошибки правильный путь: схема одинакова для всех задач, поэтому она не повторяется под каждым `:taskId`. Запрос требует скоуп `task` и не обращается к Битрикс24. 8. **`userId` задаётся только при создании.** В `POST` его можно передать, в `PATCH` он возвращает `400 READONLY_FIELD` — Битрикс24 не умеет переносить запись на другого сотрудника. В справочнике полей это поле помечено `createOnly`. 9. **Имя поля в ответе и в теле запроса различается у комментария.** В ответе он приходит как `commentText`, а передаётся при записи как `comment`. ## Типичный сценарий 1. Найти или создать задачу: [`GET /v1/tasks`](./list.md) / [`POST /v1/tasks`](./create.md). 2. Добавить запись: [`POST /v1/tasks/:taskId/time`](./time/create.md) с `seconds` и при необходимости `comment` и `userId`. 3. Посмотреть историю учёта: [`GET /v1/tasks/:taskId/time`](./time/list.md). 4. Скорректировать длительность или комментарий: [`PATCH /v1/tasks/:taskId/time/:itemId`](./time/update.md). 5. Удалить ошибочную запись: [`DELETE /v1/tasks/:taskId/time/:itemId`](./time/delete.md). 6. Собрать отчёт за период по сотруднику, не перебирая задачи: [`GET /v1/task-time`](./time/global-list.md). ## Лимиты | Лимит | Значение | |-------|----------| | Количество записей на странице | 1..500, по умолчанию 50 | | Частота запросов | общая для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Задачи](../tasks.md) - [Комментарии задач](../task-comments.md) - [Сотрудники](/docs/entities/users) - [Лимиты и оптимизация](/docs/optimization) --- # Tasks: Create ## Добавить запись учёта времени `POST /v1/tasks/:taskId/time` Создаёт новую запись учёта времени для задачи — фиксирует потраченные секунды, а при необходимости автора записи и комментарий к ней. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `taskId` (path) | number | да | ID задачи | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `seconds` | number | да | Длительность в секундах | | `comment` | string | нет | Комментарий к записи. При чтении записи возвращается в поле `commentText` | | `userId` | number | нет | ID автора. По умолчанию — пользователь API-ключа. Передавайте только существующие ID сотрудников из [`GET /v1/users`](/docs/entities/users) — см. «Известные особенности» | | `createdDate` | string | нет | Дата и время записи. Принимаются три формата: ISO 8601 со смещением `2026-07-13T14:30:00+03:00`, ISO 8601 без смещения `2026-07-13T14:30:00` и дата `2026-07-13`. Без этого поля запись датируется моментом создания | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/tasks/289/time" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "seconds": 1800, "comment": "Подготовка черновика" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/tasks/289/time" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "seconds": 1800, "comment": "Подготовка черновика" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289/time', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ seconds: 1800, comment: 'Подготовка черновика', }), }) const { success, data } = await res.json() console.log('ID новой записи:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289/time', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ seconds: 1800, comment: 'Подготовка черновика', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Идентификатор созданной записи. Используйте его для `GET` / `PATCH` / `DELETE` | ## Пример ответа HTTP 201 Created: ```json { "success": true, "data": { "id": 161 } } ``` ## Пример ответа при ошибке 400 — не передан обязательный `seconds`: ```json { "success": false, "error": { "code": "MISSING_PARAMS", "message": "Required: seconds (number)" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_PARAMS` | Не передано поле `seconds` | | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку (например, родительская задача недоступна) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `task` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Существование `userId` не проверяется.** Запись сохраняется с любым значением `userId`, даже несуществующим, и вызов возвращает `201`. Но такую «запись-призрак» затем нельзя ни прочитать, ни обновить, ни удалить — `GET`, `PATCH` и `DELETE /v1/tasks/:taskId/time/:itemId` вернут `422 ITEM_NOT_FOUND_OR_NOT_ACCESSIBLE`. Она остаётся видна только в списках `GET /v1/tasks/:taskId/time` и `GET /v1/task-time` и засоряет отчёты без возможности очистки через API. Передавайте только реальные ID сотрудников из [`GET /v1/users`](/docs/entities/users). **Ответ — только `id`, без остальных полей.** В отличие от создания задачи или комментария, метод возвращает только идентификатор. Чтобы получить полную запись с заполненными системой `minutes`, `source`, `createdDate`, `dateStart` и `dateStop` — сделайте [`GET /v1/tasks/:taskId/time/:itemId`](./get.md). ## Смотрите также - [Получить запись](./get.md) - [Список записей](./list.md) - [Обновить запись](./update.md) - [Удалить запись](./delete.md) - [Задачи](/docs/entities/tasks) --- # Tasks: Delete ## Удалить запись учёта времени `DELETE /v1/tasks/:taskId/time/:itemId` Удаляет запись учёта времени. Восстановить её через API нельзя — создавайте новую при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `taskId` (path) | number | да | ID задачи | | `itemId` (path) | number | да | ID записи учёта времени | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/tasks/289/time/161" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/tasks/289/time/161" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289/time/161', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Запись удалена') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289/time/161', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 422 — запись не найдена или недоступна: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "TASKS_ERROR_EXCEPTION_#512; Check listitem not found or not accessible; 512/TE/ITEM_NOT_FOUND_OR_NOT_ACCESSIBLE" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Запись с таким `itemId` не найдена (в том числе если она или родительская задача уже удалены) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `task` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список записей](./list.md) - [Получить запись](./get.md) - [Обновить запись](./update.md) - [Задачи](/docs/entities/tasks) --- # Tasks: Get ## Получить запись учёта времени `GET /v1/tasks/:taskId/time/:itemId` Возвращает одну запись учёта времени по её идентификатору. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `taskId` (path) | number | да | ID задачи | | `itemId` (path) | number | да | ID записи учёта времени (из [`GET /v1/tasks/:taskId/time`](./list.md) или ответа [`POST /v1/tasks/:taskId/time`](./create.md)) | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/tasks/289/time/161" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/tasks/289/time/161" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289/time/161', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log(`Минут потрачено: ${data.minutes}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289/time/161', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Идентификатор записи | | `data.taskId` | number | ID родительской задачи | | `data.userId` | number | Автор. Профиль: `GET /v1/users/:userId` | | `data.seconds` | number | Длительность в секундах | | `data.minutes` | number | Длительность в минутах (производное от `seconds`) | | `data.commentText` | string | Комментарий к записи | | `data.source` | string | Источник: `2` — REST API | | `data.createdDate` | datetime | Когда запись была создана | | `data.dateStart` | datetime | Начало учтённого интервала | | `data.dateStop` | datetime | Окончание учтённого интервала | ## Пример ответа ```json { "success": true, "data": { "id": 161, "taskId": 289, "userId": 1, "commentText": "Подготовка черновика", "seconds": 900, "minutes": 15, "source": "2", "createdDate": "2026-05-13T16:15:41+03:00", "dateStart": "2026-05-13T17:15:41+03:00", "dateStop": "2026-05-13T17:15:41+03:00" } } ``` ## Пример ответа при ошибке 422 — запись не найдена или недоступна: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "TASKS_ERROR_EXCEPTION_#512; Check listitem not found or not accessible; 512/TE/ITEM_NOT_FOUND_OR_NOT_ACCESSIBLE" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Запись с таким `itemId` не найдена или родительская задача недоступна | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `task` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список записей](./list.md) - [Обновить запись](./update.md) - [Удалить запись](./delete.md) - [Задачи](/docs/entities/tasks) --- # Tasks: Global List ## Список записей по всему порталу `GET /v1/task-time` Возвращает записи учёта времени со всех задач портала одним запросом, с отбором по сотруднику, периоду и задаче. Применяется, когда список задач заранее неизвестен — например, для отчёта о времени сотрудника за месяц. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `userId` (query) | number | — | Идентификатор сотрудника. Список: `GET /v1/users`. Без параметра возвращаются записи всех сотрудников, доступных владельцу ключа | | `from` (query) | string | — | Нижняя граница периода включительно по полю `createdDate`. Принимает ISO 8601 `2026-05-01T00:00:00+03:00` и дату `2026-05-01` | | `to` (query) | string | — | Верхняя граница периода включительно по полю `createdDate`. Формат — как у `from`. Дата без времени включает весь день целиком | | `taskId` (query) | number | — | Сузить выборку до одной задачи, поверх `userId`, `from` и `to`. Идентификатор: `GET /v1/tasks` | | `limit` (query) | number | `50` | Размер страницы, от 1 до 500. Значение больше 500 приводится к 500 | | `offset` (query) | number | `0` | Смещение в выборке. Должно быть кратно `limit` | **Пагинация.** За один вызов возвращается до 500 записей. При `limit` больше 50 Вайбкод собирает окно на своей стороне и отдаёт его целиком. Значение `offset` кратно `limit` — `0`, `limit`, `2 × limit` и так далее, иначе приходит `400 INVALID_OFFSET`. Признак того, что за окном есть ещё записи, — `meta.hasMore`. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/task-time?userId=1&from=2026-05-01&to=2026-05-31" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/task-time?userId=1&from=2026-05-01&to=2026-05-31" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const url = 'https://vibecode.bitrix24.tech/v1/task-time?userId=1&from=2026-05-01&to=2026-05-31' const res = await fetch(url, { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() const totalSeconds = data.reduce((sum, r) => sum + r.seconds, 0) console.log(`За период: ${totalSeconds / 3600} ч, записей ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const url = 'https://vibecode.bitrix24.tech/v1/task-time?userId=1&from=2026-05-01&to=2026-05-31' const res = await fetch(url, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив записей учёта времени | | `data[].id` | number | Идентификатор записи | | `data[].taskId` | number | Идентификатор родительской задачи. Карточка: `GET /v1/tasks/:id` | | `data[].userId` | number | Автор записи. Профиль: `GET /v1/users/:userId` | | `data[].seconds` | number | Длительность в секундах | | `data[].minutes` | number | Длительность в минутах, производное от `seconds` | | `data[].commentText` | string | Комментарий к записи. Если комментарий пуст, приходит `""` | | `data[].source` | string | Источник: `2` — REST API | | `data[].createdDate` | datetime | Когда запись была создана | | `data[].dateStart` | datetime | Начало учтённого интервала, заполняется автоматически | | `data[].dateStop` | datetime | Окончание учтённого интервала, заполняется автоматически | | `meta.total` | number | Общее число записей, соответствующих отбору | | `meta.limit` | number | Применённый размер страницы | | `meta.offset` | number | Применённое смещение | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами текущего окна | ## Пример ответа ```json { "success": true, "data": [ { "id": 161, "taskId": 3881, "userId": 1, "commentText": "Код-ревью", "seconds": 900, "minutes": 15, "source": "2", "createdDate": "2026-05-13T16:15:41+03:00", "dateStart": "2026-05-13T17:15:41+03:00", "dateStop": "2026-05-13T17:15:41+03:00" }, { "id": 159, "taskId": 3867, "userId": 1, "commentText": "Проверка сборки", "seconds": 600, "minutes": 10, "source": "2", "createdDate": "2026-05-06T10:46:12+03:00", "dateStart": "2026-05-06T11:46:12+03:00", "dateStop": "2026-05-06T11:46:12+03:00" }, { "id": 157, "taskId": 289, "userId": 1, "commentText": "Подготовка черновика", "seconds": 1800, "minutes": 30, "source": "2", "createdDate": "2026-05-06T10:45:47+03:00", "dateStart": "2026-05-06T11:45:47+03:00", "dateStop": "2026-05-06T11:45:47+03:00" } ], "meta": { "total": 3, "limit": 50, "offset": 0, "hasMore": false } } ``` ## Пример ответа при ошибке 400 — `userId` не является положительным целым числом: ```json { "success": false, "error": { "code": "INVALID_USER_ID", "message": "userId must be a positive integer" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_USER_ID` | `userId` не положительное целое число | | 400 | `INVALID_TASK_ID` | `taskId` не положительное целое число | | 400 | `INVALID_OFFSET` | `offset` не кратен `limit` — постраничная выборка требует значений `0`, `limit`, `2 × limit` и так далее | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `task` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Сортировка от новых к старым.** Первыми возвращаются последние добавленные записи. `limit` и `offset` работают поверх этой сортировки. **Некорректная дата не вызывает ошибку.** Значение `from` или `to`, которое не разбирается как дата, даёт пустую выборку и статус `200`. Формат проверяйте на своей стороне. **Смещение за пределы выборки.** Запрос с `offset` больше числа записей возвращает пустой массив, а `meta.total` в таком ответе повторяет `offset`. Конец выдачи определяйте по `meta.hasMore` со значением `false`, а не сравнением `offset` с `meta.total`. ## Смотрите также - [Список записей задачи](./list.md) - [Добавить запись](./create.md) - [Учёт времени задач](/docs/entities/tasks/time) - [Задачи](/docs/entities/tasks) - [Сотрудники](/docs/entities/users) - [Лимиты и оптимизация](/docs/optimization) --- # Tasks: List ## Список записей учёта времени `GET /v1/tasks/:taskId/time` Возвращает все записи учёта времени конкретной задачи, отсортированные по `id` (сначала новые). ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `taskId` (path) | number | да | — | ID задачи | | `limit` (query) | number | | `50` | Размер страницы | | `offset` (query) | number | | `0` | Пропустить N записей | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/tasks/289/time" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/tasks/289/time" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289/time', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() const totalSeconds = data.reduce((sum, r) => sum + r.seconds, 0) console.log(`Всего по задаче: ${totalSeconds / 60} мин`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289/time', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив записей учёта времени | | `data[].id` | number | Идентификатор записи | | `data[].taskId` | number | ID родительской задачи | | `data[].userId` | number | Автор. Профиль: `GET /v1/users/:userId` | | `data[].seconds` | number | Длительность в секундах | | `data[].minutes` | number | Длительность в минутах (производное от `seconds`) | | `data[].commentText` | string | Комментарий к записи | | `data[].source` | string | Источник: `2` — REST API | | `data[].createdDate` | datetime | Когда запись была создана | | `data[].dateStart` | datetime | Начало учтённого интервала (заполняется автоматически) | | `data[].dateStop` | datetime | Окончание учтённого интервала (заполняется автоматически) | | `meta.total` | number | Общее число записей учёта времени по задаче | ## Пример ответа ```json { "success": true, "data": [ { "id": 163, "taskId": 289, "userId": 1, "commentText": "Подготовка черновика", "seconds": 1800, "minutes": 30, "source": "2", "createdDate": "2026-05-13T16:15:43+03:00", "dateStart": "2026-05-13T17:15:43+03:00", "dateStop": "2026-05-13T17:15:43+03:00" }, { "id": 161, "taskId": 289, "userId": 1, "commentText": "", "seconds": 600, "minutes": 10, "source": "2", "createdDate": "2026-05-13T16:15:41+03:00", "dateStart": "2026-05-13T17:15:41+03:00", "dateStop": "2026-05-13T17:15:41+03:00" } ], "meta": { "total": 2 } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'task' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `task` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку при чтении — например, родительская задача отсутствует или удалена | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Сортировка по убыванию `id`.** Сначала возвращаются последние добавленные записи. `limit` и `offset` работают поверх этой сортировки. ## Смотрите также - [Получить запись](./get.md) - [Добавить запись](./create.md) - [Обновить запись](./update.md) - [Удалить запись](./delete.md) - [Задачи](/docs/entities/tasks) --- # Tasks: Update ## Обновить запись учёта времени `PATCH /v1/tasks/:taskId/time/:itemId` Изменяет существующую запись учёта времени. Передавайте только изменяемые поля. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `taskId` (path) | number | да | ID задачи | | `itemId` (path) | number | да | ID записи учёта времени | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `seconds` | number | нет | Новая длительность в секундах. После обновления `minutes` пересчитывается автоматически | | `comment` | string | нет | Новый комментарий к записи | | `createdDate` | string | нет | Новая дата и время записи. Принимаются три формата: ISO 8601 со смещением `2026-07-13T14:30:00+03:00`, ISO 8601 без смещения `2026-07-13T14:30:00` и дата `2026-07-13` | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/tasks/289/time/161" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "seconds": 900, "comment": "Уточнённая оценка" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/tasks/289/time/161" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "seconds": 900, "comment": "Уточнённая оценка" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289/time/161', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ seconds: 900, comment: 'Уточнённая оценка', }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/289/time/161', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ seconds: 900, comment: 'Уточнённая оценка', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успешном обновлении | | `data.id` | number | Идентификатор обновлённой записи | ## Пример ответа ```json { "success": true, "data": { "id": 161 } } ``` ## Пример ответа при ошибке 422 — запись не найдена или недоступна: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "TASKS_ERROR_EXCEPTION_#512; Check listitem not found or not accessible; 512/TE/ITEM_NOT_FOUND_OR_NOT_ACCESSIBLE" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `READONLY_FIELD` | Передан `userId` — автора записи изменить нельзя (см. «Известные особенности») | | 422 | `BITRIX_ERROR` | Запись с таким `itemId` не найдена или родительская задача недоступна | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `task` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Автора записи `userId` изменить нельзя.** Обновление принимает только `seconds`, `comment` и дату создания. Любое другое поле, включая `userId`, отвергает весь запрос целиком — вместе с переданными в нём `seconds` и `comment`. Поэтому `userId` в `PATCH` отклоняется заранее с `400 READONLY_FIELD`. Автор фиксируется при создании записи. Чтобы «переназначить» время, удалите запись и создайте новую с нужным `userId`. **Ответ — только `id`, без остальных полей.** Чтобы прочитать обновлённую запись со всеми полями, сделайте [`GET /v1/tasks/:taskId/time/:itemId`](./get.md). ## Смотрите также - [Получить запись](./get.md) - [Список записей](./list.md) - [Добавить запись](./create.md) - [Удалить запись](./delete.md) - [Задачи](/docs/entities/tasks) --- # Tasks: Unfavorite ## Убрать задачу из избранного `DELETE /v1/tasks/:taskId/favorite` Убирает задачу из личного списка избранного пользователя, от имени которого действует ключ. Действие доступно участнику с доступом к задаче на просмотр — права на редактирование задачи не нужны, в отличие от [`PATCH /v1/tasks/:id`](./update.md). ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `taskId` | path | integer | да | ID задачи. Список: `GET /v1/tasks` | Тело запроса пустое. ## Примеры ### curl — личный ключ ```bash curl -X DELETE -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/tasks/289/favorite ``` ### curl — OAuth-приложение ```bash curl -X DELETE -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ https://vibecode.bitrix24.tech/v1/tasks/289/favorite ``` ### JavaScript — личный ключ ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/tasks/${taskId}/favorite`, { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY' } } ) const body = await res.json() console.log(body.data.favorite) // false ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/tasks/${taskId}/favorite`, { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, } ) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | `true` при успешном удалении | | `data.taskId` | integer | ID задачи | | `data.favorite` | boolean | `false` — задача убрана из избранного | ## Пример ответа ```json { "success": true, "data": { "taskId": 289, "favorite": false } } ``` ## Пример ответа при ошибке 404 — задача не найдена или недоступна: ```json { "success": false, "error": { "code": "TASK_NOT_FOUND", "message": "Task 99999999 not found or not accessible." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_PARAMS` | `taskId` в пути не является положительным целым числом | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный ключ | | 401 | `TOKEN_MISSING` | У ключа нет привязанных токенов авторизации | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `task` | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ с доступом только на чтение — действие меняет данные и заблокировано | | 404 | `TASK_NOT_FOUND` | Задача не найдена или недоступна пользователю | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Ответ — краткое подтверждение, а не карточка задачи.** Полные поля задачи читайте через [`GET /v1/tasks/:id`](./get.md). ## Смотрите также - [Добавить задачу в избранное](./favorite.md) - [Открепить задачу](./unpin.md) - [Задачи](../tasks.md) --- # Tasks: Unpin ## Открепить задачу `DELETE /v1/tasks/:taskId/pin` Снимает закрепление задачи в личном списке задач пользователя, от имени которого действует ключ. Действие доступно участнику с доступом к задаче на просмотр — права на редактирование задачи не нужны, в отличие от [`PATCH /v1/tasks/:id`](./update.md). ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `taskId` | path | integer | да | ID задачи. Список: `GET /v1/tasks` | Тело запроса пустое. ## Примеры ### curl — личный ключ ```bash curl -X DELETE -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/tasks/289/pin ``` ### curl — OAuth-приложение ```bash curl -X DELETE -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ https://vibecode.bitrix24.tech/v1/tasks/289/pin ``` ### JavaScript — личный ключ ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/tasks/${taskId}/pin`, { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY' } } ) const body = await res.json() console.log(body.data.pinned) // false ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/tasks/${taskId}/pin`, { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, } ) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | `true` при успешном откреплении | | `data.taskId` | integer | ID задачи | | `data.pinned` | boolean | `false` — задача откреплена | ## Пример ответа ```json { "success": true, "data": { "taskId": 289, "pinned": false } } ``` ## Пример ответа при ошибке 404 — задача не найдена или недоступна: ```json { "success": false, "error": { "code": "TASK_NOT_FOUND", "message": "Task 99999999 not found or not accessible." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_PARAMS` | `taskId` в пути не является положительным целым числом | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный ключ | | 401 | `TOKEN_MISSING` | У ключа нет привязанных токенов авторизации | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `task` | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ с доступом только на чтение — действие меняет данные и заблокировано | | 404 | `TASK_NOT_FOUND` | Задачи с указанным `taskId` нет или она недоступна пользователю | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Ответ — краткое подтверждение, а не карточка задачи.** Полные поля задачи читайте через [`GET /v1/tasks/:id`](./get.md). ## Смотрите также - [Закрепить задачу](./pin.md) - [Убрать задачу из избранного](./unfavorite.md) - [Задачи](../tasks.md) --- # Tasks: Update ## Обновить задачу `PATCH /v1/tasks/:id` Обновляет поля существующей задачи. Передавайте только изменяемые поля. Полный список — [Поля задачи](./fields.md). ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID задачи | ## Поля запроса (body) Передавайте только изменяемые поля — поведение PATCH, остальные значения не затрагиваются. | Поле | Тип | Описание | |------|-----|---------| | `title` | string | Название | | `description` | string | Описание задачи (поддерживает BB-код) | | `responsibleId` | number | Новый ответственный. Список сотрудников: `GET /v1/users` | | `createdBy` | number | Новый постановщик. Применяется в пределах прав вызывающего пользователя. Только существующий сотрудник — см. предупреждение под таблицей. Список сотрудников: `GET /v1/users` | | `status` | number | Статус задачи. Полный список значений: `GET /v1/tasks/fields` → `fields.status.enum` | | `priority` | number | Приоритет: `0` — низкий, `1` — обычный, `2` — высокий | | `deadline` | datetime | Крайний срок (ISO 8601) | | `startDatePlan` | datetime | Плановая дата начала | | `endDatePlan` | datetime | Плановая дата окончания | | `timeEstimate` | number | Оценка трудозатрат в секундах | | `groupId` | number | Рабочая группа. Список: `GET /v1/workgroups` | | `parentId` | number | Родительская задача. Список: `GET /v1/tasks` | | `accomplices` | number[] | Соисполнители. Список сотрудников: `GET /v1/users` | | `auditors` | number[] | Наблюдатели. Список сотрудников: `GET /v1/users` | | `tags` | string[] | Метки задачи | | `ufTaskWebdavFiles` | string[] | Файлы задачи. Массив строк вида `n`, где `id` — идентификатор файла из ответа [`POST /v1/files/upload`](../files/upload.md). Запись заменяет весь список вложений, пустой массив снимает все вложения. Полное правило для полей-файлов — [Поля задачи](./fields.md) | | `changedBy` | number | Служебное поле: кто последним изменил задачу. Принимается на записи — см. раздел под таблицей. Список сотрудников: `GET /v1/users` | | `closedBy` | number | Служебное поле: кто закрыл задачу. Принимается на записи — см. раздел под таблицей. Список сотрудников: `GET /v1/users` | | `statusChangedBy` | number | Служебное поле: кто последним сменил статус. Принимается на записи — см. раздел под таблицей. Список сотрудников: `GET /v1/users` | | `createdDate` | datetime | Служебное поле: дата создания задачи, ISO 8601. Принимается на записи — см. раздел под таблицей | | `changedDate` | datetime | Служебное поле: дата последнего изменения, ISO 8601. Переданное значение сохраняется вместо текущего времени — см. раздел под таблицей | | `closedDate` | datetime | Служебное поле: дата закрытия, ISO 8601. Принимается на записи даже у незакрытой задачи — см. раздел под таблицей | Поля `id`, `dateStart`, `activityDate`, `realStatus` — read-only, в body не передаются. ### Служебные поля задачи можно задавать `createdBy` (постановщик), `changedBy`, `closedBy`, `statusChangedBy`, `createdDate`, `changedDate`, `closedDate` **принимаются** и при создании, и при обновлении: Битрикс24 сохраняет переданные значения, а Вайбкод — обёртка над ним и не запрещает того, что разрешает платформа. Принимаются оба написания — и `createdBy`, и `CREATED_BY`. Передавайте одно из двух, а не оба сразу: при обоих в одном теле применится то, которое встретится позже, без предупреждения. Значение применяется в пределах прав вызывающего пользователя. Если Битрикс24 отказывает в правке задачи, отказ приходит как есть — `422` с его собственным текстом, без подмены на нашу ошибку и без ложного успеха. **Что видно в журнале задачи.** Смену постановщика Битрикс24 пишет в журнал изменений задачи, и там остаётся настоящий вызывающий пользователь, а не тот, кого передали в `createdBy`. Для остальных шести полей отдельной записи в журнале не предусмотрено: по значению в карточке нельзя определить, кто его выставил. **Дата без часового пояса.** У `createdDate`, `changedDate` и `closedDate` значение вида `2019-05-15T13:47:00` в написании `createdDate` получает смещение вашего пояса из заголовка `X-Vibe-Timezone`, а в написании `CREATED_DATE` уходит как есть и читается в поясе владельца ключа. Передавайте дату со смещением — `2019-05-15T13:47:00+03:00` — и оба написания дадут один и тот же момент. Ограничить подмену служебных полей может только модель прав Битрикс24 — это отдельная доработка на стороне платформы, а не нашей обёртки. > **Передавайте только существующего сотрудника.** Битрикс24 не проверяет идентификатор пользователя на существование ни в `createdBy`, ни в `changedBy`, `closedBy`, `statusChangedBy` — он запишет любое число. Задача с несуществующим постановщиком перестаёт управляться через API: Битрикс24 отказывает и в дальнейшем обновлении, и в удалении (`Действие над задачей не разрешено`), причём и через обёртку, и напрямую, даже ключу администратора. Такой исход проверен на `createdBy`. У трёх остальных полей идентификатор не проверяется так же, поэтому передавайте существующего сотрудника и в них. Список сотрудников: [`GET /v1/users`](/docs/entities/users). ## Часто обновляемые поля | Поле | Когда используется | |------|-------------------| | `status` | Закрытие (`5`), возврат в работу (`3`), отказ (`7`). Расшифровка: `GET /v1/tasks/fields` → `fields.status.enum` | | `responsibleId` | Передача задачи другому сотруднику. Источник: `GET /v1/users` | | `deadline` | Перенос срока (ISO 8601 со смещением часового пояса портала) | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/tasks/3871" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "status": 5, "priority": 2 }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/tasks/3871" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "status": 5, "priority": 2 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/3871', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ status: 5, priority: 2, }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/tasks/3871', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ status: 5, priority: 2, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Обновлённый объект задачи со всеми полями — см. [Поля задачи](./fields.md) | ## Пример ответа ```json { "success": true, "data": { "id": "3871", "title": "Подготовить отчёт за квартал", "status": "5", "priority": "2", "responsibleId": "1", "createdBy": "1", "createdDate": "2026-05-12T11:46:12+03:00", "changedDate": "2026-05-12T13:02:48+03:00", "closedDate": "2026-05-12T13:02:48+03:00", "deadline": "2026-05-19T18:00:00+03:00", "accomplices": [], "auditors": [] } } ``` ## Пример ответа при ошибке 400 — попытка изменить поле, доступное только на чтение: ```json { "success": false, "error": { "code": "READONLY_FIELD", "message": "Field 'activityDate' is read-only and cannot be set" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Битрикс24 отклонил обновление — например, задача с таким ID недоступна или не существует, либо переданное значение отклонено порталом | | 404 | `ENTITY_NOT_FOUND` | Связанная сущность не найдена — например, `responsibleId` указывает на несуществующего сотрудника | | 400 | `READONLY_FIELD` | Попытка обновить поле, доступное только на чтение (`id`, `dateStart`, `activityDate`, `realStatus`) | | 400 | `INVALID_DISK_ATTACHMENT_VALUE` | Значение поля-файла передано не массивом строк вида `n` — числом, строкой без префикса или одиночной строкой вместо массива | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `tasks` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Закрытие задачи.** Чтобы пометить задачу выполненной, отправьте `status: 5`. После этого Битрикс24 сам заполняет `closedDate` — при переводе в статус `5` (завершена) или `6` (отложена). Передавать `closedDate` вручную тоже можно — см. раздел о служебных полях выше. Если поле не передано, платформа проставит его сама. ## Смотрите также - [Получить задачу](./get.md) - [Поля задачи](./fields.md) - [Удалить задачу](./delete.md) - [Список задач](./list.md) - [Загрузить файл](../files/upload.md) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Timelines: Create ## Добавить комментарий `POST /v1/timelines` Создаёт новый комментарий таймлайна, привязанный к записи CRM. Используется для фиксации заметок по сделкам, лидам, контактам и компаниям. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | **`entityType`** | string | да | Тип родительской записи CRM: `deal`, `lead`, `contact`, `company` или `DYNAMIC_` для смарт-процессов (например, `DYNAMIC_174` для смарт-процесса с `entityTypeId: 174` из [`GET /v1/smart-processes`](/docs/entities/smart-processes/list)) | | **`entityId`** | number | да | ID родительской записи. Источник зависит от типа: `GET /v1/deals`, `GET /v1/leads`, `GET /v1/contacts`, `GET /v1/companies`, `GET /v1/items/:entityTypeId` (элементы смарт-процессов) | | **`comment`** | string | да | Текст комментария. Пустая строка отклоняется ошибкой `BITRIX_ERROR Empty comment message` | | `FILES` | array | нет | Вложения к комментарию. Каждый элемент — массив из двух строк `[имяФайла, base64Содержимое]`. Тип поля в схеме Битрикс24 — `attached_diskfile` | При создании через API автор (`authorId`) проставляется по владельцу API-ключа, дата создания (`createdAt`) — сервером. **Прикрепление файлов.** Поле `FILES` — массив пар `[имяФайла, base64Содержимое]`, по одной паре на файл. Содержимое файла передаётся как строка в кодировке base64, файл загружается на Диск Битрикс24 и привязывается к комментарию. При чтении комментария ([`GET /v1/timelines/:id`](/docs/entities/timelines/get)) прикреплённые файлы возвращаются в поле `FILES` — объект, где ключ это ID файла на Диске, а значение содержит метаданные: ```json "FILES": { "9317": { "id": 9317, "name": "report.pdf", "size": 11, "type": "file", "urlDownload": "https://vibecode.bitrix24.tech/disk/downloadFile/9317/?filename=report.pdf" } } ``` ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/timelines \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "entityType": "deal", "entityId": 741, "comment": "Первый контакт: клиент заинтересовался предложением" }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/timelines \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "entityType": "deal", "entityId": 741, "comment": "Первый контакт: клиент заинтересовался предложением" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/timelines', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ entityType: 'deal', entityId: 741, comment: 'Первый контакт: клиент заинтересовался предложением', }), }) const { success, data } = await res.json() console.log('Comment ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/timelines', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ entityType: 'deal', entityId: 741, comment: 'Первый контакт: клиент заинтересовался предложением', }), }) const { success, data } = await res.json() ``` ### curl — комментарий с файлом ```bash curl -X POST https://vibecode.bitrix24.tech/v1/timelines \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "entityType": "deal", "entityId": 741, "comment": "Отчёт во вложении", "FILES": [["report.pdf", "JVBERi0xLjQKJ..."]] }' ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | number | ID созданного комментария | | `entityType` | string | Тип родительской записи | | `entityId` | number | ID родительской записи | | `comment` | string | Текст комментария | | `authorId` | number | ID автора — при создании через API соответствует владельцу ключа | | `createdAt` | datetime | Дата создания (ISO 8601, UTC) | | `FILES` | object | Прикреплённые файлы — только если были переданы. Ключ — ID файла на Диске, значение — метаданные: `name`, `size`, `type`, `urlDownload` | ## Пример ответа ```json { "success": true, "data": { "id": 66303, "entityId": 741, "entityType": "deal", "comment": "Первый контакт: клиент заинтересовался предложением", "authorId": 1, "createdAt": "2026-04-24T12:34:05.000Z" } } ``` ## Пример ответа при ошибке 422 — не передан обязательный `comment`: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Empty comment message" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_FILES_SHAPE` | Поле `FILES` передано не массивом пар `[[имяФайла, base64Содержимое]]` | | 422 | `BITRIX_ERROR` | Нарушение требований: пустой `comment`, неверный `entityType` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список комментариев](/docs/entities/timelines/list) - [Обновить комментарий](/docs/entities/timelines/update) - [Удалить комментарий](/docs/entities/timelines/delete) - [Поля комментария](/docs/entities/timelines/fields) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Timelines: Delete ## Удалить комментарий `DELETE /v1/timelines/:id` Удаляет комментарий таймлайна по ID. Восстановить удалённый комментарий через API нельзя — при необходимости создавайте новый. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID комментария | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/timelines/66303" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/timelines/66303" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/timelines/66303', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Комментарий удалён') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/timelines/66303', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Удалено') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — признак успеха проверяется по статусу. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — комментарий не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Комментарий не найден (или уже удалён) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список комментариев](/docs/entities/timelines/list) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Timelines: Fields ## Поля комментария `GET /v1/timelines/fields` Возвращает схему полей комментария таймлайна. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/timelines/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/timelines/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/timelines/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Поля:', Object.keys(data.fields)) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/timelines/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Битрикс24 | Тип | RO | Описание | |------|----------|-----|:--:|---------| | `id` | `ID` | number | да | ID комментария | | `entityType` | `ENTITY_TYPE` | string | | Тип родительской записи CRM: `deal`, `lead`, `contact`, `company` или `DYNAMIC_` для смарт-процессов (например, `DYNAMIC_174`). В ответе приходит в нижнем регистре (`dynamic_174`). Задаётся только при создании | | `entityId` | `ENTITY_ID` | number | | ID родительской записи. Задаётся только при создании. Источник: `GET /v1/deals`, `GET /v1/leads`, `GET /v1/contacts`, `GET /v1/companies`, `GET /v1/items/:entityTypeId` (элементы смарт-процессов) | | `comment` | `COMMENT` | string | | Текст комментария. Обязателен при создании | | `authorId` | `AUTHOR_ID` | number | да | ID автора комментария. Данные пользователя по ID: `GET /v1/users/:id` | | `createdAt` | `CREATED` | datetime | да | Дата создания, ISO 8601 в UTC | | `FILES` | `FILES` | attached_diskfile | | Вложения. На запись — массив пар `[[имяФайла, base64Содержимое]]`, на чтение — объект, где ключ это ID файла на Диске. Подробнее: [Добавить комментарий](/docs/entities/timelines/create) | ## Пример ответа `GET /v1/timelines/fields` возвращает описания полей под ключом `data.fields`, где каждое поле — `{ type, readonly, label, description }`. Подпись `label` у поля `FILES` приходит от Битрикс24 и зависит от языка портала. ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "ID", "description": "Уникальный числовой идентификатор комментария таймлайна." }, "entityType": { "type": "string", "readonly": false, "label": "Тип сущности", "description": "Тип родительской записи CRM: deal, lead, contact, company или DYNAMIC_ для смарт-процессов. Задаётся только при создании." }, "entityId": { "type": "number", "readonly": false, "label": "ID сущности", "description": "ID родительской записи CRM, к которой относится комментарий. Задаётся только при создании." }, "comment": { "type": "string", "readonly": false, "label": "Комментарий", "description": "Текст комментария. Обязателен при создании." }, "authorId": { "type": "number", "readonly": false, "label": "Автор", "description": "ID пользователя, написавшего комментарий." }, "createdAt": { "type": "datetime", "readonly": true, "label": "Создан", "description": "Дата и время создания комментария (ISO 8601, UTC)." }, "FILES": { "type": "attached_diskfile", "readonly": false, "label": "Список файлов", "description": "Файлы, приложенные к комментарию. На запись передаётся массив пар [имя файла, содержимое файла в base64], на чтение приходит объект, ключ которого — ID файла на Диске." } } } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'crm' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Добавить комментарий](/docs/entities/timelines/create) - [Список комментариев](/docs/entities/timelines/list) - [Entity API](/docs/entity-api) - [Лимиты и оптимизация](/docs/optimization) --- # Timelines: File Download ## Скачать вложение комментария таймлайна `GET /v1/timelines/:commentId/files/:fileRef/download` Скачивает файл, приложенный к комментарию таймлайна. Ответ — бинарный поток с заголовком `Content-Disposition`. Эндпоинт принимает **два разных идентификатора** в `fileRef`, потому что клиент может держать любой из них: - **ID привязки.** Его показывает интерфейс портала, и он же приходит в файловых пользовательских полях. Этот путь считает доступ через сущность-носитель, то есть через сам комментарий, а не через личные права на Диске — поэтому он дотягивается до вложений, которые [скачивание файла Диска](/docs/entities/files/download) отдавать отказывается; - **ID объекта Диска.** Это ключ объекта в поле `files` ответа [`GET /v1/timelines/:id`](/docs/entities/timelines/get). Путь идёт через личные права на Диске, поэтому может завершиться отказом там, где путь по ID привязки сработал бы. Сначала комментарий читается сам, затем пробуется ID объекта Диска, и только если его нет в списке файлов комментария — ID привязки. Указывать, какой идентификатор вы передаёте, не нужно. Такой порядок дешевле: документированный случай обходится двумя обращениями к Битрикс24 вместо трёх. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `commentId` | path | number | да | ID комментария таймлайна. Получить: [`GET /v1/timelines`](/docs/entities/timelines/list) | | `fileRef` | path | number | да | ID привязки либо ID объекта Диска. Второй — ключ объекта в поле `files` ответа [`GET /v1/timelines/:id`](/docs/entities/timelines/get) | Тело запроса пустое. ## Примеры ### curl — личный ключ ```bash # По ID объекта Диска — ключ из поля files ответа комментария curl -OJ -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/timelines/67689/files/9747/download # По ID привязки — если он у вас есть curl -OJ -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/timelines/67689/files/551/download ``` ### curl — OAuth-приложение ```bash curl -OJ \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ https://vibecode.bitrix24.tech/v1/timelines/67689/files/9747/download ``` ### JavaScript — личный ключ ```javascript // Идентификаторы вложений берём из ответа комментария const comment = await fetch( 'https://vibecode.bitrix24.tech/v1/timelines/67689', { headers: { 'X-Api-Key': 'YOUR_API_KEY' } }, ).then(r => r.json()) for (const objectId of Object.keys(comment.data.files ?? {})) { const res = await fetch( `https://vibecode.bitrix24.tech/v1/timelines/67689/files/${objectId}/download`, { headers: { 'X-Api-Key': 'YOUR_API_KEY' } }, ) if (!res.ok) { const { error } = await res.json() console.warn(`${objectId}: ${error.code}`) continue } console.log(objectId, 'байт:', (await res.arrayBuffer()).byteLength) } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/timelines/67689/files/9747/download', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }, ) const bytes = await res.arrayBuffer() ``` ## Заголовки ответа При успехе возвращается бинарное содержимое файла (HTTP 200). Секции `## Поля ответа` нет — тело ответа не является JSON. | Заголовок | Пример значения | Описание | |-----------|-----------------|----------| | `Content-Type` | `image/gif` | Тип содержимого, как его отдал Битрикс24 | | `Content-Disposition` | `attachment; filename="scan.pdf"` | Имя файла для сохранения | | `Content-Length` | `43` | Размер в байтах, если Битрикс24 его сообщил | ## Пример ответа при ошибке 404 — вложение относится к другому комментарию: ```json { "success": false, "error": { "code": "NOT_FOUND", "message": "Attachment 551 does not belong to comment 11111" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_PARAMS` | `commentId` или `fileRef` не является положительным целым числом | | 401 | `TOKEN_MISSING` | У ключа не настроены токены Битрикс24 | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `crm` | | 404 | `NOT_FOUND` | Комментария не существует, вложение относится к другому комментарию или к записи другого типа (задаче, предложению) либо его принадлежность комментарию подтвердить не удалось, файл не входит в его список файлов, либо у файла нет адреса для скачивания | | 502 | `DOWNLOAD_FAILED` | Битрикс24 не отдал файл либо назвал адрес за пределами домена аккаунта — по такому адресу запрос не уходит | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Вложение обязано относиться к названному комментарию.** Иначе — `404`. Без этой проверки эндпоинт позволял бы перебирать вложения портала. - **Адрес наружу не отдаётся.** В адресе для скачивания содержится код авторизации, поэтому эндпоинт отдаёт только поток байтов. - **Поле `urlDownload` из ответа комментария напрямую не работает.** Этот адрес ведёт на страницу Диска, а не в REST, и авторизовать его ключом нельзя: запрос по нему перенаправляет на страницу входа. Скачивайте через этот эндпоинт. - **Два пути дают разный доступ.** Если по ID объекта Диска приходит отказ по правам, а ID привязки у вас есть — попробуйте его: он считает доступ через комментарий, а не через личное хранилище. - **Адрес скачивания проверяется, включая перенаправления.** Он приходит в ответе Битрикс24, поэтому эндпоинт сверяет его с доменом аккаунта и по чужому адресу запрос не отправляет — иначе туда ушёл бы код авторизации. Перенаправления эндпоинт проходит сам, проверяя каждый шаг: цепочка ограничена по длине и по времени, а перенаправление на внутренний адрес не выполняется и приводит к `502`. - **Временная ошибка не выдаётся за `404`.** Если Битрикс24 ответил лимитом запросов, оказался недоступен или сработала защита от повторяющихся ошибок, приходит именно это — `429` либо `502`/`503` с заголовком `Retry-After`, а не «файл не относится к комментарию». Поэтому `404` здесь всегда означает неверную ссылку: повторять запрос по ней бессмысленно, а по `429`/`5xx` — нужно, с задержкой. ## Смотрите также - [Получить комментарий таймлайна](/docs/entities/timelines/get) - [Скачать файл дела](/docs/entities/activities/file-download) - [Скачать файл Диска](/docs/entities/files/download) - [Таймлайны](/docs/entities/timelines) --- # Timelines: Get ## Получить комментарий `GET /v1/timelines/:id` Возвращает один комментарий таймлайна по его ID. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID комментария. Получить список ID — [`GET /v1/timelines`](/docs/entities/timelines/list) | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/timelines/66303" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/timelines/66303" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/timelines/66303', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Комментарий:', data.comment) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/timelines/66303', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа Объект комментария со всеми полями — см. [Поля комментария](/docs/entities/timelines/fields). ## Пример ответа ```json { "success": true, "data": { "id": 66303, "entityId": 575, "entityType": "deal", "comment": "Первый контакт: клиент заинтересовался предложением", "authorId": 1, "createdAt": "2026-04-24T12:34:05.000Z" } } ``` ## Пример ответа при ошибке 422 — комментарий не найден: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Not found." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Комментарий с указанным ID не существует | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список комментариев](/docs/entities/timelines/list) - [Обновить комментарий](/docs/entities/timelines/update) - [Удалить комментарий](/docs/entities/timelines/delete) - [Поля комментария](/docs/entities/timelines/fields) - [Лимиты и оптимизация](/docs/optimization) --- # Timelines: List ## Список комментариев `GET /v1/timelines` Возвращает комментарии таймлайна, привязанные к конкретной записи CRM. Фильтр по `entityType` и `entityId` обязателен — без них запрос возвращает `400 MISSING_REQUIRED_FILTER`. ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `filter[entityType]` | string | да | — | Тип родительской записи CRM: `deal`, `lead`, `contact`, `company` или `DYNAMIC_` для смарт-процессов (например, `DYNAMIC_174`) | | `filter[entityId]` | number | да | — | ID родительской записи. Источник зависит от типа: `GET /v1/deals`, `GET /v1/leads`, `GET /v1/contacts`, `GET /v1/companies`, `GET /v1/items/:entityTypeId` (элементы смарт-процессов) | | `limit` | number | нет | `50` | Количество записей (до 5000). При `limit > 50` Вайбкод автоматически запрашивает несколько страниц у Битрикс24 | | `offset` | number | нет | `0` | Пропустить N записей. При `offset > 0` рекомендуется `limit ≤ 500` | | `select` | string | нет | — | Выборка полей: `?select=id,comment,authorId` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/timelines?filter[entityType]=deal&filter[entityId]=741" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/timelines?filter[entityType]=deal&filter[entityId]=741" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/timelines?filter[entityType]=deal&filter[entityId]=741', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} комментариев`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/timelines?filter[entityType]=deal&filter[entityId]=741', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив комментариев (все поля — см. [Поля комментария](/docs/entities/timelines/fields)) | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | ## Пример ответа ```json { "success": true, "data": [ { "id": 66309, "entityId": 741, "entityType": "deal", "comment": "Первый контакт: клиент заинтересовался предложением", "authorId": 1, "createdAt": "2026-04-24T12:39:28.000Z" }, { "id": 66311, "entityId": 741, "entityType": "deal", "comment": "Уточнение: клиент готов подписать договор на следующей неделе", "authorId": 1, "createdAt": "2026-04-24T12:39:30.000Z" } ], "meta": { "total": 2, "hasMore": false } } ``` ## Пример ответа при ошибке 400 — не передан обязательный фильтр: ```json { "success": false, "error": { "code": "MISSING_REQUIRED_FILTER", "message": "GET /v1/timelines requires filter fields: entityType, entityId. Example: GET /v1/timelines?filter[entityType]=...&filter[entityId]=..." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_FILTER` | Не переданы обязательные `filter[entityType]` и `filter[entityId]` | | 422 | `BITRIX_ERROR` | Неверное значение `entityType` (например, числовой код CRM вместо строки) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`entityType` — строка.** Используйте строковые идентификаторы CRM-типов: `deal`, `lead`, `contact`, `company`. Для смарт-процессов — `DYNAMIC_` (например, `DYNAMIC_174`). В ответе значение приходит в нижнем регистре (`dynamic_174`). Числовые коды CRM в `entityType` не работают — возвращается `422 BITRIX_ERROR Access denied.`. **Фильтрация только по `entityType` + `entityId`.** Битрикс24 игнорирует любые дополнительные поля в фильтре (`authorId`, `comment`, диапазоны `>=createdAt` и т. п.) — ответ возвращается тот же, что и без них. Если нужен отбор по автору или тексту — получите все комментарии записи и отфильтруйте на стороне клиента. **Порядок результатов — по `id` ASC.** Список возвращается в порядке создания: самые ранние комментарии первыми. Если нужен обратный порядок — переверните массив на клиенте (`data.reverse()`). Параметры сортировки (`order[...]`, `sort=`) для этого эндпоинта не применяются. **Авто-пагинация.** При `limit > 50` Вайбкод автоматически запрашивает несколько страниц у Битрикс24 и возвращает все записи в одном ответе. ## Смотрите также - [Получить комментарий](/docs/entities/timelines/get) - [Добавить комментарий](/docs/entities/timelines/create) - [Поля комментария](/docs/entities/timelines/fields) - [Синтаксис фильтрации](/docs/filtering) - [Entity API](/docs/entity-api) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Timelines: Search ## Поиск комментариев `POST /v1/timelines/search` Поиск комментариев таймлайна с фильтром через тело запроса — единый интерфейс с остальными сущностями. Фильтр по `entityType` и `entityId` обязателен: без них запрос возвращает `400 MISSING_REQUIRED_FILTER`. Для простой выборки в контексте одной записи подойдёт и [`GET /v1/timelines`](/docs/entities/timelines/list) с фильтром в параметрах запроса. ## Поля запроса (body) | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `filter.entityType` | string | да | — | Тип родительской записи CRM: `deal`, `lead`, `contact`, `company` или `DYNAMIC_` для смарт-процессов (например, `DYNAMIC_174`). Значение `entityTypeId` — из [`GET /v1/smart-processes`](/docs/entities/smart-processes/list) | | `filter.entityId` | number | да | — | ID родительской записи. Источник зависит от типа: `GET /v1/deals`, `GET /v1/leads`, `GET /v1/contacts`, `GET /v1/companies`, `GET /v1/items/:entityTypeId` (элементы смарт-процессов) | | `limit` | number | нет | `50` | Количество записей (до 5000) | | `offset` | number | нет | `0` | Пропустить N записей | | `select` | string[] | нет | — | Выборка полей: `["id", "comment", "authorId"]` | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/timelines/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "entityType": "deal", "entityId": 575 }, "select": ["id", "comment", "authorId"], "limit": 3 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/timelines/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "entityType": "deal", "entityId": 575 }, "select": ["id", "comment", "authorId"], "limit": 3 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/timelines/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { entityType: 'deal', entityId: 575 }, select: ['id', 'comment', 'authorId'], limit: 3, }), }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} комментариев`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/timelines/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { entityType: 'deal', entityId: 575 }, select: ['id', 'comment', 'authorId'], limit: 3, }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив комментариев (все поля — см. [Поля комментария](/docs/entities/timelines/fields)) | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа В запросе передан `select`, поэтому в ответе только выбранные поля. ```json { "success": true, "data": [ { "id": 67119, "comment": "Первый контакт: клиент заинтересовался предложением", "authorId": 1 }, { "id": 67121, "comment": "Уточнение: клиент готов подписать договор на следующей неделе", "authorId": 1 } ], "meta": { "total": 2, "hasMore": false, "durationMs": 1208 } } ``` ## Пример ответа при ошибке 400 — не передан обязательный фильтр: ```json { "success": false, "error": { "code": "MISSING_REQUIRED_FILTER", "message": "POST /v1/timelines/search requires filter fields: entityType, entityId. Example body: { \"filter\": {\"entityType\":\"...\",\"entityId\":\"...\"} }" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_REQUIRED_FILTER` | Не переданы обязательные `filter.entityType` и `filter.entityId` | | 422 | `BITRIX_ERROR` | Неверное значение `entityType` (например, числовой код CRM вместо строки) | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Фильтрация только по `entityType` + `entityId`.** Битрикс24 игнорирует любые дополнительные поля в фильтре (`authorId`, `comment`, диапазоны по `createdAt` и прочее) — ответ возвращается тот же, что и без них. Если нужен отбор по автору или тексту — получите все комментарии записи и отфильтруйте на стороне клиента. **Порядок результатов — по возрастанию `id`.** Список возвращается в порядке создания: самые ранние комментарии первыми. Параметры сортировки (`order`, `sort`) для этого эндпоинта не применяются. ## Смотрите также - [Список комментариев](/docs/entities/timelines/list) - [Получить комментарий](/docs/entities/timelines/get) - [Поля комментария](/docs/entities/timelines/fields) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Timelines: Update ## Обновить комментарий `PATCH /v1/timelines/:id` Изменяет текст существующего комментария таймлайна. Передайте только поле `comment` — остальные поля (`entityType`, `entityId`, `authorId`, `createdAt`) фиксируются при создании и через API не изменяются. ## Часто обновляемые поля | Поле | Тип | Описание | |------|-----|---------| | `comment` | string | Новый текст комментария | Полный список полей — [`GET /v1/timelines/fields`](/docs/entities/timelines/fields). ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/timelines/66303" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "comment": "Уточнение: клиент готов подписать договор на следующей неделе" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/timelines/66303" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "comment": "Уточнение: клиент готов подписать договор на следующей неделе" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/timelines/66303', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ comment: 'Уточнение: клиент готов подписать договор на следующей неделе', }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/timelines/66303', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ comment: 'Уточнение: клиент готов подписать договор на следующей неделе', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | object | Обновлённый объект комментария — все поля, см. [Поля комментария](/docs/entities/timelines/fields) | ## Пример ответа ```json { "success": true, "data": { "id": 66303, "entityId": 741, "entityType": "deal", "comment": "Уточнение: клиент готов подписать договор на следующей неделе", "authorId": 1, "createdAt": "2026-04-24T12:34:05.000Z" } } ``` ## Пример ответа при ошибке 404 — комментарий не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Элемент не найден" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Комментарий с указанным ID не существует | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить комментарий](/docs/entities/timelines/get) - [Добавить комментарий](/docs/entities/timelines/create) - [Удалить комментарий](/docs/entities/timelines/delete) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Users: Aggregate ## Агрегация сотрудников `POST /v1/users/aggregate` Подсчёт количества сотрудников с фильтрацией: - **`count`** — работает на любом запросе (с фильтром или без). - **`groupBy`** — по стандартным полям из списка агрегации (`active`, `isAdmin`, `isOnline`, `departmentId`, `workPosition`, `personalGender`, `personalCity`) и по пользовательским (UF) полям любого типа. - **`sum` / `avg` / `min` / `max`** — только по UF-полям числовых типов: `integer`, `double`, `money`. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций. Каждый элемент: `{ "field": "UF_*", "function": "sum" }`. Для `count` поле — `"*"`. Без параметра — только `count` | | `filter` | object | нет | Фильтрация по полям `GET /v1/users/fields`.
[Синтаксис фильтрации](/docs/filtering). Принимает `camelCase` и `UPPER_SNAKE_CASE` | | `groupBy` | string \| string[] | нет | Имя поля или массив (до 5). Поддерживаются: стандартные поля `active`, `isAdmin`, `isOnline`, `departmentId`, `workPosition`, `personalGender`, `personalCity`; а также любые UF-поля портала | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/users/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "active": true } }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/users/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "active": true } }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/users/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { active: true }, }), }) const { success, data } = await res.json() console.log('Активных сотрудников:', data.count) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/users/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { active: true }, }), }) const { success, data } = await res.json() ``` > Для группировки по нескольким полям передайте массив: `"groupBy": ["active", "workPosition"]` (максимум 5). ## Другие сценарии Подсчёт записей — `count` с полем `"*"`, самый быстрый запрос без выгрузки записей. Без массива `aggregate` результат тот же: ```json { "aggregate": [{ "field": "*", "function": "count" }] } ``` Распределение по статусу активности — сколько сотрудников активно, сколько деактивировано: ```json { "groupBy": "active" } ``` Группировка по UF-полю «Внутренний номер»: ```json { "groupBy": "UF_PHONE_INNER" } ``` Сумма по числовому UF-полю с группировкой: ```json { "aggregate": [{ "field": "UF_SALARY", "function": "sum" }], "groupBy": "UF_DEPARTMENT" } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Количество записей под фильтр | | `data.aggregates` | object | Результаты агрегаций (пустой объект, если в запросе не было `aggregate`) | | `data.groups` | array | Группы (только при `groupBy`). Каждый элемент: значения полей группировки + `count` | | `data.meta.totalRecords` | number | Общее количество записей под фильтр | | `data.meta.recordsProcessed` | number | Количество обработанных записей | | `data.meta.truncated` | boolean | `true`, если попало больше 5000 записей и часть не вошла в выборку | ## Пример ответа Ответ на запрос `count` без `groupBy`: ```json { "success": true, "data": { "count": 57, "aggregates": {}, "meta": { "totalRecords": 57, "recordsProcessed": 0, "truncated": false } } } ``` Без `groupBy` поле `data.groups` в ответе отсутствует. ## Пример ответа при ошибке 400 — `groupBy` по несуществующему полю (сообщение содержит список доступных стандартных и UF-полей): ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "groupBy field 'nonexistent' is not aggregatable on this entity. Available: active, isAdmin, isOnline, departmentId, workPosition, personalGender, personalCity. User-defined: UF_DEPARTMENT (string), UF_PHONE_INNER (string), UF_EMPLOYMENT_DATE (string), UF_SKILLS (string), UF_INTERESTS (string), UF_LINKEDIN (string), UF_FACEBOOK (string)." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Несуществующее или недопустимое поле в `groupBy` или `aggregate.field` — сообщение содержит список доступных полей | | 400 | `INVALID_PARAMS` | UF-поле нечислового типа (`string`, `enumeration`, `date`) в `sum`/`avg`/`min`/`max` — сообщение называет тип | | 400 | `INVALID_PARAMS` | Больше 5 полей в `groupBy` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `user` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`count` vs числовые функции.** `count` считается одним вызовом Битрикс24 на любом объёме. `sum`/`avg`/`min`/`max` подгружают записи постранично (максимум 5000), считают на стороне Вайбкод. При более 5000 записей под фильтр — `meta.truncated: true`, агрегация по первым 5000. Для точного подсчёта на больших выборках — `count` или сужение фильтра. **Money-поля.** UF-поля типа `money` хранятся в формате `"сумма|валюта"` (`"50000|RUB"`) — агрегат извлекает числовую часть автоматически, складывать можно без парсинга. ## Смотрите также - [Список сотрудников](/docs/entities/users/list) - [Поля сотрудника](/docs/entities/users/fields) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Users: Create ## Создать сотрудника `POST /v1/users` Создаёт нового сотрудника на портале. Минимальное обязательное поле — `email`. Возвращает ID и полную запись только что созданного сотрудника. > Для интеграций с пользовательским вводом удобнее [`POST /v1/users/invite`](/docs/entities/users/invite): он валидирует email на стороне Вайбкод (`EMAIL_REQUIRED`, `EMAIL_INVALID`) и автоматически проставляет `departmentId: [1]` для штатных сотрудников. Этот эндпоинт — низкоуровневая форма, ошибки прокидываются от Битрикс24 как есть. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `email` | string | да | Email — должен быть уникальным среди всех сотрудников портала | | `name` | string | нет | Имя | | `lastName` | string | нет | Фамилия | | `secondName` | string | нет | Отчество | | `workPosition` | string | нет | Должность | | `workPhone` | string | нет | Рабочий телефон | | `personalPhone` | string | нет | Личный телефон | | `personalMobile` | string | нет | Мобильный телефон | | `personalBirthday` | string | нет | Дата рождения (ISO 8601) | | `personalGender` | string | нет | Пол: `M` — мужской, `F` — женский | | `personalCity` | string | нет | Город | | `departmentId` | number[] | условно | Массив ID отделов. Для штатных сотрудников **обязателен** — без него Битрикс24 вернёт `wrong_email`. Для экстранета (`EXTRANET: "Y"`) не используется | | `xmlId` | string | нет | Внешний идентификатор | | `EXTRANET` | string | нет | `"Y"` для пользователя экстранета. Тогда вместо `departmentId` нужен `SONET_GROUP_ID` (массив ID рабочих групп) | | `SONET_GROUP_ID` | number[] | условно | Массив ID рабочих групп — обязателен при `EXTRANET: "Y"`. Список: [`GET /v1/workgroups`](/docs/entities/workgroups) | Полный список — [Поля сотрудника](/docs/entities/users/fields). Пользовательские поля (`UF_*`) тоже принимаются. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/users" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Иван", "lastName": "Петров", "email": "ivan.petrov@example.com", "workPosition": "Менеджер", "departmentId": [1] }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/users" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Иван", "lastName": "Петров", "email": "ivan.petrov@example.com", "workPosition": "Менеджер", "departmentId": [1] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/users', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Иван', lastName: 'Петров', email: 'ivan.petrov@example.com', workPosition: 'Менеджер', departmentId: [1], }), }) const { success, data } = await res.json() console.log('User ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/users', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Иван', lastName: 'Петров', email: 'ivan.petrov@example.com', workPosition: 'Менеджер', departmentId: [1], }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | ID созданного сотрудника | Ответ содержит полную запись со всеми полями сотрудника — формат тот же, что у [`GET /v1/users/:id`](/docs/entities/users/get). URL карточки сотрудника в Битрикс24 строится из `id`: ``` https://.bitrix24.ru/company/personal/user// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": { "id": 1331, "xmlId": "74668002", "active": true, "name": "Иван", "lastName": "Петров", "email": "ivan.petrov@example.com", "lastLogin": null, "dateRegister": "2026-05-06T00:00:00.000Z", "isOnline": false, "timestampX": {}, "personalGender": null, "personalBirthday": null, "departmentId": [1], "workPosition": "Менеджер", "userType": "employee" } } ``` ## Пример ответа при ошибке 400 — email не передан или дублирует существующего сотрудника: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "wrong_email", "hint": "Bitrix24 `user.add` returns `wrong_email` for several distinct cases, not only malformed email: (a) the email is already used by ANOTHER Bitrix24 user globally — check with GET /v1/users?filter[EMAIL]=the-email first; (b) the email domain is not allowed by portal policy (some portals restrict external domains); (c) missing UF_DEPARTMENT for intranet users — it is required for intranet invites (try `UF_DEPARTMENT: [1]` for the root department); (d) for external users pass `EXTRANET: \"Y\"` + `SONET_GROUP_ID: [groupId]` instead of UF_DEPARTMENT. For a convenience wrapper, try POST /v1/users/invite which sets sensible defaults. If the email is valid and unused, ask the portal admin to check user-invite settings." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `BITRIX_ERROR` (`wrong_email`) | Email не передан, дублирует существующего сотрудника, не прошёл политику домена портала, либо для штатного сотрудника не указан `departmentId` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `user` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Email должен быть глобально уникальным.** Битрикс24 проверяет уникальность среди всех сотрудников портала включая ранее деактивированных. Перед созданием — поиск через `GET /v1/users?filter[EMAIL]=ivan.petrov@example.com`. Если запись найдена и деактивирована, верните её в строй через `PATCH /v1/users/:id { active: true }` — это сохранит историю действий и связи сотрудника, в отличие от создания дубля. **Неоднозначность ошибки `wrong_email`.** Битрикс24 возвращает `wrong_email` для нескольких разных ситуаций: email уже занят, домен запрещён политикой портала, у штатного сотрудника не указан `departmentId`, у внешнего — `SONET_GROUP_ID`. Сообщение не уточняет, какая именно. Чтобы разделить эти случаи на стороне Вайбкод, используйте [`POST /v1/users/invite`](/docs/entities/users/invite) — обёртка возвращает явные коды (`EMAIL_REQUIRED`, `EMAIL_INVALID`, `SONET_GROUP_ID_REQUIRED`) до запроса в Битрикс24. ## Смотрите также - [Пригласить сотрудника](/docs/entities/users/invite) - [Поля сотрудника](/docs/entities/users/fields) - [Список сотрудников](/docs/entities/users/list) - [Отделы](/docs/entities/departments) - [Лимиты и оптимизация](/docs/optimization) --- # Users: Delete ## Деактивировать сотрудника `DELETE /v1/users/:id` Деактивирует сотрудника — снимает доступ к порталу, но сохраняет всю запись и её связи. Эндпоинт маппится на обновление поля активности (`active: false`); все данные и история действий остаются в Битрикс24. Восстановить доступ — `PATCH /v1/users/:id { active: true }`. Требует прав администратора портала. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID сотрудника | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/users/1331" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/users/1331" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/users/1331', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() if (success && data.deactivated) { console.log(`Сотрудник ${data.id} деактивирован`) } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/users/1331', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успешной деактивации | | `data.id` | number | ID деактивированного сотрудника | | `data.active` | boolean | Всегда `false` после деактивации | | `data.deactivated` | boolean | Всегда `true` — явный маркер семантики операции | | `data.user` | object | Полная запись сотрудника после деактивации (best-effort: если повторное чтение записи не сработало, поле может отсутствовать — деактивация всё равно выполнена) | ## Пример ответа ```json { "success": true, "data": { "id": 1331, "active": false, "deactivated": true, "user": { "id": 1331, "name": "Иван", "lastName": "Петров", "email": "ivan.petrov@example.com", "active": false, "workPosition": "Менеджер", "departmentId": [1], "userType": "employee" } } } ``` ## Пример ответа при ошибке 403 — у владельца ключа нет прав администратора портала: ```json { "success": false, "error": { "code": "UPDATE_FAILED", "message": "Bitrix24 rejected user.update for deactivation (result: false)", "hint": "Bitrix24 returns false when the calling user lacks portal admin rights, or when the target user id does not exist. Verify the webhook/OAuth identity is a portal admin." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_ID` | `:id` не является положительным целым числом | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `user` | | 403 | `UPDATE_FAILED` | Битрикс24 вернул `result: false`. Чаще всего — нет прав администратора портала; реже — сотрудника с таким ID не существует | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Связи остаются.** После деактивации сотрудник продолжает значиться ответственным за сделки, автором комментариев, участником чатов. Email остаётся занятым — повторно использовать его при создании нового сотрудника не получится без предварительной реактивации существующего: [`PATCH /v1/users/:id { active: true }`](/docs/entities/users/update). **Best-effort повторное чтение записи.** Вайбкод пытается получить актуальную запись после успешной деактивации и кладёт её в `data.user`. Если вспомогательный вызов упал — поле отсутствует, но сама деактивация уже произведена и подтверждена. Повторный [`GET /v1/users/:id`](/docs/entities/users/get) подгрузит запись с `active: false`. ## Смотрите также - [Обновить сотрудника](/docs/entities/users/update) - [Список сотрудников](/docs/entities/users/list) - [Получить сотрудника](/docs/entities/users/get) - [Лимиты и оптимизация](/docs/optimization) --- # Users: Fields ## Поля сотрудника `GET /v1/users/fields` Возвращает полный список полей сущности «сотрудник», включая пользовательские (`UF_*`) поля портала. Каждое поле описано ключами `type` и `readonly`. У полей схемы приходят также подпись `label` и описание `description`, а у пола (`personalGender`) и типа учётной записи (`userType`) — перечень допустимых значений `enum`, где у каждого значения английская подпись `label` и русская `labelRu`. У пола стоит дополнительно `nullable: true`: если сотрудник его не указал, в ответе приходит `null` — то же самое сообщает и схема OpenAPI, где тип поля объявлен как `["string", "null"]`. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/users/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/users/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/users/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data.fields).length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/users/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Битрикс24 | Тип | RO | Описание | |------|----------|-----|:--:|---------| | `id` | `ID` | number | да | Идентификатор сотрудника | | `name` | `NAME` | string | | Имя | | `lastName` | `LAST_NAME` | string | | Фамилия | | `secondName` | `SECOND_NAME` | string | | Отчество | | `email` | `EMAIL` | string | | Email — обязательное при создании, должно быть уникальным | | `active` | `ACTIVE` | boolean | | Признак активности (`true` — работает, `false` — деактивирован) | | `workPosition` | `WORK_POSITION` | string | | Должность | | `workPhone` | `WORK_PHONE` | string | | Рабочий телефон | | `personalPhone` | `PERSONAL_PHONE` | string | | Личный телефон | | `personalMobile` | `PERSONAL_MOBILE` | string | | Мобильный телефон | | `personalBirthday` | `PERSONAL_BIRTHDAY` | string | | Дата рождения (формат ISO 8601) | | `personalGender` | `PERSONAL_GENDER` | string | | Пол: `M` — мужской, `F` — женский. Перечень приходит в `enum`. Если сотрудник пол не указал — `null` | | `personalCity` | `PERSONAL_CITY` | string | | Город | | `personalPhoto` | `PERSONAL_PHOTO` | string | | URL фотографии | | `departmentId` | `UF_DEPARTMENT` | number[] | | Массив ID отделов. Список: `GET /v1/departments` | | `xmlId` | `XML_ID` | string | | Внешний идентификатор для интеграций | | `isAdmin` | `IS_ADMIN` | boolean | да | Признак администратора портала. Наполняется только в `GET /v1/users/me` (`true`/`false`/`null`); в `GET /v1/users/:id` и списке недоступно | | `isOnline` | `IS_ONLINE` | boolean | да | Сотрудник сейчас в сети | | `dateRegister` | `DATE_REGISTER` | datetime | да | Дата регистрации в портале | | `lastLogin` | `LAST_LOGIN` | datetime | да | Дата последнего входа | | `lastActivityDate` | `LAST_ACTIVITY_DATE` | datetime | да | Дата последней активности | | `timeZone` | `TIME_ZONE` | string | | Часовой пояс сотрудника. Пример: `"Europe/Moscow"` | | `title` | `TITLE` | string | | Обращение / звание | | `personalWww` | `PERSONAL_WWW` | string | | Личный сайт | | `personalProfession` | `PERSONAL_PROFESSION` | string | | Профессия | | `personalIcq` | `PERSONAL_ICQ` | string | | ICQ (устаревшее поле Битрикс24) | | `personalFax` | `PERSONAL_FAX` | string | | Факс | | `personalPager` | `PERSONAL_PAGER` | string | | Пейджер | | `personalStreet` | `PERSONAL_STREET` | string | | Улица | | `userType` | `USER_TYPE` | string | да | Тип учётной записи: `"employee"` — штатный сотрудник, `"extranet"` — внешний. Перечень приходит в `enum`. Список скрывает почтовых пользователей, чат-ботов, пользователей Открытых линий и записи Реплики, поэтому в ответе приходит `employee` или `extranet`. Значение `"email"` (почтовый пользователь) — только значение фильтра: Битрикс24 перечисляет его среди допустимых значений фильтра `USER_TYPE`, но в выдаче оно не встречается, потому что метод исключает таких пользователей | | `timestampX` | `TIMESTAMP_X` | datetime | да | Метка последнего изменения записи в Битрикс24. Для части пользователей возвращается пустым объектом `{}` | **Поля рабочих сведений** (`WORK_*`, часть `PERSONAL_*`) приходят под исходными именами Битрикс24 в `UPPER_SNAKE_CASE` — их подписи Битрикс24 отдаёт сам, локализованные под язык портала. Десяти из них подписи в Битрикс24 нет вовсе (`WORK_FAX`, `WORK_PAGER`, `WORK_STREET`, `WORK_MAILBOX`, `WORK_STATE`, `WORK_ZIP`, `WORK_COUNTRY`, `WORK_PROFILE`, `WORK_LOGO`, `WORK_NOTES`) — там вместо подписи приходило само имя поля, и теперь подпись с описанием подставляет Вайбкод. Если портал такое поле всё-таки подписал сам, его подпись сохраняется без изменений. Незаполненное поле рабочих сведений в ответе на чтение обычно **отсутствует целиком** — проверяйте наличие ключа, а не пустую строку. **Пользовательские поля** (`UF_*`) также возвращаются в ответах и принимаются при создании или обновлении. У пользовательского поля типа «список» (`enumeration`) в ответе есть массив `items` с возможными значениями (`ID`, `VALUE`, `DEF`, `XML_ID`) — при условии, что у ключа выдан скоуп `user.userfield`; без него поле возвращается с подписью, но без `items`. **Поля `ufDepartment` не существует** — отдел сотрудника лежит в `departmentId`, массиве идентификаторов подразделений. Исходное имя Битрикс24 `UF_DEPARTMENT` принимается в `select` как алиас и проецирует канонический `departmentId`. Незнакомое имя в `select` не отклоняется — ответ дополняется предупреждением `UNKNOWN_SELECT_FIELD` в `meta.warnings`. ## Пример ответа ```json { "success": true, "data": { "fields": { "name": { "type": "string", "readonly": false, "label": "Имя", "description": "Имя сотрудника." }, "timestampX": { "type": "datetime", "readonly": true, "label": "Дата изменения", "description": "Метка времени последнего изменения записи сотрудника." }, "personalGender": { "type": "string", "readonly": false, "nullable": true, "label": "Пол", "description": "Пол сотрудника. Если сотрудник его не указал, в ответе приходит null.", "enum": [ { "value": "M", "label": "Male", "labelRu": "Мужской" }, { "value": "F", "label": "Female", "labelRu": "Женский" } ] }, "WORK_CITY": { "type": "string", "readonly": false, "label": "Город работы" }, "WORK_FAX": { "type": "string", "readonly": false, "label": "Факс компании", "description": "Номер факса компании в рабочих сведениях сотрудника." }, "UF_USR_STATUS": { "type": "enumeration", "readonly": false, "label": "Статус", "items": [ { "ID": "1", "VALUE": "Новый", "DEF": "N", "XML_ID": "x1" }, { "ID": "2", "VALUE": "В работе", "DEF": "Y", "XML_ID": "x2" } ] } }, "batch": ["create", "update", "delete"] } } ``` Показано по одному полю каждого вида. Реальный ответ содержит 30+ полей схемы в `camelCase` — каждое с подписью и описанием, — поля рабочих сведений Битрикс24 в `UPPER_SNAKE_CASE` (`WORK_*`, часть `PERSONAL_*`) и UF-поля конкретного портала. Исходное имя Битрикс24 у поля схемы в ответе не дублируется: `UF_DEPARTMENT` приходит как `departmentId`, `NAME` — как `name`. ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'user' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `user` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать сотрудника](/docs/entities/users/create) - [Обновить сотрудника](/docs/entities/users/update) - [Список сотрудников](/docs/entities/users/list) - [Пользовательские поля](/docs/userfields) - [Лимиты и оптимизация](/docs/optimization) --- # Users: Get ## Получить сотрудника `GET /v1/users/:id` Возвращает данные сотрудника по ID со всеми полями, включая пользовательские (`UF_*`). ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID сотрудника | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/users/29" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/users/29" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/users/29', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log(`${data.name} ${data.lastName} — ${data.email}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/users/29', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа Объект сотрудника со всеми полями — см. [Поля сотрудника](/docs/entities/users/fields). ## Пример ответа ```json { "success": true, "data": { "id": 29, "xmlId": "28936832", "active": true, "name": "Иван", "lastName": "Петров", "email": "ivan.petrov@example.com", "lastLogin": "2026-03-30T14:39:25.000Z", "dateRegister": "2020-04-23T00:00:00.000Z", "timeZone": "Asia/Yekaterinburg", "isOnline": false, "timestampX": {}, "lastActivityDate": {}, "personalPhoto": "https://cdn-ru.bitrix24.ru/.../photo.png", "departmentId": [1], "userType": "employee" } } ``` ## Пример ответа при ошибке 404 — сотрудник не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "user 999999999 not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_ID` | `:id` не является положительным целым числом | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `user` | | 404 | `ENTITY_NOT_FOUND` | Сотрудник с таким ID не найден или деактивирован и недоступен текущему ключу | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Поля `WORK_*` и часть полей `PERSONAL_*` приходят в `UPPER_SNAKE_CASE`.** `WORK_COMPANY`, `WORK_DEPARTMENT`, `WORK_WWW`, `WORK_FAX`, `WORK_CITY`, `WORK_STATE`, `WORK_ZIP`, `WORK_COUNTRY` и аналогичные; `PERSONAL_STATE`, `PERSONAL_ZIP`, `PERSONAL_COUNTRY`, `PERSONAL_MAILBOX`, `PERSONAL_NOTES` — в оригинальных именах Битрикс24. UF-поля портала тоже сохраняют свои имена. Стандартные поля (`name`, `email`, `active`, `timeZone`, `userType`, `departmentId` и др.) — `camelCase`. ## Смотрите также - [Поля сотрудника](/docs/entities/users/fields) - [Список сотрудников](/docs/entities/users/list) - [Обновить сотрудника](/docs/entities/users/update) - [Лимиты и оптимизация](/docs/optimization) --- # Users: Invite ## Пригласить сотрудника `POST /v1/users/invite` Создаёт нового сотрудника или приглашает внешнего пользователя на портал. Принимает поля в `camelCase` и `UPPER_SNAKE_CASE`, проставляет разумные значения по умолчанию и проверяет email до вызова Битрикс24 — возвращая понятные коды ошибок (`EMAIL_REQUIRED`, `EMAIL_INVALID`, `SONET_GROUP_ID_REQUIRED`) вместо общего `wrong_email`. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `email` | string | да | Email — должен быть уникальным среди всех сотрудников портала. Базовая синтаксическая проверка происходит на стороне Вайбкод | | `name` | string | нет | Имя | | `lastName` | string | нет | Фамилия | | `secondName` | string | нет | Отчество | | `workPosition` | string | нет | Должность | | `workPhone` | string | нет | Рабочий телефон | | `workCompany` | string | нет | Название компании | | `personalPhone` | string | нет | Личный телефон | | `personalMobile` | string | нет | Мобильный телефон | | `personalBirthday` | string | нет | Дата рождения (ISO 8601) | | `personalGender` | string | нет | Пол: `M` — мужской, `F` — женский | | `personalCity` | string | нет | Город | | `departmentId` | number[] | нет | Массив ID отделов. По умолчанию `[1]` (корневой отдел) для штатных сотрудников. Список: `GET /v1/departments` | | `extranet` | string | нет | `"Y"` для приглашения внешнего пользователя. В этом случае `departmentId` игнорируется и обязателен `sonetGroupId` | | `sonetGroupId` | number[] | условно | Массив ID рабочих групп — обязателен при `extranet: "Y"`. Список: [`GET /v1/workgroups`](/docs/entities/workgroups) | | `active` | boolean | нет | Признак активности (по умолчанию `true`) | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/users/invite" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "email": "ivan.petrov@example.com", "name": "Иван", "lastName": "Петров", "workPosition": "Менеджер" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/users/invite" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "email": "ivan.petrov@example.com", "name": "Иван", "lastName": "Петров", "workPosition": "Менеджер" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/users/invite', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ email: 'ivan.petrov@example.com', name: 'Иван', lastName: 'Петров', workPosition: 'Менеджер', }), }) const { success, data } = await res.json() console.log('Создан сотрудник ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/users/invite', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ email: 'ivan.petrov@example.com', name: 'Иван', lastName: 'Петров', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | ID созданного сотрудника | | `data.user` | object | Полная запись только что созданного сотрудника — те же поля, что у [`GET /v1/users/:id`](/docs/entities/users/get) | ## Пример ответа ```json { "success": true, "data": { "id": 1331, "user": { "id": 1331, "xmlId": "74668002", "active": true, "name": "Иван", "lastName": "Петров", "email": "ivan.petrov@example.com", "lastLogin": null, "dateRegister": "2026-05-06T00:00:00.000Z", "isOnline": false, "timestampX": {}, "personalGender": null, "departmentId": [1], "workPosition": "Менеджер", "userType": "employee" } } } ``` HTTP-статус ответа — `201 Created`. ## Пример ответа при ошибке 400 — email не передан: ```json { "success": false, "error": { "code": "EMAIL_REQUIRED", "message": "EMAIL (or `email`) is required to invite a user." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `EMAIL_REQUIRED` | В теле запроса нет `email` (или `EMAIL`) | | 400 | `EMAIL_INVALID` | Email не прошёл синтаксическую проверку Вайбкод | | 400 | `SONET_GROUP_ID_REQUIRED` | При `extranet: "Y"` не передан `sonetGroupId` | | 400 | `BITRIX_ERROR` (`wrong_email`) | Битрикс24 отклонил создание: email уже занят, домен запрещён политикой портала, или другая ошибка email | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `user` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Зачем дефолт `departmentId: [1]`.** Без `UF_DEPARTMENT` Битрикс24 возвращает обобщённый `wrong_email` без указания причины — отсутствие отдела у штатного сотрудника одна из самых частых ловушек. Подстановка корневого отдела `[1]` устраняет её для типового случая «приглашаем сотрудника, конкретный отдел неизвестен». Если структура отделов важна — передавайте `departmentId` явно. **Уникальность email на портале.** Email проверяется среди всех сотрудников включая ранее деактивированных — при дубле Битрикс24 отдаст `BITRIX_ERROR: wrong_email`. Перед приглашением — поиск через `GET /v1/users?filter[EMAIL]=ivan.petrov@example.com`. Если найден деактивированный, верните его в строй через [`PATCH /v1/users/:id { active: true }`](/docs/entities/users/update) — это сохранит историю и связи, в отличие от создания дубля. **Best-effort повторное чтение.** После успешного создания обёртка делает повторное чтение записи и кладёт её в `data.user`. Если вспомогательный вызов упал, `data.id` всё равно вернётся — сотрудник уже создан, повторное обращение [`GET /v1/users/:id`](/docs/entities/users/get) подгрузит запись. ## Смотрите также - [Создать сотрудника](/docs/entities/users/create) - [Список сотрудников](/docs/entities/users/list) - [Обновить сотрудника](/docs/entities/users/update) - [Отделы](/docs/entities/departments) - [Лимиты и оптимизация](/docs/optimization) --- # Users: List ## Список сотрудников `GET /v1/users` Возвращает список сотрудников портала с поддержкой фильтрации, сортировки и автопагинации. Метод не возвращает ботов, почтовых пользователей и пользователей Открытых линий. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` Вайбкод автоматически запрашивает несколько страниц у Битрикс24 | | `offset` | number | `0` | Пропустить N записей. При `offset > 0` рекомендуется `limit ≤ 500` | | `order` | object | — | Сортировка по любому полю записи. Пример: `?order[name]=asc` | | `filter` | object | — | Фильтрация по полям `GET /v1/users/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[name]=Иван` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/users?limit=10&filter[active]=true" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/users?limit=10&filter[active]=true" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/users?limit=10&filter[active]=true', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} сотрудников`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/users?limit=10&filter[active]=true', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив сотрудников. Каждый элемент содержит все поля — см. [Поля сотрудника](/docs/entities/users/fields) | | `meta.total` | number | Общее количество записей под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | URL карточки любого сотрудника из массива `data` — его `id`: ``` https://.bitrix24.ru/company/personal/user// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 1, "xmlId": "28889266", "active": true, "name": "Мария", "lastName": null, "secondName": "Отчество", "email": "maria@example.com", "lastLogin": "2026-05-05T08:25:11.000Z", "dateRegister": "2020-04-20T00:00:00.000Z", "timeZone": "Europe/Kaliningrad", "isOnline": false, "timestampX": {}, "lastActivityDate": {}, "personalGender": "F", "personalPhoto": "https://cdn-ru.bitrix24.ru/.../photo.jpg", "personalMobile": "+79991234567", "workPosition": null, "departmentId": [1, 107, 47], "userType": "employee" }, { "id": 29, "xmlId": "28936832", "active": true, "name": "Иван", "lastName": "Петров", "email": "ivan.petrov@example.com", "departmentId": [1], "userType": "employee" } ], "meta": { "total": 30, "hasMore": true } } ``` Показаны основные поля. Полный список — [Поля сотрудника](/docs/entities/users/fields). ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'user' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_FILTER_FIELD` | Фильтр по несуществующему полю — список полей в `GET /v1/users/fields` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `user` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Семантика `filter[active]`.** `active: true` исключает деактивированных. `active: false` Битрикс24 не интерпретирует как «только деактивированные» — возвращаются все. Чтобы получить только деактивированных, просеивайте результат на стороне клиента по полю `active`. **Поля `WORK_*` и часть полей `PERSONAL_*` приходят в `UPPER_SNAKE_CASE`.** `WORK_COMPANY`, `WORK_DEPARTMENT`, `WORK_WWW`, `WORK_FAX`, `WORK_CITY`, `WORK_STATE`, `WORK_ZIP`, `WORK_COUNTRY` и аналогичные; `PERSONAL_STATE`, `PERSONAL_ZIP`, `PERSONAL_COUNTRY`, `PERSONAL_MAILBOX`, `PERSONAL_NOTES` — в оригинальных именах Битрикс24. UF-поля портала тоже сохраняют свои имена. Стандартные поля (`name`, `email`, `active`, `timeZone`, `userType`, `departmentId` и др.) — `camelCase`. **Поле `lastActivityDate` (объявлено `datetime`).** На практике приходит **пустым объектом `{}`**, либо ключ **отсутствует** вовсе — ISO-строка по этому полю в проверках не наблюдалась. `{}` — истинное значение в JS, поэтому `if (u.lastActivityDate)` ложно-срабатывает. То же у `timestampX` (всегда `{}`). Не парсьте как дату и не полагайтесь на truthy-проверку; сравнивайте тип (`typeof x === 'string'`). См. сводку по «пусто» в datetime-полях в [обзоре сущности](/docs/entities/users) (п. 7). ## Смотрите также - [Получить сотрудника](/docs/entities/users/get) - [Поиск сотрудников](/docs/entities/users/search) - [Поля сотрудника](/docs/entities/users/fields) - [Синтаксис фильтрации](/docs/filtering) - [Entity API](/docs/entity-api) - [Лимиты и оптимизация](/docs/optimization) --- # Users: Search ## Поиск сотрудников `POST /v1/users/search` Поиск сотрудников с фильтрами в теле запроса и автопагинацией. Аналогичен [`GET /v1/users`](/docs/entities/users/list), но через POST — удобнее для сложных запросов и больших массивов значений в фильтре. ## Поля запроса (body) | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` | object | — | Фильтрация по полям `GET /v1/users/fields`.
[Синтаксис фильтрации](/docs/filtering). Пример: `{ "filter": { "active": true, "lastName": "Иванов" } }` | | `limit` | number | `50` | Количество записей (до 5000) | | `offset` | number | `0` | Пропустить N записей. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки» | | `order` | object | — | Сортировка: `{ "NAME": "asc" }` | | `autoWindow` | boolean | `true` | Разбивать выборку по недельным окнам при фильтре по диапазону дат шире 14 дней. `false` отключает разбиение | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/users/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "active": true }, "limit": 10 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/users/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "active": true }, "limit": 10 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/users/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { active: true }, limit: 10, }), }) const { success, data } = await res.json() console.log('Найдено:', data.length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/users/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { active: true }, limit: 10, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив сотрудников. Каждый элемент содержит все поля — см. [Поля сотрудника](/docs/entities/users/fields) | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временны́м окнам | | `meta.windowCount` | number | Число окон. Приходит при `autoWindowed: true` | | `meta.batchWaves` | number | Число волн параллельных запросов. Приходит при `autoWindowed: true` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. URL карточки любого сотрудника из массива `data` — его `id`: ``` https://.bitrix24.ru/company/personal/user// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 1, "active": true, "name": "Мария", "lastName": null, "email": "maria@example.com", "departmentId": [1, 107, 47] }, { "id": 29, "active": true, "name": "Иван", "lastName": "Петров", "email": "ivan.petrov@example.com", "departmentId": [1] } ], "meta": { "total": 59, "hasMore": true, "durationMs": 186 } } ``` С фильтром по диапазону дат шире 14 дней в `meta` дополнительно приходят `autoWindowed`, `windowCount` и `batchWaves`: ```json { "success": true, "data": [], "meta": { "total": 0, "hasMore": false, "autoWindowed": true, "windowCount": 131, "batchWaves": 3, "durationMs": 1189 } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'user' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_FILTER_FIELD` | Фильтр по несуществующему полю — список полей в `GET /v1/users/fields` | | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `user` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Разбиение по временны́м окнам.** Фильтр по диапазону дат шире 14 дней автоматически разбивается на недельные окна, которые выполняются параллельными волнами — так выборка обходит потолок в 5000 записей на один вызов. В `meta` тогда приходят `autoWindowed: true`, число окон `windowCount` и число волн `batchWaves`. Отключает разбиение параметр `autoWindow: false`. При активном разбиении `offset` больше нуля отклоняется с `UNSTABLE_OFFSET_PAGINATION`. **Семантика `filter[active]: false`.** Возвращает всех сотрудников, а не только деактивированных — Битрикс24 интерпретирует `ACTIVE = "Y"` как «исключить деактивированных», а другие значения как «без фильтра по статусу». Чтобы получить только деактивированных, делайте отдельную фильтрацию на стороне клиента по полю `active`. **Когда использовать search вместо list.** POST-search удобнее для длинных списков значений в фильтре (`{ "id": [1, 5, 12, 27, 99] }`) — query-строка GET-запроса имеет ограничения на длину, а body POST — нет. Для коротких фильтров обе формы эквивалентны. ## Смотрите также - [Список сотрудников](/docs/entities/users/list) - [Поля сотрудника](/docs/entities/users/fields) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Users: Update ## Обновить сотрудника `PATCH /v1/users/:id` Обновляет поля существующего сотрудника. Передавайте только изменяемые поля. Требует прав администратора портала на стороне Битрикс24 — без них вызов отклоняется. ## Поля запроса (body) | Параметр | Тип | Описание | |----------|-----|---------| | `workPosition` | string | Должность | | `departmentId` | number[] | Массив ID отделов. Список: `GET /v1/departments` | | `email` | string | Email — должен оставаться уникальным на портале | | `workPhone` / `personalPhone` / `personalMobile` | string | Телефоны | | `active` | boolean | Реактивировать (`true`) или деактивировать (`false`) — деактивация эквивалентна [`DELETE /v1/users/:id`](/docs/entities/users/delete) | Полный список полей — [Поля сотрудника](/docs/entities/users/fields). Пользовательские (`UF_*`) поля принимаются. ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/users/29" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "workPosition": "Старший менеджер", "departmentId": [1, 47] }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/users/29" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "workPosition": "Старший менеджер", "departmentId": [1, 47] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/users/29', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ workPosition: 'Старший менеджер', departmentId: [1, 47], }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/users/29', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ workPosition: 'Старший менеджер', departmentId: [1, 47], }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Обновлённый объект сотрудника со всеми полями — формат тот же, что у [`GET /v1/users/:id`](/docs/entities/users/get) | ## Пример ответа ```json { "success": true, "data": { "id": 29, "name": "Иван", "lastName": "Петров", "email": "ivan.petrov@example.com", "active": true, "workPosition": "Старший менеджер", "departmentId": [1, 47], "userType": "employee" } } ``` ## Пример ответа при ошибке 403 — обновление отклонено Битрикс24: ```json { "success": false, "error": { "code": "UPDATE_FAILED", "message": "Bitrix24 rejected user.update (result: false)", "hint": "Bitrix24 returns false when the calling user lacks portal admin rights, when a read-only field was touched (isOnline, lastLogin, dateRegister, isAdmin), or when the target user ID does not exist. Verify the webhook/OAuth identity is a portal admin." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_ID` | `:id` не является положительным целым числом | | 400 | `READONLY_FIELD` | В теле запроса передано readonly-поле (`id`, `isOnline`, `isAdmin`, `lastLogin`, `dateRegister`, `lastActivityDate`, `userType`, `timestampX`). Вайбкод отклоняет до вызова Битрикс24 | | 400 | `BITRIX_ERROR` | Битрикс24 отклонил поле — например, `wrong_email` при попытке поставить уже занятый email | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `user` | | 403 | `UPDATE_FAILED` | Битрикс24 вернул `result: false` для запроса на обновление. Чаще всего — у владельца ключа нет прав администратора портала | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Изменение email.** Если новый email уже занят другим сотрудником портала, Битрикс24 вернёт `BITRIX_ERROR: wrong_email`. Перед PATCH — проверка через `GET /v1/users?filter[EMAIL]=новый@example.com`. ## Смотрите также - [Получить сотрудника](/docs/entities/users/get) - [Поля сотрудника](/docs/entities/users/fields) - [Деактивировать сотрудника](/docs/entities/users/delete) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Warehouses: Create ## Создать склад `POST /v1/warehouses` Создаёт новый склад. Поля передаются плоско в корне JSON — без обёртки `fields`. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `title` | string | да | Название склада | | `address` | string | да | Адрес склада | | `active` | string | нет | Активность: `"Y"` / `"N"`. По умолчанию `"Y"` | | `issuingCenter` | string | нет | Пункт выдачи заказов: `"Y"` / `"N"`. По умолчанию `"N"` | | `description` | string | нет | Описание склада | | `phone` | string | нет | Контактный телефон | | `email` | string | нет | Контактная почта | | `schedule` | string | нет | Режим работы — произвольный текст | | `sort` | number | нет | Порядок сортировки. По умолчанию `100` | | `code` | string | нет | Символьный код | | `xmlId` | string | нет | Внешний идентификатор для синхронизации | | `gpsN` | number | нет | Географическая широта | | `gpsS` | number | нет | Географическая долгота | | `userId` | number | нет | Ответственный сотрудник — идентификатор из [`GET /v1/users`](/docs/entities/users) | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/warehouses" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Основной склад", "address": "г. Москва, ул. Складская, 1", "active": "Y" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/warehouses" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Основной склад", "address": "г. Москва, ул. Складская, 1", "active": "Y" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/warehouses', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Основной склад', address: 'г. Москва, ул. Складская, 1', active: 'Y', }), }) const { success, data } = await res.json() console.log('ID склада:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/warehouses', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Основной склад', address: 'г. Москва, ул. Складская, 1', active: 'Y', }), }) const { success, data } = await res.json() ``` ## Поля ответа Возвращается объект созданного склада в поле `data`. | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор склада | | `title` | string | Название склада | | `address` | string | Адрес склада | | `active` | string | Активность: `"Y"` / `"N"` | | `issuingCenter` | string | Признак пункта выдачи заказов: `"Y"` / `"N"` | | `description` | string \| null | Описание склада. `null`, если не задано | | `phone` | string \| null | Контактный телефон. `null`, если не задан | | `email` | string \| null | Контактная почта. `null`, если не задана | | `schedule` | string \| null | Режим работы. `null`, если не задан | | `sort` | number | Порядок сортировки | | `code` | string \| null | Символьный код. `null`, если не задан | | `xmlId` | string \| null | Внешний идентификатор. `null`, если не задан | | `gpsN` | number \| null | Географическая широта. `null`, если не задана | | `gpsS` | number \| null | Географическая долгота. `null`, если не задана | | `imageId` | object \| null | Изображение склада: `{ "id", "url" }` или `null` | | `userId` | number | Ответственный сотрудник | | `modifiedBy` | number | Идентификатор пользователя, изменившего склад последним | | `dateCreate` | datetime | Дата создания | | `dateModify` | datetime | Дата последнего изменения | ## Пример ответа ```json { "success": true, "data": { "id": 25, "title": "Основной склад", "address": "г. Москва, ул. Складская, 1", "active": "Y", "issuingCenter": "N", "description": null, "phone": null, "email": null, "schedule": null, "sort": 100, "code": null, "xmlId": null, "gpsN": null, "gpsS": null, "imageId": null, "userId": 1, "modifiedBy": 1, "dateCreate": "2026-06-02T12:04:24+03:00", "dateModify": "2026-06-02T12:04:24+03:00" } } ``` ## Пример ответа при ошибке 400 — не передано обязательное поле: ```json { "success": false, "error": { "code": "MISSING_PARAMS", "message": "Required: title (string), address (string)" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_PARAMS` | Не передано `title` либо `address` | | 400 | `INVALID_PARAMS` | `title` или `address` не строка | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 422 | `BITRIX_ERROR` | Битрикс24 отклонил создание (например, недопустимое значение поля) | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Значения по умолчанию.** Если не передать `active`, `sort` и `issuingCenter`, склад создаётся со значениями `active: "Y"`, `sort: 100`, `issuingCenter: "N"`. Поля `userId` и `modifiedBy` в ответе заполняются текущим пользователем, под которым выпущен ключ. ## Смотрите также - [Список складов](/docs/entities/warehouses/list) - [Обновить склад](/docs/entities/warehouses/update) - [Удалить склад](/docs/entities/warehouses/delete) - [Справочник сущностей](/docs/entities-index) --- # Warehouses: Delete ## Удалить склад `DELETE /v1/warehouses/:id` Удаляет склад по идентификатору. ## Параметры пути | Параметр | Тип | Описание | |----------|-----|---------| | `id` | number | Идентификатор склада | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/warehouses/1" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/warehouses/1" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/warehouses/1', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) console.log(res.status) // 204 ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/warehouses/1', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) console.log(res.status) // 204 ``` ## Поля ответа При успехе — статус `204 No Content`, тело ответа пустое. ## Пример ответа ``` HTTP/1.1 204 No Content ``` Тело ответа отсутствует. ## Пример ответа при ошибке 422 — склад с таким `id` не существует: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "store does not exist." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `id` не положительное целое | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 422 | `BITRIX_ERROR` | Склад с указанным `id` не существует | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Несуществующий склад — `422`, не `404`.** Удаление склада по неизвестному `id` возвращает `422` с кодом `BITRIX_ERROR`. Повторное удаление уже удалённого склада вернёт ту же ошибку. ## Смотрите также - [Список складов](/docs/entities/warehouses/list) - [Получить склад](/docs/entities/warehouses/get) - [Создать склад](/docs/entities/warehouses/create) - [Справочник сущностей](/docs/entities-index) --- # Warehouses: Fields ## Поля склада `GET /v1/warehouses/fields` Возвращает схему полей склада: для каждого из 19 полей — тип, признак «только для чтения», человеческое название и описание. Полезно для автогенерации кода и подсказок ИИ-агентам. Склады — кастомный роут (без сущностной схемы), поэтому справка полей отдаётся из статической таблицы и **не обращается к Битрикс24** — скоуп `catalog` проверяется, но токены портала не требуются. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/warehouses/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/warehouses/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/warehouses/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Поля склада:', Object.keys(data.fields)) ``` ## Поля ответа `data.fields` — объект, ключ которого — имя поля, а значение — `{ type, readonly, label, description }`. | Поле | Тип | RO | Описание | |------|-----|----|---------| | `id` | number | да | Идентификатор склада | | `title` | string | | Название склада | | `address` | string | | Адрес склада | | `active` | string | | Активность: `"Y"` / `"N"` | | `issuingCenter` | string | | Признак пункта выдачи заказов: `"Y"` / `"N"` | | `description` | string | | Описание склада. `null`, если не задано | | `phone` | string | | Контактный телефон. `null`, если не задан | | `email` | string | | Контактная почта. `null`, если не задана | | `schedule` | string | | Режим работы. `null`, если не задан | | `sort` | number | | Порядок сортировки | | `code` | string | | Символьный код. `null`, если не задан | | `xmlId` | string | | Внешний идентификатор. `null`, если не задан | | `gpsN` | number | | Географическая широта. `null`, если не задана | | `gpsS` | number | | Географическая долгота. `null`, если не задана | | `imageId` | object | да | Изображение склада: `{ id, url }` или `null` | | `userId` | number | | Ответственный сотрудник. `null` у системных складов | | `modifiedBy` | number | да | ID пользователя, изменившего склад последним. `null` у системных складов | | `dateCreate` | datetime | да | Дата создания. `null` у части системных складов | | `dateModify` | datetime | да | Дата последнего изменения | Поля с отметкой RO (`readonly: true`) — `id`, `imageId`, `modifiedBy`, `dateCreate`, `dateModify` — заполняются платформой и не принимаются при создании и обновлении. ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "Идентификатор", "description": "Идентификатор склада." }, "title": { "type": "string", "readonly": false, "label": "Название", "description": "Название склада." }, "active": { "type": "string", "readonly": false, "label": "Активность", "description": "Активность склада: «Y» / «N»." } } } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `TOKEN_MISSING` | API-ключ не передан | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список складов](/docs/entities/warehouses/list) - [Создать склад](/docs/entities/warehouses/create) - [Справочник сущностей](/docs/entities-index) --- # Warehouses: Get ## Получить склад `GET /v1/warehouses/:id` Возвращает один склад по идентификатору со всеми полями. ## Параметры пути | Параметр | Тип | Описание | |----------|-----|---------| | `id` | number | Идентификатор склада | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/warehouses/1" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/warehouses/1" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/warehouses/1', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log(data.title) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/warehouses/1', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект склада — состав полей ниже | ### Поля склада | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор склада | | `title` | string | Название склада | | `address` | string | Адрес склада | | `active` | string | Активность: `"Y"` / `"N"` | | `issuingCenter` | string | Признак пункта выдачи заказов: `"Y"` / `"N"` | | `description` | string \| null | Описание склада. `null`, если не задано | | `phone` | string \| null | Контактный телефон. `null`, если не задан | | `email` | string \| null | Контактная почта. `null`, если не задана | | `schedule` | string \| null | Режим работы. `null`, если не задан | | `sort` | number | Порядок сортировки | | `code` | string \| null | Символьный код. `null`, если не задан | | `xmlId` | string \| null | Внешний идентификатор. `null`, если не задан | | `gpsN` | number \| null | Географическая широта. `null`, если не задана | | `gpsS` | number \| null | Географическая долгота. `null`, если не задана | | `imageId` | object \| null | Изображение склада: `{ "id", "url" }` или `null` | | `userId` | number \| null | Ответственный сотрудник. `null` у системных складов, заполняется при создании через API | | `modifiedBy` | number \| null | ID пользователя, изменившего склад последним. `null` у системных складов, заполняется при создании через API | | `dateCreate` | datetime \| null | Дата создания. `null` у части системных складов (например, маркетплейсов) | | `dateModify` | datetime | Дата последнего изменения | ## Пример ответа ```json { "success": true, "data": { "id": 1, "title": "Основной склад", "address": "г. Москва, ул. Складская, 1", "active": "Y", "issuingCenter": "N", "description": "Центральный склад", "phone": "+7 495 000 00 00", "email": "warehouse@example.com", "schedule": "Пн–Пт 9:00–20:00", "sort": 100, "code": "main", "xmlId": null, "gpsN": 55.751244, "gpsS": 37.618423, "imageId": { "id": 57, "url": "https://cdn.bitrix24.ru/b00000000/catalog/store.png" }, "userId": 1, "modifiedBy": 1, "dateCreate": "2024-01-15T09:00:00+03:00", "dateModify": "2024-06-20T14:30:00+03:00" } } ``` ## Пример ответа при ошибке 422 — склад с таким `id` не существует: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "store does not exist." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `id` не положительное целое | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 422 | `BITRIX_ERROR` | Склад с указанным `id` не существует | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Несуществующий склад — `422`, не `404`.** Запрос склада по неизвестному `id` возвращает `422` с кодом `BITRIX_ERROR`. Перед получением проверяйте наличие склада в [списке складов](/docs/entities/warehouses/list). **Изображение склада.** Поле `imageId` приходит объектом `{ "id", "url" }` со ссылкой на картинку склада либо `null`, если изображение не задано. ## Смотрите также - [Список складов](/docs/entities/warehouses/list) - [Обновить склад](/docs/entities/warehouses/update) - [Остатки склада](/docs/entities/warehouses/stock) - [Справочник сущностей](/docs/entities-index) --- # Warehouses: List ## Список складов `GET /v1/warehouses` Возвращает список складов портала. Постраничный вывод задаётся параметрами `limit` и `offset`. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` ответ автоматически собирается из нескольких страниц Битрикс24. При `limit ≤ 50` лишние записи отсекаются на стороне Vibe (Битрикс24 отдаёт страницу до 50 записей независимо от значения) | | `offset` | number | `0` | Смещение от начала выборки, **построчное**: `offset=1` начинает со второй записи. При `offset ≥ 2500` держите `limit ≤ 500` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/warehouses" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/warehouses" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/warehouses', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Складов: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/warehouses', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив складов — состав полей одного склада ниже | | `meta.total` | number | Общее количество складов на портале | | `meta.hasMore` | boolean | Есть ли записи за пределами текущей страницы (`offset + длина data < total`). Если `true` — увеличьте `limit` (до 5000) либо сдвиньте `offset` | ### Поля склада | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор склада | | `title` | string | Название склада | | `address` | string | Адрес склада | | `active` | string | Активность: `"Y"` / `"N"` | | `issuingCenter` | string | Признак пункта выдачи заказов: `"Y"` / `"N"` | | `description` | string \| null | Описание склада. `null`, если не задано | | `phone` | string \| null | Контактный телефон. `null`, если не задан | | `email` | string \| null | Контактная почта. `null`, если не задана | | `schedule` | string \| null | Режим работы. `null`, если не задан | | `sort` | number | Порядок сортировки | | `code` | string \| null | Символьный код. `null`, если не задан | | `xmlId` | string \| null | Внешний идентификатор. `null`, если не задан | | `gpsN` | number \| null | Географическая широта. `null`, если не задана | | `gpsS` | number \| null | Географическая долгота. `null`, если не задана | | `imageId` | object \| null | Изображение склада: `{ "id", "url" }` или `null` | | `userId` | number \| null | Ответственный сотрудник. `null` у системных складов, заполняется при создании через API | | `modifiedBy` | number \| null | ID пользователя, изменившего склад последним. `null` у системных складов, заполняется при создании через API | | `dateCreate` | datetime \| null | Дата создания. `null` у части системных складов (например, маркетплейсов) | | `dateModify` | datetime | Дата последнего изменения | ## Пример ответа ```json { "success": true, "data": [ { "id": 1, "title": "Основной склад", "address": "г. Москва, ул. Складская, 1", "active": "Y", "issuingCenter": "N", "description": null, "phone": null, "email": null, "schedule": null, "sort": 100, "code": null, "xmlId": null, "gpsN": null, "gpsS": null, "imageId": null, "userId": 1, "modifiedBy": 1, "dateCreate": "2024-01-15T09:00:00+03:00", "dateModify": "2024-06-20T14:30:00+03:00" }, { "id": 2, "title": "Пункт выдачи «Север»", "address": "г. Москва, ул. Полярная, 8", "active": "Y", "issuingCenter": "Y", "description": null, "phone": "+7 495 000 00 00", "email": null, "schedule": "Пн–Пт 10:00–20:00", "sort": 200, "code": "pvz-north", "xmlId": null, "gpsN": 55.85, "gpsS": 37.6, "imageId": null, "userId": 1, "modifiedBy": 1, "dateCreate": "2024-03-10T11:00:00+03:00", "dateModify": "2024-03-10T11:00:00+03:00" } ], "meta": { "total": 2, "hasMore": false } } ``` ## Пример ответа при ошибке 400 — некорректное значение `limit`: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "limit must be a positive integer" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `limit` не положительное целое либо `offset` отрицательный | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Только постраничный вывод.** Список принимает лишь `limit` и `offset`. Фильтрация, сортировка и выборка отдельных полей (`filter`, `sort`, `select`) на этом эндпоинте не поддерживаются — возвращаются все склады портала. Нужный склад отбирайте на стороне клиента по полю из ответа. **Забрать все склады одним запросом.** На портале с числом складов больше 50 укажите `limit` больше реального количества (например, `?limit=5000`) — ответ соберётся из нескольких страниц Битрикс24 и вернёт всё разом. Признак неполного ответа — `meta.hasMore: true` (его же отдаёт ответ по умолчанию `limit=50`, когда складов больше 50). Сравнивать `data.length` с `meta.total` вручную больше не нужно. **`offset` построчный.** Битрикс24 отдаёт склады страницами по 50 и сдвигает выборку только на целую страницу, поэтому Вайбкод запрашивает страницу, накрывающую нужное окно, и отсекает лишние строки с начала. Вам это видно как обычное построчное смещение: `offset=1&limit=3` вернёт вторую, третью и четвёртую записи. **Пустой `data` при `hasMore: true` — останавливайте обход.** Такое бывает, когда запрошенное окно не покрывается одной страницей Битрикс24: в `meta.warnings` придёт `OFFSET_BEYOND_FETCHED_PAGE`. Увеличьте `limit`, чтобы окно уместилось в выборку. ## Смотрите также - [Поля склада](/docs/entities/warehouses/fields) - [Получить склад](/docs/entities/warehouses/get) - [Создать склад](/docs/entities/warehouses/create) - [Остатки склада](/docs/entities/warehouses/stock) - [Справочник сущностей](/docs/entities-index) --- # Warehouses: Stock ## Остатки склада `GET /v1/warehouses/:id/stock` Возвращает остатки товаров на складе — по строке на каждый товар, который числится на этом складе. Только для чтения: изменить количество через этот эндпоинт нельзя. ## Параметры пути | Параметр | Тип | Описание | |----------|-----|---------| | `id` | number | Идентификатор склада | ## Параметры запроса | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `limit` | number | `50` | Количество строк (до 5000). При `limit > 50` ответ автоматически собирается из нескольких страниц Битрикс24 | | `offset` | number | `0` | Смещение от начала выборки, **построчное**: `offset=1` начинает со второй строки. Битрикс24 сдвигает выборку только на целую страницу по 50, поэтому Вайбкод запрашивает накрывающую страницу и отсекает лишние строки с начала. Если запрошенное окно не покрывается одной страницей, `data` придёт пустым при `hasMore: true`, а в `meta.warnings` — `OFFSET_BEYOND_FETCHED_PAGE`: увеличьте `limit` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/warehouses/1/stock" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/warehouses/1/stock" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/warehouses/1/stock', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/warehouses/1/stock', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Строки остатков на складе | | `data[].id` | number | Идентификатор строки остатка | | `data[].productId` | number | Идентификатор товара — см. [Товары каталога](/docs/entities/catalog-products) | | `data[].storeId` | number | Идентификатор склада | | `data[].amount` | number | Количество на складе. Может быть `null` — трактуйте как `0` | | `data[].quantityReserved` | number | Зарезервированное количество. Может быть `null` — трактуйте как `0` | | `meta.total` | number | Количество строк остатков на складе | | `meta.hasMore` | boolean | Есть ли строки за пределами текущей страницы (`offset + длина data < total`). Если `true` — увеличьте `limit` (до 5000) либо сдвиньте `offset` | ## Пример ответа ```json { "success": true, "data": [ { "id": 3, "productId": 200, "storeId": 1, "amount": 15, "quantityReserved": 30 }, { "id": 5, "productId": 201, "storeId": 1, "amount": 54, "quantityReserved": null }, { "id": 9, "productId": 202, "storeId": 1, "amount": null, "quantityReserved": null } ], "meta": { "total": 3, "hasMore": false } } ``` ## Пример ответа при ошибке 400 — некорректный `id` склада: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "id must be a positive integer" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `id`, `limit` или `offset` заданы некорректно | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Пустой склад.** Если на складе нет товаров с остатками, `data` — пустой массив, `meta.total` — `0`. ## Смотрите также - [Сводные остатки по товарам](/docs/entities/warehouses/stock-totals) - [Получить склад](/docs/entities/warehouses/get) - [Товары каталога](/docs/entities/catalog-products) - [Справочник сущностей](/docs/entities-index) --- # Warehouses: Stock Totals ## Сводные остатки по товарам `GET /v1/warehouses/stock/totals` Складывает остатки каждого товара по всем складам портала. Для товара возвращает суммарное количество, суммарный резерв и список складов, где товар представлен. Только для чтения. ## Параметры запроса | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `productId` | number | — | Свести остатки только по одному товару | | `limit` | number | — | Сколько товаров вернуть в ответе | | `offset` | number | `0` | Смещение по списку товаров | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/warehouses/stock/totals?productId=200" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/warehouses/stock/totals?productId=200" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/warehouses/stock/totals', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/warehouses/stock/totals', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Сводка по товарам | | `data[].productId` | number | Идентификатор товара — см. [Товары каталога](/docs/entities/catalog-products) | | `data[].amount` | number | Суммарное количество товара по всем складам | | `data[].quantityReserved` | number | Суммарный резерв товара по всем складам | | `data[].storeIds` | array | Идентификаторы складов, где товар представлен | | `meta.total` | number | Количество товаров в ответе | | `meta.rawTotal` | number | Количество исходных строк остатков, обработанных при агрегации | | `meta.truncated` | boolean | `true`, если исходных строк остатков больше 5000 и часть не вошла в свод | ## Пример ответа ```json { "success": true, "data": [ { "productId": 200, "amount": 25, "quantityReserved": 30, "storeIds": [1, 2, 5] } ], "meta": { "total": 1, "truncated": false, "rawTotal": 3 } } ``` ## Пример ответа при ошибке 400 — некорректный `productId`: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "productId must be a positive integer" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `productId`, `limit` или `offset` заданы некорректно | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Суммирование по товару.** Количество и резерв одного товара суммируются по всем складам, где он представлен. Список таких складов — в `storeIds`. Если на отдельном складе количество не задано, при суммировании оно считается нулём. **Ограничение свода.** Свод считается по первым 5000 строкам остатков. Если строк больше, `meta.truncated` равно `true`, и свод получается неполным. В этом случае сузьте выборку параметром `productId`. ## Смотрите также - [Остатки склада](/docs/entities/warehouses/stock) - [Список складов](/docs/entities/warehouses/list) - [Товары каталога](/docs/entities/catalog-products) - [Справочник сущностей](/docs/entities-index) --- # Warehouses: Update ## Обновить склад `PATCH /v1/warehouses/:id` Обновляет склад. Передавайте только изменяемые поля — плоско в корне JSON. Переданные поля заменяют текущие значения, остальные остаются прежними. ## Параметры пути | Параметр | Тип | Описание | |----------|-----|---------| | `id` | number | Идентификатор склада | ## Поля запроса (body) Любое подмножество изменяемых полей склада — все необязательны. | Параметр | Тип | Описание | |----------|-----|---------| | `title` | string | Название склада | | `address` | string | Адрес склада | | `active` | string | Активность: `"Y"` / `"N"` | | `issuingCenter` | string | Пункт выдачи заказов: `"Y"` / `"N"` | | `description` | string | Описание склада | | `phone` | string | Контактный телефон | | `email` | string | Контактная почта | | `schedule` | string | Режим работы | | `sort` | number | Порядок сортировки | | `code` | string | Символьный код | | `xmlId` | string | Внешний идентификатор | | `gpsN` | number | Географическая широта | | `gpsS` | number | Географическая долгота | | `userId` | number | Ответственный сотрудник | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/warehouses/1" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Центральный склад", "sort": 50 }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/warehouses/1" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Центральный склад", "sort": 50 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/warehouses/1', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Центральный склад', sort: 50, }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/warehouses/1', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Центральный склад', sort: 50, }), }) const { success, data } = await res.json() ``` ## Поля ответа Возвращается объект обновлённого склада в поле `data`. | Поле | Тип | Описание | |------|-----|---------| | `id` | number | Идентификатор склада | | `title` | string | Название склада | | `address` | string | Адрес склада | | `active` | string | Активность: `"Y"` / `"N"` | | `issuingCenter` | string | Признак пункта выдачи заказов: `"Y"` / `"N"` | | `description` | string \| null | Описание склада. `null`, если не задано | | `phone` | string \| null | Контактный телефон. `null`, если не задан | | `email` | string \| null | Контактная почта. `null`, если не задана | | `schedule` | string \| null | Режим работы. `null`, если не задан | | `sort` | number | Порядок сортировки | | `code` | string \| null | Символьный код. `null`, если не задан | | `xmlId` | string \| null | Внешний идентификатор. `null`, если не задан | | `gpsN` | number \| null | Географическая широта. `null`, если не задана | | `gpsS` | number \| null | Географическая долгота. `null`, если не задана | | `imageId` | object \| null | Изображение склада: `{ "id", "url" }` или `null` | | `userId` | number \| null | Ответственный сотрудник. `null` у системных складов | | `modifiedBy` | number | Идентификатор пользователя, изменившего склад последним. После обновления — тот, под кем выпущен ключ | | `dateCreate` | datetime \| null | Дата создания. `null` у части системных складов, например маркетплейсов | | `dateModify` | datetime | Дата последнего изменения | ## Пример ответа ```json { "success": true, "data": { "id": 1, "title": "Центральный склад", "address": "г. Москва, ул. Складская, 1", "active": "Y", "issuingCenter": "N", "description": "Центральный склад", "phone": "+7 495 000 00 00", "email": "warehouse@example.com", "schedule": "Пн–Пт 9:00–20:00", "sort": 50, "code": "main", "xmlId": null, "gpsN": 55.751244, "gpsS": 37.618423, "imageId": null, "userId": 1, "modifiedBy": 1, "dateCreate": "2024-01-15T09:00:00+03:00", "dateModify": "2026-06-02T12:04:25+03:00" } } ``` ## Пример ответа при ошибке 422 — склад с таким `id` не существует: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "store does not exist." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `id` не положительное целое | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` | | 422 | `BITRIX_ERROR` | Склад с указанным `id` не существует | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Несуществующий склад — `422`, не `404`.** Обновление склада по неизвестному `id` возвращает `422` с кодом `BITRIX_ERROR`. Перед обновлением проверяйте наличие склада в [списке складов](/docs/entities/warehouses/list). ## Смотрите также - [Получить склад](/docs/entities/warehouses/get) - [Создать склад](/docs/entities/warehouses/create) - [Удалить склад](/docs/entities/warehouses/delete) - [Справочник сущностей](/docs/entities-index) --- # Workgroups: Aggregate ## Агрегация рабочих групп `POST /v1/workgroups/aggregate` Подсчёт количества рабочих групп, числовые агрегаты и группировка по фильтру. Без тела запроса возвращает общее количество групп одним вызовом, без выгрузки записей. **Стандартные поля:** - `membersCount` — число участников (числовое агрегирование имеет смысл) - `active` — признак активности (для `groupBy`) - `isProject` — признак проекта (для `groupBy`) - `ownerId` — владелец группы (для `groupBy`) ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций. Числовая функция: `{ "field": "membersCount", "function": "sum" }`. Функция подсчёта: `{ "field": "*", "function": "count" }`. Функции: `count`, `sum`, `avg`, `min`, `max`. Без массива возвращается только `count` | | `filter` | object | нет | Фильтрация по полям `GET /v1/workgroups/fields`. [Синтаксис фильтрации](/docs/filtering) | | `groupBy` | string \| string[] | нет | Поле или массив полей для группировки (максимум 5). Допустимые значения — из списка выше | | `groupOrderBy` | array | нет | Сортировка групп: `[{ "field": "membersCount:sum", "direction": "desc" }]` | | `groupLimit` | number | нет | Ограничение количества возвращаемых групп (1-1000) | Функции `sum`, `avg`, `min`, `max` требуют имя числового поля, `count` требует поле `"*"`. Осмысленная числовая агрегация по рабочим группам — по полю `membersCount`, числу участников. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/workgroups/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "membersCount", "function": "sum" }, { "field": "membersCount", "function": "avg" }, { "field": "membersCount", "function": "min" }, { "field": "membersCount", "function": "max" } ] }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/workgroups/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "aggregate": [ { "field": "membersCount", "function": "sum" }, { "field": "membersCount", "function": "avg" }, { "field": "membersCount", "function": "min" }, { "field": "membersCount", "function": "max" } ] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/workgroups/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [ { field: 'membersCount', function: 'sum' }, { field: 'membersCount', function: 'avg' }, { field: 'membersCount', function: 'min' }, { field: 'membersCount', function: 'max' }, ], }), }) const { success, data } = await res.json() console.log('Всего участников во всех группах:', data.aggregates.membersCount.sum) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/workgroups/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ aggregate: [ { field: 'membersCount', function: 'sum' }, { field: 'membersCount', function: 'avg' }, { field: 'membersCount', function: 'min' }, { field: 'membersCount', function: 'max' }, ], }), }) const { success, data } = await res.json() ``` ## Другие сценарии Общее количество групп в портале, самый быстрый запрос без выгрузки записей: ```json {} ``` Средний размер группы среди проектов: ```json { "filter": { "isProject": true }, "aggregate": [{ "field": "membersCount", "function": "avg" }] } ``` Разбивка количества групп по признаку активности: ```json { "groupBy": "active" } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Количество групп под фильтр | | `data.aggregates` | object | Результаты числовых агрегаций по полям. Пустой объект, если массив `aggregate` не передан | | `data.groups` | array | Группы (только при `groupBy`). Каждый элемент: поля группировки, `count` и `aggregates` | | `data.meta.totalRecords` | number | Общее количество групп под фильтр | | `data.meta.recordsProcessed` | number | Сколько записей обработано: `0` для чистого `count`, число записей при числовых функциях и при `groupBy` | | `data.meta.truncated` | boolean | `true`, если под фильтр попало больше 5000 записей и результат посчитан по первым 5000. Для запроса только `count` всегда `false` | | `data.meta.groupTotal` | number | Количество групп в разбивке. Приходит только при `groupBy` | | `data.meta.groupsTruncated` | boolean | Признак того, что часть групп не попала в ответ. Приходит только при `groupBy` | ## Пример ответа Числовые агрегаты по полю `membersCount`: ```json { "success": true, "data": { "count": 33, "aggregates": { "membersCount": { "sum": 65, "avg": 1.9696969696969697, "min": 0, "max": 7 } }, "meta": { "totalRecords": 33, "recordsProcessed": 33, "truncated": false } } } ``` Группировка, тело `{ "groupBy": "active" }`: ```json { "success": true, "data": { "count": 33, "aggregates": {}, "groups": [ { "active": true, "count": 33, "aggregates": {} } ], "meta": { "totalRecords": 33, "recordsProcessed": 33, "truncated": false, "groupTotal": 1, "groupsTruncated": false } } } ``` Запрос количества, тело `{}`, записи не выгружаются и `recordsProcessed` равен `0`: ```json { "success": true, "data": { "count": 33, "aggregates": {}, "meta": { "totalRecords": 33, "recordsProcessed": 0, "truncated": false } } } ``` Без `groupBy` поле `data.groups` в ответе отсутствует. ## Пример ответа при ошибке 400 — в `groupBy` передано поле, по которому группировка недоступна. Сообщение содержит список допустимых полей: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "groupBy field 'name' is not aggregatable on this entity. Available: membersCount, active, isProject, ownerId." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Некорректное имя функции, числовая функция по нечисловому полю, `groupBy` по недопустимому полю или больше 5 полей в `groupBy` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sonet_group` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`count` против числовых функций и группировки.** `count` считается одним вызовом на любом объёме — записи не выгружаются, `recordsProcessed` равен `0`, а результат совпадает с полем `total` из [списка рабочих групп](./list.md). Функции `sum`, `avg`, `min`, `max` и группировка через `groupBy` подгружают записи постранично и считаются на стороне платформы, поэтому `recordsProcessed` равен числу обработанных групп. При более чем 5000 записей под фильтр `meta.truncated` становится `true`, а результат считается по первым 5000 — для точного результата на больших выборках сузьте фильтр. ## Смотрите также - [Список рабочих групп](/docs/entities/workgroups/list) - [Поиск рабочих групп](/docs/entities/workgroups/search) - [Синтаксис фильтрации](/docs/filtering) --- # Workgroups: Create ## Создать рабочую группу `POST /v1/workgroups` Создаёт новую рабочую группу на портале. Возвращает полный объект созданной группы. Обязательное поле одно — `name`; остальные параметры опциональны. ## Поля запроса (body) | Поле | Тип | Обяз. | По умолч. | Описание | |------|-----|:-----:|-----------|---------| | `name` | string | ★ | — | Название рабочей группы | | `description` | string | нет | — | Описание | | `ownerId` | number | нет | текущий пользователь ключа | Идентификатор владельца группы. Список: `GET /v1/users` | | `subjectId` | number | нет | тема портала по умолчанию | Идентификатор темы | | `active` | boolean | нет | `true` | Активна ли группа | | `visible` | boolean | нет | `true` | Видна ли в общих списках | | `opened` | boolean | нет | `false` | Открыта ли для вступления без приглашения | | `archived` | boolean | нет | `false` | Поместить в архив сразу при создании | | `isProject` | boolean | нет | `false` | Создать как проект | | `isExtranet` | boolean | нет | `false` | Группа экстранета | | `keywords` | string | нет | — | Ключевые слова для поиска | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/workgroups" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Маркетинг 2026", "description": "Координация рекламных кампаний", "opened": true, "isProject": false }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/workgroups" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Маркетинг 2026", "description": "Координация рекламных кампаний", "opened": true, "isProject": false }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/workgroups', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Маркетинг 2026', description: 'Координация рекламных кампаний', opened: true, isProject: false, }), }) const { success, data } = await res.json() console.log('Workgroup ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/workgroups', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Маркетинг 2026', description: 'Координация рекламных кампаний', opened: true, isProject: false, }), }) const { success, data } = await res.json() ``` ## Поля ответа Возвращается полный объект созданной рабочей группы. | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект созданной рабочей группы. Полное описание полей — [Получить рабочую группу](./get.md) или [Поля рабочей группы](./fields.md) | ## Пример ответа ```json { "success": true, "data": { "id": 173, "siteId": "s1", "name": "Маркетинг 2026", "description": "Координация рекламных кампаний", "dateCreate": "2026-05-26T05:56:40.000Z", "dateUpdate": "2026-05-26T05:56:40.000Z", "active": true, "visible": true, "opened": true, "archived": false, "subjectId": 1, "ownerId": 1, "keywords": null, "membersCount": 1, "dateActivity": "2026-05-26T05:56:40.000Z", "subjectName": "Рабочие группы", "isProject": false, "isExtranet": false } } ``` ## Пример ответа при ошибке 422 — не передано обязательное поле `name`: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Не указано название" } } ``` ## Ошибки | HTTP | `error.code` | Описание | |------|--------------|---------| | 422 | `BITRIX_ERROR` | Битрикс24 отказал в создании группы — текст причины в `error.message`. Типичная причина: отсутствует обязательное поле `name` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Переданный ключ не распознан | | 403 | `SCOPE_DENIED` | У ключа нет скоупа `sonet_group` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список рабочих групп](./list.md) - [Получить рабочую группу](./get.md) - [Обновить рабочую группу](./update.md) - [Поля рабочей группы](./fields.md) --- # Workgroups: Delete ## Удалить рабочую группу `DELETE /v1/workgroups/:id` Удаляет рабочую группу и все связанные с ней данные. Операция необратимая. ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `id` (path) | number | ★ да | — | Идентификатор рабочей группы. Список: [`GET /v1/workgroups`](./list.md) | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/workgroups/85" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/workgroups/85" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/workgroups/85', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) if (res.status === 204) { console.log('Рабочая группа удалена') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/workgroups/85', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if (res.status === 204) { console.log('Рабочая группа удалена') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — успех проверяется по статусу. ## Пример ответа ```http HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 422 — попытка удалить несуществующую группу: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Socialnetwork group not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Битрикс24 отказал в удалении. Типичные причины: группа не существует, нет прав на удаление | | 401 | `MISSING_API_KEY` | Не передан `X-Api-Key` | | 401 | `INVALID_API_KEY` | Передан некорректный ключ | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `sonet_group` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - Для временного скрытия группы без потери данных используйте [`PATCH /v1/workgroups/:id`](./update.md) с `archived: true` — группа перестанет показываться в активных списках, но останется доступной для восстановления. - Сообщение `Socialnetwork group not found` возвращается и при отсутствии группы, и при отсутствии прав на удаление — точную причину по ответу определить нельзя. ## Смотрите также - [Список рабочих групп](./list.md) - [Получить рабочую группу](./get.md) - [Обновить рабочую группу](./update.md) --- # Workgroups: Fields ## Поля рабочей группы `GET /v1/workgroups/fields` Возвращает схему полей рабочей группы и список операций, доступных в пакетных запросах. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/workgroups/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/workgroups/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/workgroups/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Полей:', Object.keys(data.fields).length) console.log('Доступные batch-операции:', data.batch) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/workgroups/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.fields` | object | Объект схемы полей рабочей группы | | `data.fields.<имя>` | object | Описание одного поля | | `data.fields.<имя>.type` | string | Тип значения: `number`, `string`, `boolean` или `datetime` | | `data.fields.<имя>.readonly` | boolean | Доступно ли поле для записи через `POST` / `PATCH` | | `data.batch` | array | Список операций сущности, доступных в [`POST /v1/batch`](/docs/batch): `create`, `update`, `delete` | ### Поля рабочей группы | Поле | Тип | Только чтение | Описание | |------|-----|:--:|---------| | `id` | number | да | Идентификатор рабочей группы | | `name` | string | | Название | | `description` | string | | Описание | | `active` | boolean | | Активна ли группа | | `visible` | boolean | | Видна ли в общих списках | | `opened` | boolean | | Открыта ли для вступления без приглашения | | `ownerId` | number | | Владелец (ответственный). Список: [`GET /v1/users`](/docs/entities/users) | | `subjectId` | number | | Идентификатор темы | | `subjectName` | string | да | Название темы | | `membersCount` | number | да | Количество участников | | `dateCreate` | datetime | да | Дата создания | | `dateUpdate` | datetime | да | Дата последнего обновления | | `dateActivity` | datetime | да | Дата последней активности | | `archived` | boolean | | Помещена ли в архив | | `isProject` | boolean | | Является ли проектом с задачами и сроками | | `isExtranet` | boolean | | Экстранет-группа | | `keywords` | string | | Ключевые слова | | `siteId` | string | да | Идентификатор сайта портала | | `imageUrl` | string | да | URL аватара группы | ## Пример ответа ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "ID", "description": "Идентификатор рабочей группы." }, "name": { "type": "string", "readonly": false, "label": "Название", "description": "Название рабочей группы." }, "description": { "type": "string", "readonly": false, "label": "Описание", "description": "Текстовое описание рабочей группы." }, "active": { "type": "boolean", "readonly": false, "label": "Активна", "description": "Признак того, что группа активна." }, "visible": { "type": "boolean", "readonly": false, "label": "Видна в списках", "description": "Признак того, что группа отображается в общих списках." }, "opened": { "type": "boolean", "readonly": false, "label": "Открытая группа", "description": "Признак того, что вступление в группу возможно без приглашения." }, "ownerId": { "type": "number", "readonly": false, "label": "Владелец", "description": "Идентификатор пользователя, ответственного за группу." }, "subjectId": { "type": "number", "readonly": false, "label": "ID темы", "description": "Идентификатор темы (направления деятельности) рабочей группы." }, "subjectName": { "type": "string", "readonly": true, "label": "Название темы", "description": "Название темы, к которой относится рабочая группа." }, "membersCount": { "type": "number", "readonly": true, "label": "Число участников", "description": "Число участников рабочей группы." }, "dateCreate": { "type": "datetime", "readonly": true, "label": "Дата создания", "description": "Дата и время создания рабочей группы." }, "dateUpdate": { "type": "datetime", "readonly": true, "label": "Дата обновления", "description": "Дата и время последнего обновления рабочей группы." }, "dateActivity": { "type": "datetime", "readonly": true, "label": "Дата активности", "description": "Дата и время последней активности в рабочей группе." }, "archived": { "type": "boolean", "readonly": false, "label": "В архиве", "description": "Признак того, что группа помещена в архив." }, "isProject": { "type": "boolean", "readonly": false, "label": "Проект", "description": "Признак того, что группа является проектом с задачами и сроками." }, "isExtranet": { "type": "boolean", "readonly": false, "label": "Экстранет-группа", "description": "Признак того, что группа относится к экстранету." }, "keywords": { "type": "string", "readonly": false, "label": "Ключевые слова", "description": "Ключевые слова, связанные с рабочей группой." }, "siteId": { "type": "string", "readonly": true, "label": "ID сайта", "description": "Идентификатор сайта портала, к которому относится группа." }, "imageUrl": { "type": "string", "readonly": true, "label": "URL аватара", "description": "Ссылка на изображение аватара рабочей группы." } }, "batch": ["create", "update", "delete"] } } ``` ## Пример ответа при ошибке 401 — нет ключа авторизации: ```json { "success": false, "error": { "code": "MISSING_API_KEY", "message": "API key is required" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Передан неверный ключ | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sonet_group` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - Список полей не зависит от прав пользователя ключа — возвращается полная схема сущности. - Кроме операций, перечисленных в `data.batch`, в [`POST /v1/batch`](/docs/batch) для рабочих групп можно вызывать `get`, `list` и `fields`. ## Смотрите также - [Список рабочих групп](./list.md) - [Создать рабочую группу](./create.md) - [Обновить рабочую группу](./update.md) - [Batch](/docs/batch) - [Entity API](/docs/entity-api) --- # Workgroups: Get ## Получить рабочую группу `GET /v1/workgroups/:id` Возвращает рабочую группу по идентификатору со всеми её полями. ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `id` (path) | number | ★ да | — | Идентификатор рабочей группы. Список: [`GET /v1/workgroups`](./list.md) | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/workgroups/85" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/workgroups/85" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/workgroups/85', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Группа:', data.name, '— участников:', data.membersCount) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/workgroups/85', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Идентификатор рабочей группы (только чтение) | | `data.name` | string | Название | | `data.description` | string \| null | Описание | | `data.active` | boolean | Активна ли группа | | `data.visible` | boolean | Видна ли группа в общих списках | | `data.opened` | boolean | Открыта ли для вступления без приглашения | | `data.ownerId` | number | Идентификатор владельца (ответственного). Список: [`GET /v1/users`](/docs/entities/users) | | `data.subjectId` | number | Идентификатор темы | | `data.subjectName` | string | Название темы (только чтение) | | `data.membersCount` | number | Количество участников (только чтение) | | `data.dateCreate` | string | Дата создания, ISO 8601 (только чтение) | | `data.dateUpdate` | string | Дата последнего обновления, ISO 8601 (только чтение) | | `data.dateActivity` | string | Дата последней активности, ISO 8601 (только чтение) | | `data.archived` | boolean | Помещена ли в архив | | `data.isProject` | boolean | Является ли проектом с задачами и сроками | | `data.isExtranet` | boolean | Группа экстранета — с доступом для внешних пользователей | | `data.keywords` | string \| null | Ключевые слова | | `data.siteId` | string | Идентификатор сайта портала, для основного сайта — `s1` (только чтение) | | `data.imageUrl` | string \| null | URL аватара группы (только чтение) | ## Пример ответа ```json { "success": true, "data": { "id": 85, "siteId": "s1", "name": "Команда разработки нового продукта", "description": "Внутренний проект инфраструктуры", "dateCreate": "2026-03-20T06:45:10.000Z", "dateUpdate": "2026-03-20T06:45:10.000Z", "active": true, "visible": true, "opened": false, "archived": false, "subjectId": 1, "ownerId": 1271, "keywords": null, "membersCount": 2, "dateActivity": "2026-03-20T06:45:10.000Z", "subjectName": "Рабочие группы", "isProject": true, "isExtranet": false, "imageUrl": null } } ``` ## Пример ответа при ошибке 404 — рабочая группа с таким id не существует: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "workgroup 999999 not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 404 | `ENTITY_NOT_FOUND` | Рабочая группа с указанным `id` не найдена | | 401 | `MISSING_API_KEY` | Не передан `X-Api-Key` | | 401 | `INVALID_API_KEY` | Передан некорректный ключ | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `sonet_group` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - Нечисловой `id` (например `abc`) возвращает `404 ENTITY_NOT_FOUND`, а не `400` — учитывайте это при обработке ошибок валидации на клиенте. - Чтобы сменить тему рабочей группы, передавайте числовой `subjectId` в [`PATCH /v1/workgroups/:id`](./update.md). Поле `subjectName` доступно только для чтения — попытка передать его в теле PATCH вернёт `400 READONLY_FIELD`. ## Смотрите также - [Список рабочих групп](./list.md) - [Создать рабочую группу](./create.md) - [Обновить рабочую группу](./update.md) - [Удалить рабочую группу](./delete.md) - [Поля рабочей группы](./fields.md) --- # Workgroups: List ## Список рабочих групп `GET /v1/workgroups` Возвращает список рабочих групп портала с поддержкой фильтрации, сортировки и автоматической пагинации. ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `filter` (query) | object | нет | — | Фильтрация по полям [GET /v1/workgroups/fields](./fields.md).
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[archived]=N` | | `select` (query) | array | нет | — | Список полей в ответе. Имена — из [GET /v1/workgroups/fields](./fields.md). | | `sort` (query) | object | нет | — | Сортировка: `sort[<поле>]=ASC\|DESC`. Пример: `?sort[dateCreate]=DESC`. | | `limit` (query) | number | нет | `50` | Максимум записей в ответе. Допустимо до 5000. | | `offset` (query) | number | нет | `0` | Смещение от начала выборки. | Для `limit > 50` Вайбкод автоматически пагинирует запрос на стороне сервера. Максимум — 5000 записей за вызов. Если под фильтр попадает больше — `meta.hasMore` придёт `true`. ### Получить только проекты В одной коллекции хранятся и рабочие группы, и проекты. Поле `isProject` различает их: `true` — проект, `false` — обычная рабочая группа. Для выборки проектов передавайте `filter[isProject]=Y`. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/workgroups?limit=3" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/workgroups?limit=3" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/workgroups?limit=3', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} рабочих групп`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/workgroups?limit=3', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив рабочих групп (все поля — см. [Поля рабочей группы](./fields.md)) | | `meta.total` | number | Общее количество записей, соответствующих фильтру | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | ## Пример ответа ```json { "success": true, "data": [ { "id": 85, "siteId": "s1", "name": "Маркетинг 2026", "description": null, "dateCreate": "2026-03-20T06:45:10.000Z", "dateUpdate": "2026-03-20T06:45:10.000Z", "active": true, "visible": true, "opened": false, "archived": false, "subjectId": 1, "ownerId": 1271, "keywords": null, "membersCount": 2, "dateActivity": "2026-03-20T06:45:10.000Z", "subjectName": "Рабочие группы", "isProject": true, "isExtranet": false }, { "id": 83, "siteId": "s1", "name": "Команда разработки нового продукта", "description": null, "dateCreate": "2026-03-20T06:41:07.000Z", "dateUpdate": "2026-03-20T06:41:07.000Z", "active": true, "visible": true, "opened": false, "archived": false, "subjectId": 1, "ownerId": 1269, "keywords": null, "membersCount": 1, "dateActivity": "2026-03-20T06:41:07.000Z", "subjectName": "Рабочие группы", "isProject": true, "imageUrl": "https://cdn-ru.bitrix24.ru/example/disk/avatar.jpg", "isExtranet": false }, { "id": 81, "siteId": "s1", "name": "Запуск регионального офиса", "description": null, "dateCreate": "2026-03-20T06:29:07.000Z", "dateUpdate": "2026-03-20T06:29:07.000Z", "active": true, "visible": true, "opened": false, "archived": false, "subjectId": 1, "ownerId": 1271, "keywords": null, "membersCount": 1, "dateActivity": "2026-03-20T06:29:07.000Z", "subjectName": "Рабочие группы", "isProject": true, "isExtranet": false } ], "meta": { "total": 33, "hasMore": true } } ``` ## Пример ответа при ошибке 401 — нет ключа авторизации: ```json { "success": false, "error": { "code": "MISSING_API_KEY", "message": "API key required. Pass via X-Api-Key header." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Переданный ключ не распознан | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `sonet_group` | | 429 | `RATE_LIMITED` | Превышен лимит запросов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Логические поля в фильтре принимают `Y` / `N`.** В ответе те же поля приходят как `true` / `false`, но при фильтрации используйте `filter[active]=Y` / `filter[archived]=N`. Значения `true` / `false` в фильтре не дадут совпадений и не вызовут ошибку. **Префикс `%` в имени поля — поиск по подстроке.** `?filter[%name]=Маркетинг` найдёт все группы, в названии которых встречается «Маркетинг». Без префикса фильтр требует точного совпадения. **`limit = 0` не является размером страницы** — параметр отбрасывается, применяется значение по умолчанию (50), а в ответ добавляется предупреждение `LIMIT_ZERO_IGNORED` в `meta.warnings`. Чтобы прочитать всю коллекцию, передайте явный `limit` (до 5000). Для пустой выборки используйте фильтр, который заведомо ничего не находит. ## Смотрите также - [Поля рабочей группы](./fields.md) - [Синтаксис фильтрации](/docs/filtering) - [Entity API](/docs/entity-api) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Workgroups: Search ## Поиск рабочих групп `POST /v1/workgroups/search` Возвращает список рабочих групп по заданным фильтрам. Тот же контракт, что [GET /v1/workgroups](./list.md), но условия передаются в теле запроса — подходит для длинных фильтров и нелатинских значений. ## Поля запроса (body) | Поле | Тип | Описание | |------|-----|---------| | `filter` | object | Условия фильтрации. Список полей: [GET /v1/workgroups/fields](./fields.md). Синтаксис: [Фильтрация](/docs/filtering). | | `select` | array | Список полей в ответе. Имена — из [GET /v1/workgroups/fields](./fields.md). | | `sort` | object | Сортировка: `{"<поле>": "ASC"\|"DESC"}`. | | `limit` | number | Максимум записей. По умолчанию 50, максимум 5000. | | `offset` | number | Смещение от начала выборки. По умолчанию 0. Вместе с фильтром по диапазону дат шире 14 дней отклоняется — см. `UNSTABLE_OFFSET_PAGINATION` в разделе «Ошибки». | | `autoWindow` | boolean | Разбивать выборку по недельным окнам при фильтре по диапазону дат шире 14 дней. По умолчанию `true`. `false` отключает разбиение | Для `limit > 50` Вайбкод автоматически пагинирует запрос на стороне сервера. Максимум — 5000 записей за вызов. Если под фильтр попадает больше — `meta.hasMore` придёт `true`. ### Получить только проекты В одной коллекции хранятся и рабочие группы, и проекты. Поле `isProject` различает их: `true` — проект, `false` — обычная рабочая группа. Для выборки проектов передавайте `"filter": { "isProject": "Y" }`. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/workgroups/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "%name": "Маркетинг", "archived": "N" }, "select": ["id", "name", "ownerId", "membersCount"], "sort": { "dateCreate": "DESC" }, "limit": 5 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/workgroups/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "%name": "Маркетинг", "archived": "N" }, "select": ["id", "name", "ownerId", "membersCount"], "sort": { "dateCreate": "DESC" }, "limit": 5 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/workgroups/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { '%name': 'Маркетинг', archived: 'N' }, select: ['id', 'name', 'ownerId', 'membersCount'], sort: { dateCreate: 'DESC' }, limit: 5, }), }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} рабочих групп`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/workgroups/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { '%name': 'Маркетинг', archived: 'N' }, select: ['id', 'name', 'ownerId', 'membersCount'], sort: { dateCreate: 'DESC' }, limit: 5, }), }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив рабочих групп (все поля — см. [Поля рабочей группы](./fields.md)) | | `meta.total` | number | Сколько записей подошло под фильтр | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | | `meta.durationMs` | number | Длительность запроса в миллисекундах | | `meta.autoWindowed` | boolean | `true`, если выборка была разбита по временны́м окнам | | `meta.windowCount` | number | Число окон. Приходит при `autoWindowed: true` | | `meta.batchWaves` | number | Число волн параллельных запросов. Приходит при `autoWindowed: true` | Поля `meta` лежат рядом с `data`, а не внутри него. Обходить страницы нужно по `meta.hasMore`: длина `data`, равная `limit`, последней страницы не исключает. ## Пример ответа ```json { "success": true, "data": [ { "id": 85, "name": "Маркетинг 2026", "ownerId": 1271, "membersCount": 2, "dateCreate": "2026-03-20T06:45:10.000Z" }, { "id": 83, "name": "Команда разработки нового продукта", "ownerId": 1269, "membersCount": 1, "dateCreate": "2026-03-20T06:41:07.000Z" }, { "id": 81, "name": "Запуск регионального офиса", "ownerId": 1271, "membersCount": 1, "dateCreate": "2026-03-20T06:29:07.000Z" } ], "meta": { "total": 3, "hasMore": false } } ``` С фильтром по диапазону дат шире 14 дней в `meta` дополнительно приходят `autoWindowed`, `windowCount` и `batchWaves`: ```json { "success": true, "data": [ /* ... */ ], "meta": { "total": 29, "hasMore": true, "autoWindowed": true, "windowCount": 131, "batchWaves": 3, "durationMs": 4217 } } ``` ## Пример ответа при ошибке 401 — не передан ключ авторизации: ```json { "success": false, "error": { "code": "MISSING_API_KEY", "message": "API key required. Pass via X-Api-Key header." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Тело запроса не парсится или содержит недопустимые поля | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Переданный ключ не распознан | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `sonet_group` | | 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` больше нуля вместе с фильтром по диапазону дат шире 14 дней. Два разных алгоритма выдачи дают несогласованные результаты, поэтому запрос отклоняется. Возьмите всё одним запросом с `limit` до 5000, либо передайте `autoWindow: false` с сортировкой по `id`, либо режьте диапазон дат на части сами | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Разбиение по временны́м окнам.** Фильтр по диапазону дат шире 14 дней автоматически разбивается на недельные окна, которые выполняются параллельными волнами — так выборка обходит потолок в 5000 записей на один вызов. В `meta` тогда приходят `autoWindowed: true`, число окон `windowCount` и число волн `batchWaves`. Отключает разбиение параметр `autoWindow: false`. При активном разбиении `offset` больше нуля отклоняется с `UNSTABLE_OFFSET_PAGINATION`. **Логические поля в фильтре можно передавать двумя способами.** В теле POST допустимы и `Y` / `N`, и нативные JSON `true` / `false`: `"filter": {"active": "Y"}` и `"filter": {"active": true}` дают одинаковую выборку. В ответе те же поля всегда приходят как `true` / `false`. **Префикс `%` в имени поля — поиск по подстроке.** `"filter": {"%name": "Маркетинг"}` найдёт все группы, в названии которых встречается «Маркетинг». Без префикса фильтр требует точного совпадения. **Параметр сортировки в теле — `sort`.** Ключ `order` в теле игнорируется без ошибки — выборка возвращается в порядке по умолчанию. Используйте `"sort": {"dateCreate": "DESC"}` или строковую форму `"sort": "dateCreate"` (направление по умолчанию — `ASC`). ## Смотрите также - [Список рабочих групп](./list.md) - [Получить рабочую группу](./get.md) - [Поля рабочей группы](./fields.md) - [Синтаксис фильтрации](/docs/filtering) --- # Workgroups: Update ## Обновить рабочую группу `PATCH /v1/workgroups/:id` Обновляет указанные поля рабочей группы. Возвращает полный объект группы после обновления. Неупомянутые в теле поля остаются без изменений. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | ★ | Идентификатор рабочей группы. Список: [`GET /v1/workgroups`](./list.md) | ## Поля запроса (body) Передавайте только те поля, которые нужно изменить. Остальные сохраняют текущие значения. | Поле | Тип | Обяз. | По умолч. | Описание | |------|-----|:-----:|-----------|---------| | `name` | string | нет | текущее значение | Название рабочей группы | | `description` | string | нет | текущее значение | Описание | | `ownerId` | number | нет | текущее значение | Идентификатор нового владельца группы. Список: `GET /v1/users` | | `subjectId` | number | нет | текущее значение | Идентификатор темы | | `active` | boolean | нет | текущее значение | Активна ли группа | | `visible` | boolean | нет | текущее значение | Видна ли в общих списках | | `opened` | boolean | нет | текущее значение | Открыта ли для вступления без приглашения | | `archived` | boolean | нет | текущее значение | Помещена ли в архив | | `isProject` | boolean | нет | текущее значение | Является ли проектом | | `isExtranet` | boolean | нет | текущее значение | Группа экстранета | | `keywords` | string | нет | текущее значение | Ключевые слова для поиска | Поля `id`, `subjectName`, `membersCount`, `dateCreate`, `dateUpdate`, `dateActivity`, `siteId`, `imageUrl` доступны только для чтения. Передача любого из них в теле возвращает `400 READONLY_FIELD`. ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/workgroups/85" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "description": "Обновлённое описание команды", "opened": true, "archived": false }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/workgroups/85" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "description": "Обновлённое описание команды", "opened": true, "archived": false }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/workgroups/85', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ description: 'Обновлённое описание команды', opened: true, archived: false, }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/workgroups/85', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ description: 'Обновлённое описание команды', opened: true, archived: false, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Полный объект рабочей группы после обновления — все поля см. [Получить рабочую группу](./get.md) | ## Пример ответа ```json { "success": true, "data": { "id": 85, "siteId": "s1", "name": "Маркетинг 2026", "description": "Обновлённое описание команды", "dateCreate": "2026-05-12T08:14:21.000Z", "dateUpdate": "2026-05-26T05:58:08.000Z", "active": true, "visible": true, "opened": true, "archived": false, "subjectId": 1, "ownerId": 1, "keywords": "проект,команда", "membersCount": 7, "dateActivity": "2026-05-26T05:58:08.000Z", "subjectName": "Рабочие группы", "isProject": false, "isExtranet": false } } ``` ## Пример ответа при ошибке Битрикс24 не различает «группа не существует» и «нет прав на обновление»: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "User has no permissions to update group" } } ``` ## Ошибки | HTTP | `error.code` | Описание | |------|--------------|---------| | 400 | `READONLY_FIELD` | В теле передано поле, доступное только для чтения (`id`, `subjectName`, `membersCount`, `dateCreate`, `dateUpdate`, `dateActivity`, `siteId`, `imageUrl`) | | 422 | `BITRIX_ERROR` | Битрикс24 отказал в обновлении. Текст в `error.message`. Типичные причины: ошибка валидации, конфликт значений, отсутствие прав на изменение, отсутствие рабочей группы с указанным `id` (два последних случая возвращают одинаковое сообщение) | | 401 | `MISSING_API_KEY` | В запросе не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Переданный ключ недействителен или отозван | | 403 | `SCOPE_DENIED` | У ключа нет скоупа `sonet_group` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - Сообщение `User has no permissions to update group` возвращается и при отсутствии рабочей группы с указанным `id`, и при отсутствии прав на её изменение. Чтобы различить эти два случая, сделайте дополнительный запрос [`GET /v1/workgroups/:id`](./get.md): ответ `404` — группы нет, успешный ответ — нет прав на изменение. ## Смотрите также - [Создать рабочую группу](./create.md) - [Получить рабочую группу](./get.md) - [Список рабочих групп](./list.md) --- # Telephony: Analytics # Аналитика и справочники Чтение статистики прошедших звонков с фильтрацией по дате, типу, оператору и другим полям, и справочник доступных голосов для синтеза речи в автозвонках. Bitrix24 API: `voximplant.statistic.get`, `voximplant.tts.voices.get` Скоуп: `telephony` ## Операции - [Статистика звонков](./analytics/statistics.md) — `GET /v1/calls/statistics` - [Справочник голосов](./analytics/voices.md) — `GET /v1/calls/voices` ## Смотрите также - [Телефония — обзор](../telephony.md) - [Исходящие звонки](./outbound.md) --- # Telephony Analytics: Statistics ## Статистика звонков `GET /v1/calls/statistics` Возвращает список записей о прошедших звонках с поддержкой фильтрации по полям, сортировки и пагинации. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `filter` (query) | object | — | Фильтрация по полям записи (UPPER_SNAKE_CASE). Поддерживаются операторы `>`, `>=`, `<`, `<=`, `!` в виде префикса к имени поля. Пример: `?filter[CALL_TYPE]=1`, `?filter[>CALL_START_DATE]=2026-01-01T00:00:00` | | `sort` (query) | string | — | Поле для сортировки в UPPER_SNAKE_CASE. Пример: `CALL_START_DATE` | | `order` (query) | string | — | Направление сортировки: `ASC` или `DESC` | | `limit` (query) | number | `50` | Максимальное количество записей в ответе (до 500) | | `offset` (query) | number | `0` | Смещение для пагинации | Диапазон дат задаётся двумя операторами одновременно. Пример: `filter[>CALL_START_DATE]=2026-04-01T00:00:00&filter[= total || data.length === 0) break } console.log(`Собрано записей: ${allCalls.length}`) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив записей о звонках | | `data[].id` | string | Внутренний идентификатор записи | | `data[].portalUserId` | string | ID оператора. Список: [`GET /v1/users`](/docs/entities/users) | | `data[].portalNumber` | string | Идентификатор линии: `reg` — арендованная линия Voximplant, `sip` — SIP-линия, `REST_APP:` — линия через REST-приложение | | `data[].phoneNumber` | string | Номер телефона клиента | | `data[].callId` | string | Идентификатор звонка. Префиксы: `externalCall.` — от [`register`](../crm/register.md), `callback.` — от [обратного звонка](../outbound/callback.md), `infocall.` — от [автозвонка](../outbound/auto-call.md) | | `data[].externalCallId` | string \| null | Внешний идентификатор, переданный при регистрации | | `data[].callCategory` | string | Категория: `external` для звонков через REST API | | `data[].callLog` | string \| null | URL детального лога Voximplant. `null` для звонков через REST-приложение | | `data[].callDuration` | string | Длительность звонка в секундах (строка) | | `data[].callStartDate` | string | Дата начала звонка, ISO 8601 с тайм-зоной портала | | `data[].callRecordUrl` | string | URL аудиозаписи звонка | | `data[].callVote` | string \| null | Оценка звонка от `1` до `5` | | `data[].cost` | string | Стоимость звонка (десятичная строка) | | `data[].costCurrency` | string | Код валюты (`RUR` и др.) | | `data[].callFailedCode` | string | Код результата: `200` — успех, `603-S` — отменён, `304` — пропущен, `500` — ошибка сценария, `402` — недостаточно средств, `403` — запрещено | | `data[].callFailedReason` | string | Текстовая причина результата | | `data[].crmEntityType` | string | Тип привязанной CRM-сущности: `LEAD`, `CONTACT` или пустая строка. Источник: [лиды](/docs/entities/leads), [контакты](/docs/entities/contacts) | | `data[].crmEntityId` | string | ID привязанной CRM-сущности | | `data[].crmActivityId` | string | ID CRM-активности. `"0"` — активность не создана | | `data[].restAppId` | string \| null | ID приложения-инициатора звонка | | `data[].restAppName` | string \| null | Название приложения-инициатора звонка | | `data[].transcriptId` | string \| null | ID прикреплённой транскрипции. Прикрепить: [`POST /v1/calls/:callId/transcription`](../crm/transcription.md) | | `data[].transcriptPending` | string | `Y` — транскрипция в обработке, `N` — транскрипция готова или отсутствует | | `data[].sessionId` | string | Идентификатор сессии Voximplant | | `data[].redialAttempt` | string \| null | Номер попытки перенабора | | `data[].comment` | string \| null | Комментарий оператора | | `data[].recordDuration` | string \| null | Длительность записи разговора в секундах | | `data[].recordFileId` | string \| null | ID файла записи на Диске | | `data[].callType` | string | Тип звонка: `"1"` — исходящий, `"2"` — входящий, `"3"` — входящий с перенаправлением, `"4"` — [обратный звонок](../outbound/callback.md), `"5"` — информационный ([автозвонок](../outbound/auto-call.md)) | | `total` | number | Общее количество записей, соответствующих фильтру | ## Пример ответа ```json { "success": true, "data": [ { "id": "1", "portalUserId": "1", "portalNumber": "reg133788", "phoneNumber": "+79638835976", "callId": "11018129443EB80D.1754478520.11438214", "externalCallId": null, "callCategory": "external", "callLog": "https://storage-gw-ru-02.voximplant.com/voximplant-logs/2025/08/06/...", "callDuration": "0", "callStartDate": "2025-08-06T14:08:40+03:00", "callRecordUrl": "", "callVote": null, "cost": "0.0000", "costCurrency": "RUR", "callFailedCode": "603-S", "callFailedReason": "Decline self", "crmEntityType": "CONTACT", "crmEntityId": "275", "crmActivityId": "7739", "restAppId": null, "restAppName": null, "transcriptId": null, "transcriptPending": "N", "sessionId": "3841557776", "redialAttempt": null, "comment": null, "recordDuration": null, "recordFileId": null, "callType": "1" } ], "total": 30 } ``` ## Пример ответа при ошибке 403 — нет скоупа `telephony`: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'telephony' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `TOKEN_MISSING` | Ключ не имеет настроенных токенов Битрикс24 | | 401 | `KEY_INACTIVE` | API-ключ неактивен или отозван | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `telephony` | | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку (текст в `error.message`) | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Имена полей в фильтре и сортировке — UPPER_SNAKE_CASE, а в ответе — camelCase.** Параметры `filter` и `sort` принимают исходные имена Битрикс24 (`CALL_TYPE`, `CALL_START_DATE`), а поля ответа приходят в camelCase (`callType`, `callStartDate`). Фильтр по camelCase-имени молча игнорируется — возвращаются все записи. **`total` находится в корне ответа.** В отличие от других list-эндпоинтов Вайбкод, поле `total` расположено непосредственно в корне ответа, а не в `meta.total`. **Фильтр по несуществующему полю** не возвращает ошибку — некорректное имя поля молча игнорируется и возвращаются все записи. ## Смотрите также - [Зарегистрировать звонок](../crm/register.md) - [Обратный звонок](../outbound/callback.md) - [Автозвонок с синтезом речи](../outbound/auto-call.md) - [Автозвонок с аудиофайлом](../outbound/auto-call-audio.md) - [Справочник голосов](./voices.md) - [Лиды](/docs/entities/leads) - [Контакты](/docs/entities/contacts) - [Телефония — обзор](/docs/telephony) --- # Telephony Analytics: Voices ## Справочник голосов `GET /v1/calls/voices` Возвращает словарь доступных голосов для синтеза речи. Идентификаторы из ответа передаются как параметр `voice` в [`POST /v1/calls/auto-call`](../outbound/auto-call.md). ## Примеры ### curl — личный ключ ```bash curl https://vibecode.bitrix24.tech/v1/calls/voices \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl https://vibecode.bitrix24.tech/v1/calls/voices \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calls/voices', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() const voices = Object.entries(data) // [['ruinternalfemale', 'Русский (женский) (Default)'], ...] ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calls/voices', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Словарь голосов: ключ — идентификатор голоса, значение — название для отображения с указанием источника синтеза в скобках | | `data.` | string | Название голоса. В скобках — источник синтеза: `Amazon` или `Default`. Передавайте `voiceId` как параметр `voice` в автозвонке | ## Пример ответа ```json { "success": true, "data": { "auenglishfemale": "Австралийский английский (женский) (Amazon)", "brportuguesefemale": "Бразильский португальский (женский) (Amazon)", "ruinternalfemale": "Русский (женский) (Default)", "ruinternalmale": "Русский (мужской) (Default)", "ukenglishfemale": "Английский (женский) (Amazon)", "ukenglishmale": "Английский (мужской) (Amazon)", "usenglishfemale": "Американский английский (женский) (Default)", "usenglishmale": "Американский английский (мужской) (Default)", "eurfrenchfemale": "Французский (женский) (Amazon)", "eurfrenchmale": "Французский (мужской) (Amazon)", "eurgermanfemale": "Немецкий (женский) (Default)", "eurgermanmale": "Немецкий (мужской) (Default)", "jpjapanesefemale": "Японский (женский) (Default)", "chchinesefemale": "Китайский (женский) (Default)" } } ``` ## Пример ответа при ошибке 403 — нет скоупа `telephony`: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'telephony' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `TOKEN_MISSING` | Ключ не имеет настроенных токенов Битрикс24 | | 401 | `KEY_INACTIVE` | API-ключ неактивен или отозван | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `telephony` | | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку (текст в `error.message`) | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`data` — объект-словарь, не массив.** Для перебора всех голосов используйте `Object.entries(data)`. Получить конкретный голос по идентификатору: `data['ruinternalfemale']`. **Голос по умолчанию.** При вызове автозвонка без параметра `voice` Битрикс24 выбирает голос по умолчанию исходя из языка портала. Для русскоязычного портала — `ruinternalfemale`. **Набор голосов зависит от тарифа.** Доступные голоса и их идентификаторы могут различаться в зависимости от тарифного плана портала. ## Смотрите также - [Автозвонок с синтезом речи](../outbound/auto-call.md) - [Автозвонок с аудиофайлом](../outbound/auto-call-audio.md) - [Статистика звонков](./statistics.md) - [Телефония — обзор](/docs/telephony) --- # Telephony: Crm # Звонки в CRM Регистрация входящих и исходящих внешних звонков в CRM Битрикс24, отображение карточки звонка оператору, завершение со статусом и длительностью, прикрепление текстовой транскрипции диалога. Bitrix24 API: `telephony.externalcall.*`, `telephony.call.attachTranscription` Скоуп: `telephony` ## Операции - [Зарегистрировать звонок](./crm/register.md) — `POST /v1/calls/register` - [Завершить звонок](./crm/finish.md) — `POST /v1/calls/:callId/finish` - [Показать карточку](./crm/show.md) — `POST /v1/calls/:callId/show` - [Скрыть карточку](./crm/hide.md) — `POST /v1/calls/:callId/hide` - [Прикрепить транскрипцию](./crm/transcription.md) — `POST /v1/calls/:callId/transcription` ## Типовой сценарий 1. Входящий звонок поступил во внешнюю АТС → `POST /v1/calls/register` с `crmCreate: true` создаёт лид, если номер не найден в CRM. В ответе — `CALL_ID` и `CRM_ENTITY_ID`. 2. Карточка показывается оператору: `POST /v1/calls/:callId/show`. 3. Звонок завершается: `POST /v1/calls/:callId/finish` с длительностью и кодом результата. 4. После распознавания речи прикрепляется транскрипция: `POST /v1/calls/:callId/transcription` со списком реплик. ## Смотрите также - [Телефония — обзор](../telephony.md) - [Линии](./lines.md) - [Исходящие звонки](./outbound.md) --- # Telephony Crm: Finish ## Завершить звонок `POST /v1/calls/:callId/finish` Завершает зарегистрированный звонок: фиксирует длительность и итоговый статус, создаёт дело в связанной CRM-сущности. Вызывайте после окончания разговора, до прикрепления транскрипции. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|---------| | `callId` | path | string | да | `callId` из ответа [`POST /v1/calls/register`](./register.md) | ## Поля запроса (body) | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `userId` | number | да | — | ID пользователя Битрикс24, завершившего звонок. Положительное целое число, принимается также числовая строка `"42"`. [Список пользователей](/docs/entities/users) | | `duration` | number | да | — | Длительность звонка в секундах. Неотрицательное число, принимается также числовая строка | | `statusCode` | string | нет | `"200"` при duration > 0, иначе `"304"` | Код завершения: `"200"` успешно, `"304"` пропущен, `"403"` запрещено, `"486"` занято, `"603"` отклонён, `"603-S"` отменён клиентом, `"402"` нет средств, `"404"` неверный номер, `"423"` заблокирован, `"480"` временно недоступен, `"484"` / `"503"` недоступное направление, `"OTHER"` | | `add_to_chat` | boolean | нет | — | Добавить событие о звонке в чат сотрудника | | `vote` | number | нет | — | Оценка звонка: `1`–`5`. Попадает в поле `CALL_VOTE` («Оценка», звёздочки) раздела [Статистика звонков](/docs/telephony/analytics/statistics). Допускается также UPPER-форма `VOTE` | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/calls/CALL_ID/finish \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "userId": 1, "duration": 120, "statusCode": "200" }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/calls/CALL_ID/finish \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "userId": 1, "duration": 120, "statusCode": "200" }' ``` ### JavaScript — личный ключ ```javascript const callId = 'externalCall.00b1e735843c558431be668e3687a58b.1777974304' const res = await fetch(`https://vibecode.bitrix24.tech/v1/calls/${callId}/finish`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ userId: 1, duration: 120, statusCode: '200', }), }) const { success, data } = await res.json() console.log('Дело:', data.crmActivityId) ``` ### JavaScript — OAuth-приложение ```javascript const callId = 'externalCall.00b1e735843c558431be668e3687a58b.1777974304' const res = await fetch(`https://vibecode.bitrix24.tech/v1/calls/${callId}/finish`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ userId: 1, duration: 120, statusCode: '200', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `callId` | string | Идентификатор звонка | | `externalCallId` | string \| null | Внешний идентификатор, переданный при регистрации | | `portalUserId` | number | ID пользователя Битрикс24 | | `phoneNumber` | string | Номер телефона | | `portalNumber` | string | Номер линии на портале | | `incoming` | string | Тип звонка: `"1"` — исходящий, `"2"` — входящий, `"3"` — входящий с перенаправлением, `"4"` — обратный звонок, `"5"` — информационный | | `callDuration` | number | Длительность в секундах | | `callStartDate` | object | Дата начала звонка. Возвращается как пустой объект `{}` — см. [особенности](#известные-особенности) | | `callStatus` | number | Статус завершения | | `callVote` | number | Оценка звонка | | `cost` | number | Стоимость звонка | | `costCurrency` | string | Валюта стоимости | | `callFailedCode` | string | Переданный `statusCode` | | `callFailedReason` | string | Текстовое описание причины завершения | | `restAppId` | number \| null | ID приложения | | `restAppName` | string \| false | Имя приложения | | `crmActivityId` | number \| false | ID созданного дела. `false`, если сущность не привязана | | `comment` | string \| null | Комментарий к звонку | | `id` | number | Внутренний ID записи о звонке | | `ERRORS` | object \| null | Ошибки, не прервавшие завершение (например `ACTIVITY_CREATION`) | | `crmEntityType` | string | Тип привязанной CRM-сущности (только при наличии привязки) | | `crmEntityId` | number | ID привязанной CRM-сущности (только при наличии привязки) | ## Пример ответа HTTP 200 — звонок завершён, дело создано: ```json { "success": true, "data": { "callId": "externalCall.00b1e735843c558431be668e3687a58b.1777974304", "externalCallId": null, "portalUserId": 1, "phoneNumber": "+79161234567", "portalNumber": "REST_APP:", "incoming": "2", "callDuration": 120, "callStartDate": {}, "callStatus": 1, "callVote": 0, "cost": 0, "costCurrency": "", "callFailedCode": "200", "callFailedReason": "", "restAppId": null, "restAppName": false, "crmActivityId": 7995, "comment": null, "crmEntityType": "LEAD", "crmEntityId": 1001069, "id": 61 } } ``` ## Пример ответа при ошибке 400 — не переданы обязательные параметры: ```json { "success": false, "error": { "code": "MISSING_PARAMS", "message": "Required: userId (positive integer), duration (number ≥ 0, seconds)" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_PARAMS` | `userId` не передан или не распознан как положительное целое число, либо `duration` не передан или не распознан как неотрицательное число | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `TOKEN_MISSING` | Ключ не имеет настроенных токенов Битрикс24 | | 401 | `KEY_INACTIVE` | API-ключ неактивен или отозван | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `telephony` | | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку (текст в `error.message`) | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`callStartDate` всегда возвращается как пустой объект `{}`.** Реальную дату начала звонка смотрите в [статистике](/docs/telephony/analytics/statistics). **`CRM_ACTIVITY_ID: false` при отсутствии привязки.** В поле `ERRORS.ACTIVITY_CREATION` возвращается текстовое описание причины. Звонок при этом считается завершённым. **Значение `statusCode` влияет на метку в CRM.** Явная передача позволяет зафиксировать причину завершения независимо от длительности. ## Смотрите также - [Зарегистрировать звонок](./register.md) - [Прикрепить транскрипцию](./transcription.md) - [Показать карточку](./show.md) - [Статистика звонков](/docs/telephony/analytics/statistics) - [Лиды](/docs/entities/leads) - [Контакты](/docs/entities/contacts) - [Сделки](/docs/entities/deals) --- # Telephony Crm: Hide ## Скрыть карточку звонка `POST /v1/calls/:callId/hide` Убирает карточку активного звонка поверх открытых окон Битрикс24 у указанного пользователя. Симметричен [`POST /v1/calls/:callId/show`](./show.md). ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|---------| | `callId` | path | string | да | `CALL_ID` из ответа [`POST /v1/calls/register`](./register.md) | ## Поля запроса (body) | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `userId` | number | да | — | ID пользователя Битрикс24, у которого скрывается карточка. Положительное целое число, принимается также числовая строка `"42"`. [Список пользователей](/docs/entities/users) | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/calls/CALL_ID/hide \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"userId": 1}' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/calls/CALL_ID/hide \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"userId": 1}' ``` ### JavaScript — личный ключ ```javascript const callId = 'externalCall.00b1e735843c558431be668e3687a58b.1777974304' const res = await fetch(`https://vibecode.bitrix24.tech/v1/calls/${callId}/hide`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ userId: 1 }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const callId = 'externalCall.00b1e735843c558431be668e3687a58b.1777974304' const res = await fetch(`https://vibecode.bitrix24.tech/v1/calls/${callId}/hide`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ userId: 1 }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | boolean | `true` — карточка скрыта успешно, `false` — карточка не найдена: звонок не существует или уже завершён | ## Пример ответа ```json { "success": true, "data": true } ``` ## Пример ответа при ошибке 400 — не передан обязательный параметр: ```json { "success": false, "error": { "code": "MISSING_PARAMS", "message": "Required: userId (positive integer)" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_PARAMS` | `userId` не передан или не распознан как положительное целое число | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `TOKEN_MISSING` | Ключ не имеет настроенных токенов Битрикс24 | | 401 | `KEY_INACTIVE` | API-ключ неактивен или отозван | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `telephony` | | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку (текст в `error.message`) | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Признак успеха — поле `data`, не HTTP-статус.** При несуществующем `callId` Битрикс24 возвращает `HTTP 200` с `data: false`. Проверяйте значение поля, а не код ответа. **`userId` не обязан совпадать с тем, кто регистрировал звонок.** Карточку можно скрыть у любого пользователя портала. ## Смотрите также - [Показать карточку](./show.md) - [Зарегистрировать звонок](./register.md) - [Завершить звонок](./finish.md) --- # Telephony Crm: Register ## Зарегистрировать звонок `POST /v1/calls/register` Регистрирует входящий или исходящий звонок в Битрикс24 CRM. При `crmCreate: true` создаёт лид, если номер телефона не найден среди существующих сущностей. Возвращает `callId` для всех последующих операций со звонком. ## Поля запроса (body) | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `userId` | number | да | — | ID пользователя Битрикс24, принимающего звонок. Положительное целое число, принимается также числовая строка `"42"`. [Список пользователей](/docs/entities/users) | | `phoneNumber` | string | да | — | Номер телефона звонящего в международном формате. Непустая строка или число. Пробелы по краям отбрасываются, строка из одних пробелов считается пустой | | `type` | number | да | — | Направление: `1` — исходящий, `2` — входящий, `3` — входящий с перенаправлением, `4` — обратный звонок, `5` — информационный | | `lineNumber` | string | нет | — | Номер внешней линии приложения. [Список линий](/docs/telephony/lines/list) | | `crmCreate` | boolean | нет | `false` | `true` — создать лид, если номер не найден в CRM | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/calls/register \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "userId": 1, "phoneNumber": "+79161234567", "type": 2, "crmCreate": true }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/calls/register \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "userId": 1, "phoneNumber": "+79161234567", "type": 2, "crmCreate": true }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calls/register', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ userId: 1, phoneNumber: '+79161234567', type: 2, crmCreate: true, }), }) const { success, data } = await res.json() const callId = data.callId ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calls/register', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ userId: 1, phoneNumber: '+79161234567', type: 2, crmCreate: true, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `callId` | string | Идентификатор звонка для всех последующих операций | | `crmCreatedLead` | number \| null | ID созданного лида. `null`, если лид не создан | | `crmCreatedEntities` | array | Массив созданных CRM-сущностей `[{entityType, entityId}]` | | `crmEntityType` | string | Тип привязанной CRM-сущности: `LEAD`, `CONTACT`, `COMPANY` или пустая строка | | `crmEntityId` | number \| null | ID привязанной CRM-сущности. `null`, если сущность не привязана | ## Пример ответа HTTP 201 — звонок зарегистрирован, создан новый лид: ```json { "success": true, "data": { "callId": "externalCall.00b1e735843c558431be668e3687a58b.1777974304", "crmCreatedLead": 1001069, "crmCreatedEntities": [{"entityType": "LEAD", "entityId": 1001069}], "crmEntityType": "LEAD", "crmEntityId": 1001069 } } ``` ## Пример ответа при ошибке 400 — не переданы обязательные параметры: ```json { "success": false, "error": { "code": "MISSING_PARAMS", "message": "Required: userId (positive integer), phoneNumber (non-empty string)" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_PARAMS` | `userId` не передан или не распознан как положительное целое число, либо `phoneNumber` не передан или не распознан как непустая строка или число | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `TOKEN_MISSING` | Ключ не имеет настроенных токенов Битрикс24 | | 401 | `KEY_INACTIVE` | API-ключ неактивен или отозван | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `telephony` | | 422 | `BITRIX_ERROR` | `type` не передан или его значение вне перечня `1`–`5` — в `error.message` приходит `Unknown TYPE` | | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку (текст в `error.message`) | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Поиск существующей CRM-сущности при `crmCreate: true`.** Битрикс24 сначала ищет лид, контакт или компанию с совпадающим номером телефона. При нахождении `crmEntityId` указывает на существующую сущность, а `crmCreatedLead` остаётся `null`. Новый лид создаётся только если совпадений нет. **`CRM_*` поля пустые при `crmCreate: false`.** Привязка к CRM может произойти автоматически при завершении через [`POST /v1/calls/:callId/finish`](./finish.md), если Битрикс24 найдёт совпадение по номеру в момент завершения. **`callId` — обязательный параметр для всех следующих шагов.** Сохраните его сразу: все операции `show`, `hide`, `finish`, `transcription` принимают `callId` в пути запроса. ## Смотрите также - [Завершить звонок](./finish.md) - [Показать карточку](./show.md) - [Скрыть карточку](./hide.md) - [Прикрепить транскрипцию](./transcription.md) - [Лиды](/docs/entities/leads) - [Контакты](/docs/entities/contacts) - [Линии](/docs/telephony/lines) --- # Telephony Crm: Show ## Показать карточку звонка `POST /v1/calls/:callId/show` Отображает карточку активного звонка поверх открытых окон Битрикс24 у указанного пользователя. Вызывайте после [`POST /v1/calls/register`](./register.md), пока звонок не завершён. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|---------| | `callId` | path | string | да | `CALL_ID` из ответа [`POST /v1/calls/register`](./register.md) | ## Поля запроса (body) | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `userId` | number | да | — | ID пользователя Битрикс24, которому показывается карточка. Положительное целое число, принимается также числовая строка `"42"`. [Список пользователей](/docs/entities/users) | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/calls/CALL_ID/show \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"userId": 1}' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/calls/CALL_ID/show \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"userId": 1}' ``` ### JavaScript — личный ключ ```javascript const callId = 'externalCall.00b1e735843c558431be668e3687a58b.1777974304' const res = await fetch(`https://vibecode.bitrix24.tech/v1/calls/${callId}/show`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ userId: 1 }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const callId = 'externalCall.00b1e735843c558431be668e3687a58b.1777974304' const res = await fetch(`https://vibecode.bitrix24.tech/v1/calls/${callId}/show`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ userId: 1 }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data` | boolean | `true` — карточка показана успешно, `false` — карточка не показана: звонок не найден или уже завершён | ## Пример ответа ```json { "success": true, "data": true } ``` ## Пример ответа при ошибке 400 — не передан обязательный параметр: ```json { "success": false, "error": { "code": "MISSING_PARAMS", "message": "Required: userId (positive integer)" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_PARAMS` | `userId` не передан или не распознан как положительное целое число | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `TOKEN_MISSING` | Ключ не имеет настроенных токенов Битрикс24 | | 401 | `KEY_INACTIVE` | API-ключ неактивен или отозван | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `telephony` | | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку (текст в `error.message`) | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Признак успеха — поле `data`, не HTTP-статус.** При несуществующем или уже завершённом `callId` Битрикс24 возвращает `HTTP 200` с `data: false`. Проверяйте значение поля, а не код ответа. **`userId` не обязан совпадать с тем, кто регистрировал звонок.** Карточку можно показать любому пользователю портала — например, супервизору или замещающему оператору. ## Смотрите также - [Зарегистрировать звонок](./register.md) - [Скрыть карточку](./hide.md) - [Завершить звонок](./finish.md) --- # Telephony Crm: Transcription ## Прикрепить транскрипцию `POST /v1/calls/:callId/transcription` Прикрепляет текстовую транскрипцию диалога к завершённому звонку в Битрикс24. Звонок должен быть предварительно завершён через [`POST /v1/calls/:callId/finish`](./finish.md). ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|---------| | `callId` | path | string | да | `callId` из ответа [`POST /v1/calls/register`](./register.md) | ## Поля запроса (body) | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `messages` | array | да | — | Массив реплик диалога. Каждый элемент: `{side, startTime, stopTime, message}`. Не может быть пустым | | `messages[].side` | string | да | — | Сторона диалога: `"User"` — оператор, `"Client"` — клиент | | `messages[].startTime` | number | да | — | Время начала реплики в секундах от начала записи (≥ 0) | | `messages[].stopTime` | number | да | — | Время окончания реплики в секундах (> 0) | | `messages[].message` | string | да | — | Текст реплики (непустая строка) | | `cost` | number | нет | — | Стоимость распознавания | | `costCurrency` | string | нет | — | Валюта стоимости (например `"RUB"`) | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/calls/CALL_ID/transcription \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "messages": [ {"side": "User", "startTime": 0, "stopTime": 3, "message": "Здравствуйте, чем могу помочь?"}, {"side": "Client", "startTime": 4, "stopTime": 9, "message": "Здравствуйте, хотел уточнить статус заказа"} ] }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/calls/CALL_ID/transcription \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "messages": [ {"side": "User", "startTime": 0, "stopTime": 3, "message": "Здравствуйте, чем могу помочь?"}, {"side": "Client", "startTime": 4, "stopTime": 9, "message": "Здравствуйте, хотел уточнить статус заказа"} ] }' ``` ### JavaScript — личный ключ ```javascript const callId = 'externalCall.00b1e735843c558431be668e3687a58b.1777974304' const res = await fetch(`https://vibecode.bitrix24.tech/v1/calls/${callId}/transcription`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ messages: [ { side: 'User', startTime: 0, stopTime: 3, message: 'Здравствуйте, чем могу помочь?' }, { side: 'Client', startTime: 4, stopTime: 9, message: 'Здравствуйте, хотел уточнить статус заказа' }, ], }), }) const { success, data } = await res.json() console.log('ID транскрипции:', data.transcriptId) ``` ### JavaScript — OAuth-приложение ```javascript const callId = 'externalCall.00b1e735843c558431be668e3687a58b.1777974304' const res = await fetch(`https://vibecode.bitrix24.tech/v1/calls/${callId}/transcription`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ messages: [ { side: 'User', startTime: 0, stopTime: 3, message: 'Здравствуйте, чем могу помочь?' }, { side: 'Client', startTime: 4, stopTime: 9, message: 'Здравствуйте, хотел уточнить статус заказа' }, ], }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `transcriptId` | number | Внутренний ID транскрипции на портале Битрикс24 | ## Пример ответа HTTP 200 — транскрипция прикреплена: ```json { "success": true, "data": { "transcriptId": 3 } } ``` ## Пример ответа при ошибке 400 — не передан массив реплик: ```json { "success": false, "error": { "code": "MISSING_PARAMS", "message": "Required: messages (non-empty array of {side, startTime, stopTime, message})" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_PARAMS` | `messages` не передан, не является массивом или массив пустой | | 400 | `INVALID_MESSAGE_SHAPE` | Некорректная структура элемента `messages[i]`: неверный `side`, тип или диапазон `startTime`/`stopTime`, пустой `message`. В тексте ошибки — индекс некорректного элемента и нарушенное поле | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `TOKEN_MISSING` | Ключ не имеет настроенных токенов Битрикс24 | | 401 | `KEY_INACTIVE` | API-ключ неактивен или отозван | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `telephony` | | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку (текст в `error.message`) | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **На незавершённом звонке Битрикс24 вернёт ошибку.** Порядок операций: `register` → `finish` → `transcription`. **Вайбкод валидирует структуру `messages` локально.** Каждый элемент проверяется до отправки в Битрикс24. Ошибка `INVALID_MESSAGE_SHAPE` содержит индекс некорректного элемента и точное описание нарушенного ограничения — это позволяет исправить конкретный элемент без повторной отправки всего массива. **`transcriptId` используется только внутри портала.** Внешних эндпоинтов для чтения транскрипций по этому ID нет. ## Смотрите также - [Завершить звонок](./finish.md) - [Зарегистрировать звонок](./register.md) - [Статистика звонков](/docs/telephony/analytics/statistics) --- # Telephony: Lines # Линии Создание, обновление и удаление внешних линий приложения, а также чтение списка линий, арендованных у Voximplant или подключённых по SIP. Bitrix24 API: `telephony.externalLine.*`, `voximplant.line.get` Скоуп: `telephony` ## Операции - [Список линий приложения](./lines/list.md) — `GET /v1/telephony-lines` - [Добавить линию](./lines/create.md) — `POST /v1/telephony-lines` - [Обновить линию](./lines/update.md) — `PATCH /v1/telephony-lines/:number` - [Удалить линию](./lines/delete.md) — `DELETE /v1/telephony-lines/:number` - [Поля линии приложения](./lines/fields.md) — `GET /v1/telephony-lines/fields` - [Линии Voximplant](./lines/voximplant.md) — `GET /v1/voximplant-lines` ## Что нужно знать Два эндпоинта возвращают линии из разных источников: - `GET /v1/telephony-lines` — линии, **добавленные приложением** через `POST /v1/telephony-lines`. Актуально для приложений, подключающих собственную АТС к порталу. - `GET /v1/voximplant-lines` — линии, **арендованные у Voximplant** или подключённые по SIP, видимые порталу. Только чтение. Идентификатор линии приложения — строка `number`, заданная при создании. URL обновления и удаления использует именно её — спецсимволы нужно URL-кодировать. ## Поля линии приложения | Поле | Тип | Описание | |------|-----|---------| | `number` | string | Номер внешней линии, заданный при создании | | `name` | string \| null | Название линии, отображаемое в интерфейсе. `null`, если не задано при создании | | `crmAutoCreate` | boolean | Автосоздание CRM-сущности при исходящем звонке через линию. По умолчанию `true` | | `serverName` | string | Имя сервера телефонии. Только для чтения: в ответах не приходит, а запись отклоняется с `400 READONLY_FIELD` | Какие из этих полей принимаются на запись — [Добавить линию](./lines/create.md) и [Обновить линию](./lines/update.md). Набор полей линий Voximplant описан на странице [Линии Voximplant](./lines/voximplant.md). ## Смотрите также - [Телефония — обзор](../telephony.md) - [Исходящие звонки](./outbound.md) --- # Telephony Lines: Create ## Добавить линию `POST /v1/telephony-lines` Регистрирует новую внешнюю линию приложения на портале. После создания линия доступна в [`GET /v1/telephony-lines`](./list.md) и может использоваться как `fromLine` в исходящих звонках. Поля передаются плоско в корне JSON — без обёртки `fields`. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `number` | string | да | Уникальный идентификатор линии на портале | | `name` | string | нет | Отображаемое название линии | | `crmAutoCreate` | boolean | нет | Автосоздание CRM-сущности при исходящем звонке через линию: `true` — создавать, `false` — не создавать. По умолчанию `true` | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/telephony-lines" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "number": "sip-line-1", "name": "Основная линия", "crmAutoCreate": false }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/telephony-lines" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "number": "sip-line-1", "name": "Основная линия", "crmAutoCreate": false }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/telephony-lines', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ number: 'sip-line-1', name: 'Основная линия', crmAutoCreate: false, }), }) const { success, data } = await res.json() console.log('Внутренний ID записи:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/telephony-lines', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ number: 'sip-line-1', name: 'Основная линия', crmAutoCreate: false, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Внутренний идентификатор записи в Битрикс24. Для последующих операций не используется — обновление и удаление ведутся по `number` | ## Пример ответа ```json { "success": true, "data": { "id": 17 } } ``` ## Пример ответа при ошибке 422 — поле `number` не передано: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "NUMBER should not be empty" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `READONLY_FIELD` | В теле передано поле только для чтения — `serverName` | | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку — текст в `error.message`. Причины: не передан `number`, дублирующий идентификатор | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `TOKEN_MISSING` | Ключ не имеет настроенных токенов | | 401 | `KEY_INACTIVE` | API-ключ неактивен или отозван | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `telephony` | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`serverName` — только для чтения, запись отклоняется.** Битрикс24 это поле не хранит и не возвращает, поэтому запись отклоняется до обращения к нему: и создание, и обновление отвечают `400 READONLY_FIELD`. Раньше создание отвечало `201`, а значение молча терялось. Само поле осталось видимым в `GET /v1/telephony-lines/fields` с признаком «только для чтения», чтобы его назначение можно было понять. **Поле `crmAutoCreate` — camelCase boolean.** Передавайте `true`/`false`; если поле опущено, линия создаётся со значением по умолчанию `true`. Ранее принималось только UPPER_SNAKE-имя `CRM_AUTO_CREATE` строкой `"Y"`/`"N"`, а `crmAutoCreate` молча отбрасывался — с 07.2026 канонично camelCase boolean (сырой UPPER-вариант ещё принимается на запись для совместимости). **`data.id` — внутренний идентификатор, не используется для других операций.** Обновление и удаление линии выполняются по `number` из тела запроса, а не по `data.id` из ответа. Сохраните переданное `number` — именно оно подставляется в URL `PATCH /v1/telephony-lines/:number` и `DELETE /v1/telephony-lines/:number`. Значения с `+`, пробелами или `/` допустимы — при подстановке в URL их нужно кодировать: `+79161234567` → `%2B79161234567`. ## Смотрите также - [Список линий приложения](./list.md) - [Обновить линию](./update.md) - [Удалить линию](./delete.md) - [Исходящие звонки](/docs/telephony/outbound) --- # Telephony Lines: Delete ## Удалить линию `DELETE /v1/telephony-lines/:number` Удаляет внешнюю линию приложения по идентификатору `number`. Восстановить удалённую линию через API нельзя — создайте новую с тем же `number` при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `number` (path) | string | да | Идентификатор линии, заданный при создании. Если содержит спецсимволы — URL-кодировать | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/telephony-lines/sip-line-1" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/telephony-lines/sip-line-1" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const number = 'sip-line-1' const res = await fetch( `https://vibecode.bitrix24.tech/v1/telephony-lines/${encodeURIComponent(number)}`, { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, } ) if (res.status === 204) { console.log('Линия удалена') } ``` ### JavaScript — OAuth-приложение ```javascript const number = 'sip-line-1' const res = await fetch( `https://vibecode.bitrix24.tech/v1/telephony-lines/${encodeURIComponent(number)}`, { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, } ) if (res.status === 204) { console.log('Линия удалена') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — успех проверяется по коду ответа. ## Пример ответа ```http HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 422 — ошибка Битрикс24: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "External line not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку — текст в `error.message`. Возникает в том числе при попытке удалить несуществующую линию | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `TOKEN_MISSING` | Ключ не имеет настроенных токенов | | 401 | `KEY_INACTIVE` | API-ключ неактивен или отозван | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `telephony` | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список линий приложения](./list.md) - [Добавить линию](./create.md) - [Обновить линию](./update.md) --- # Telephony Lines: Fields ## Поля линии приложения `GET /v1/telephony-lines/fields` Возвращает схему полей внешней линии приложения: тип каждого поля, доступность на запись, название и описание. Схема нужна перед [добавлением](./create.md) и [обновлением](./update.md) линии — по ней видно, какие поля принимаются, а какие только читаются. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/telephony-lines/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/telephony-lines/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/telephony-lines/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Поля линии:', Object.keys(data.fields)) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/telephony-lines/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.fields` | object | Схема полей линии. Ключ — имя поля в camelCase, значение — его описание | | `data.fields.<имя>.type` | string | Тип значения поля: `string` или `boolean` | | `data.fields.<имя>.readonly` | boolean | `true` — поле только читается, запись отклоняется с `400 READONLY_FIELD` | | `data.fields.<имя>.nullable` | boolean | Присутствует у полей, которые могут прийти со значением `null` | | `data.fields.<имя>.notReturned` | boolean | Присутствует у полей, которые объявлены в схеме, но в ответах не приходят | | `data.fields.<имя>.label` | string | Короткое название поля | | `data.fields.<имя>.description` | string | Развёрнутое описание поля | | `data.batch` | array | Операции линии, доступные в пакетном вызове: `create`, `update`, `delete` | Схема описывает четыре поля: | Поле | Тип | RO | Описание | |------|-----|----|---------| | `number` | string | | Номер внешней линии — он же идентификатор линии в путях обновления и удаления | | `name` | string \| null | | Название линии, отображаемое в интерфейсе. У линии, созданной без названия, приходит `null` | | `crmAutoCreate` | boolean | | Создавать ли автоматически лид или контакт по звонкам на этой линии | | `serverName` | string | да | Имя сервера телефонии, на котором зарегистрирована линия. В ответах не приходит, на запись отклоняется | ## Пример ответа ```json { "success": true, "data": { "fields": { "number": { "type": "string", "readonly": false, "label": "Номер линии", "description": "Номер внешней линии — идентификатор телефонной линии." }, "serverName": { "type": "string", "readonly": true, "notReturned": true, "label": "Имя сервера", "description": "Имя сервера телефонии, на котором зарегистрирована линия. Только для чтения: Битрикс24 его не хранит и не возвращает, поэтому запись отклоняется с 400 READONLY_FIELD, а не теряется молча." }, "name": { "type": "string", "readonly": false, "nullable": true, "label": "Название линии", "description": "Человекочитаемое название линии, отображаемое в интерфейсе. Может быть null: у линии, созданной без названия, возвращается null." }, "crmAutoCreate": { "type": "boolean", "readonly": false, "label": "Автосоздание в CRM", "description": "Создавать ли автоматически сущности CRM (лид/контакт) по звонкам на этой линии." } }, "batch": ["create", "update", "delete"] } } ``` ## Пример ответа при ошибке 401 — не передан ключ: ```json { "success": false, "error": { "code": "MISSING_API_KEY", "message": "API key required. Pass via X-Api-Key header." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `TOKEN_MISSING` | Ключ не имеет настроенных токенов | | 401 | `KEY_INACTIVE` | API-ключ неактивен или отозван | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `telephony` | | 429 | `RATE_LIMITED` | Превышен лимит запросов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Схема одинакова на всех порталах.** Ответ собирается из описания линии на стороне Вайбкод, а не запрашивается у портала, поэтому набор полей и их типы не зависят от настроек конкретного портала и от доступности Битрикс24. Ответ кэшируется, источник показывает заголовок `X-Cache` — правила и способы обойти кэш описаны в [Лимитах и оптимизации](/docs/optimization). **`serverName` объявлено, но не приходит.** Поле есть в схеме с пометкой `notReturned`, и это не рассинхронизация: в ответах [списка](./list.md), создания и обновления его нет ни при каких условиях, а попытка записать значение отклоняется с `400 READONLY_FIELD` — молчаливой потери значения не происходит. Считайте его справочным описанием, а не источником данных. **`batch` называет доступные пакетные операции.** Массив перечисляет операции линии, которые принимает [пакетный вызов](/docs/batch): `create`, `update`, `delete`. Чтения в этом списке нет — список линий забирается отдельным вызовом. ## Смотрите также - [Список линий приложения](./list.md) - [Добавить линию](./create.md) - [Обновить линию](./update.md) - [Удалить линию](./delete.md) - [Лимиты и оптимизация](/docs/optimization) --- # Telephony Lines: List ## Список линий приложения `GET /v1/telephony-lines` Возвращает список внешних линий, добавленных приложением через `POST /v1/telephony-lines`. Список возвращается целиком — фильтрация, сортировка и `offset` не поддерживаются и отклоняются с `400`, нужную линию отбирайте на стороне клиента. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|---------| | `select` (query) | string | — | Выборка полей в camelCase: `?select=number,name` | | `limit` (query) | number | `50` | Количество записей (до 5000) | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/telephony-lines" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/telephony-lines" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/telephony-lines', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, meta } = await res.json() console.log(`Найдено ${meta.total} линий`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/telephony-lines', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив линий | | `data[].number` | string | Идентификатор линии, заданный при создании | | `data[].name` | string \| null | Отображаемое название. `null`, если не задано при создании | | `data[].crmAutoCreate` | boolean | Автосоздание CRM-сущности при исходящем звонке через эту линию: `true` — создавать, `false` — не создавать | | `meta.total` | number | Общее количество линий приложения | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | ## Пример ответа HTTP 200, пустая выборка: ```json {"success":true,"data":[],"meta":{"total":0,"hasMore":false}} ``` HTTP 200, одна линия: ```json { "success": true, "data": [ { "number": "doc-test-line-001", "name": "Тестовая линия (аудит)", "crmAutoCreate": true } ], "meta": { "total": 1, "hasMore": false } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'telephony' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `UNSUPPORTED_FILTER` | Передан фильтр — метод Битрикс24 его не поддерживает | | 400 | `INVALID_SORT_FIELD` | Передана сортировка — метод Битрикс24 её не поддерживает | | 400 | `UNSUPPORTED_OFFSET` | Передано ненулевое смещение — у метода Битрикс24 нет постраничности | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `TOKEN_MISSING` | Ключ не имеет настроенных токенов | | 401 | `KEY_INACTIVE` | API-ключ неактивен или отозван | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `telephony` | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Только линии этого приложения.** Список содержит линии, созданные через `POST /v1/telephony-lines` в рамках текущего API-ключа. Линии, арендованные у Voximplant или подключённые по SIP, доступны через [`GET /v1/voximplant-lines`](./voximplant.md). **Фильтрация, сортировка и смещение отклоняются.** Метод Битрикс24 за этим списком не принимает входных параметров вовсе, поэтому фильтр отвечает `400 UNSUPPORTED_FILTER`, сортировка — `400 INVALID_SORT_FIELD`, а ненулевой `offset` — `400 UNSUPPORTED_OFFSET`. Раньше все три принимались без ошибки и молча игнорировались. Отказ фильтру приходит также на `POST /v1/telephony-lines/search`, `POST /v1/telephony-lines/aggregate` и в подзапросах обоих пакетных запросов. Отказ сортировке и смещению — на `POST /v1/telephony-lines/search` и в подзапросе общего `POST /v1/batch`, агрегат этих параметров не читает. Работают `limit`, он ограничивает количество, и `select`, он выбирает поля в camelCase. Коллекция линий приложения приходит целиком одной страницей, поэтому отбирайте, сортируйте и разбивайте её на страницы на своей стороне. **Все поля ответа — в camelCase**, включая `crmAutoCreate` (boolean). Ранее это поле приходило в UPPER_SNAKE_CASE строкой `"Y"`/`"N"` — с 07.2026 оно нормализовано в camelCase boolean, как и остальные поля. **`serverName` не возвращается.** Поле объявлено в [схеме полей](./fields.md), но в списке не приходит ни при каких условиях — даже если задавалось при создании ([детали](./create.md#известные-особенности)). ## Смотрите также - [Добавить линию](./create.md) - [Обновить линию](./update.md) - [Удалить линию](./delete.md) - [Линии Voximplant](./voximplant.md) - [Исходящие звонки](/docs/telephony/outbound) --- # Telephony Lines: Update ## Обновить линию `PATCH /v1/telephony-lines/:number` Обновляет параметры существующей внешней линии приложения. Идентификатор `number` задаётся при создании и не меняется. Поля передаются плоско в корне JSON — без обёртки `fields`. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `number` (path) | string | да | Идентификатор линии, заданный при создании. Если содержит спецсимволы — URL-кодировать | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `name` | string | нет | Новое отображаемое название линии | | `crmAutoCreate` | boolean | нет | Автосоздание CRM-сущности при исходящем звонке: `true` / `false` | ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/telephony-lines/sip-line-1" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Основная линия (обновлено)" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/telephony-lines/sip-line-1" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Основная линия (обновлено)" }' ``` ### JavaScript — личный ключ ```javascript const number = 'sip-line-1' const res = await fetch( `https://vibecode.bitrix24.tech/v1/telephony-lines/${encodeURIComponent(number)}`, { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Основная линия (обновлено)', }), } ) const { success, data } = await res.json() console.log('Идентификатор линии:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const number = 'sip-line-1' const res = await fetch( `https://vibecode.bitrix24.tech/v1/telephony-lines/${encodeURIComponent(number)}`, { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Основная линия (обновлено)', }), } ) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | string | Идентификатор обновлённой линии (значение `number` из URL) | ## Пример ответа ```json { "success": true, "data": { "id": "sip-line-1" } } ``` ## Пример ответа при ошибке 422 — линия не найдена или ошибка Битрикс24: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "NUMBER should not be empty" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `READONLY_FIELD` | В теле передано поле только для чтения — `serverName` | | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку — текст в `error.message` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `TOKEN_MISSING` | Ключ не имеет настроенных токенов | | 401 | `KEY_INACTIVE` | API-ключ неактивен или отозван | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `telephony` | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Нужно хотя бы одно обновляемое поле.** Распознаются только `name` и `crmAutoCreate`. Тело без них (пустое или только с нераспознанными полями) отвечает `422 «There are no fields to update»`. **`serverName` — только для чтения.** Битрикс24 его не хранит и не возвращает, поэтому запись отклоняется до обращения к Битрикс24: `PATCH` с этим полем отвечает `400 READONLY_FIELD` (раньше — `422 «There are no fields to update»`). Поле остаётся видимым в `GET /v1/telephony-lines/fields` с признаком «только для чтения». **`data.id` — это `number` из URL, не целое число.** В отличие от ответа `POST /v1/telephony-lines`, где `data.id` является внутренним числовым идентификатором записи, ответ обновления возвращает строку — значение `number` из пути запроса. **Изменить `number` через обновление нельзя.** Идентификатор фиксируется при создании. Чтобы сменить `number` — удалите линию и создайте новую с нужным значением. ## Смотрите также - [Список линий приложения](./list.md) - [Добавить линию](./create.md) - [Удалить линию](./delete.md) --- # Telephony Lines: Voximplant ## Линии Voximplant `GET /v1/voximplant-lines` Возвращает список линий, арендованных у Voximplant или подключённых по SIP, которые видит портал. Операции создания, обновления и удаления для этих линий недоступны — только чтение. Идентификаторы из этого списка можно передавать как `fromLine` в исходящих звонках. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/voximplant-lines" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/voximplant-lines" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/voximplant-lines', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log(`Доступно ${data.length} линий`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/voximplant-lines', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив линий | | `data[].id` | string | Идентификатор линии. Префикс `reg` — арендованный у Voximplant номер, `sip` — подключённый SIP-канал | | `data[].name` | string | Отображаемое название | ## Пример ответа ```json { "success": true, "data": [ {"id": "reg133788", "name": "test"}, {"id": "reg150907", "name": "+79179087621"}, {"id": "sip7", "name": "Office PBX 1"}, {"id": "reg151083", "name": "Облачная АТС (9)"}, {"id": "sip11", "name": "Офисная АТС (11)"}, {"id": "reg151085", "name": "SIP line 2"} ] } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'telephony' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `TOKEN_MISSING` | Ключ не имеет настроенных токенов | | 401 | `KEY_INACTIVE` | API-ключ неактивен или отозван | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `telephony` | | 403 | `BITRIX_ACCESS_DENIED` | Скоуп есть, но у владельца ключа нет прав администратора телефонии (управление линиями) в Битрикс24 | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Два типа линий по префиксу `id`.** Идентификаторы `reg` соответствуют номерам, арендованным у Voximplant; `sip` — каналам, подключённым по SIP. Оба типа принимаются в качестве `fromLine` в исходящих звонках. **Источник для исходящих звонков.** В параметр `fromLine` методов [callback](../outbound/callback.md), [auto-call](../outbound/auto-call.md) и [auto-call-audio](../outbound/auto-call-audio.md) можно передавать как `id` из этого списка, так и `number` линии приложения из [`GET /v1/telephony-lines`](./list.md). Выбор зависит от того, через какой тип линии выполняется звонок. **Нужны права администратора телефонии.** Скоупа `telephony` у ключа недостаточно: список линий отдаётся только если у владельца ключа (для `vibe_app_` — у авторизованного пользователя) есть право управления линиями телефонии в Битрикс24. Без него запрос возвращает `403 BITRIX_ACCESS_DENIED`. Право управления линиями телефонии выдаёт администратор портала в настройках телефонии Битрикс24. Та же модель прав распространяется на статистику звонков — без прав администратора телефонии выборка приходит пустой. Это ограничение Битрикс24, а не Вайбкод. ## Смотрите также - [Список линий приложения](./list.md) - [Callback](../outbound/callback.md) - [Автодозвон](../outbound/auto-call.md) - [Автодозвон с аудио](../outbound/auto-call-audio.md) --- # Telephony: Outbound # Исходящие звонки Инициация исходящих звонков через инфраструктуру Voximplant: обратный звонок с соединением оператора и клиента, автоматические информационные звонки с синтезом речи или с воспроизведением аудиофайла. Bitrix24 API: `voximplant.callback.start`, `voximplant.infocall.*` Скоуп: `telephony` ## Операции - [Обратный звонок](./outbound/callback.md) — `POST /v1/calls/callback` - [Автозвонок с синтезом речи](./outbound/auto-call.md) — `POST /v1/calls/auto-call` - [Автозвонок с аудиофайлом](./outbound/auto-call-audio.md) — `POST /v1/calls/auto-call-audio` ## Типовой сценарий 1. Получить список доступных линий: [`GET /v1/voximplant-lines`](./lines/voximplant.md). 2. Выбрать `fromLine` из ответа. 3. Инициировать звонок одним из трёх эндпоинтов выше. 4. После завершения звонка запись появится в [статистике](./analytics/statistics.md) с типом 4 (обратный звонок) или 5 (информационный). ## Смотрите также - [Телефония — обзор](../telephony.md) - [Линии](./lines.md) - [Справочник голосов](./analytics/voices.md) --- # Telephony Outbound: Auto Call ## Запустить автозвонок с синтезом речи `POST /v1/calls/auto-call` Набирает `toNumber` и после принятия звонка воспроизводит синтезированный текст (`textToPronounce`). Оператор не задействован. Применяется для автоматических уведомлений, напоминаний и роботизированных обзвонов. ## Поля запроса (body) | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `fromLine` | string | да | — | ID линии исходящего звонка. Список линий — [`GET /v1/voximplant-lines`](../lines/voximplant.md) | | `toNumber` | string | да | — | Номер телефона в международном формате | | `textToPronounce` | string | да | — | Текст для синтеза речи | | `voice` | string | нет | голос языка портала | ID голоса. Список доступных — [`GET /v1/calls/voices`](../analytics/voices.md) | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/calls/auto-call \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "fromLine": "YOUR_LINE_ID", "toNumber": "+79161234567", "textToPronounce": "Здравствуйте! Ваш заказ готов к выдаче." }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/calls/auto-call \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "fromLine": "YOUR_LINE_ID", "toNumber": "+79161234567", "textToPronounce": "Здравствуйте! Ваш заказ готов к выдаче." }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calls/auto-call', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ fromLine: 'YOUR_LINE_ID', toNumber: '+79161234567', textToPronounce: 'Здравствуйте! Ваш заказ готов к выдаче.', }), }) const { success, data } = await res.json() const callId = data.callId ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calls/auto-call', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ fromLine: 'YOUR_LINE_ID', toNumber: '+79161234567', textToPronounce: 'Здравствуйте! Ваш заказ готов к выдаче.', }), }) const { success, data } = await res.json() const callId = data.callId ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `result` | boolean | `true` при успешном инициировании звонка | | `callId` | string | Идентификатор инициированного звонка с префиксом `infocall.` | ## Пример ответа HTTP 200 — звонок инициирован: ```json { "success": true, "data": { "result": true, "callId": "infocall.a3f2c1e4b8d06f7a9e2c5d1b4f8a3e06.1777974900" } } ``` ## Пример ответа при ошибке 400 — не переданы обязательные параметры: ```json { "success": false, "error": { "code": "MISSING_PARAMS", "message": "Required: fromLine (string — ID from GET /v1/voximplant-lines), toNumber (string), textToPronounce (string)" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_PARAMS` | Не передан `fromLine`, `toNumber` или `textToPronounce` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `TOKEN_MISSING` | Ключ не имеет настроенных токенов Битрикс24 | | 401 | `KEY_INACTIVE` | API-ключ неактивен или отозван | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `telephony` | | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку (сообщение в `error.message`) | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Голос по умолчанию.** Если `voice` не указан, Битрикс24 использует голос, соответствующий языку портала. Для русскоязычных порталов — `ruinternalfemale`. Полный список доступных голосов — [`GET /v1/calls/voices`](../analytics/voices.md). **Превышение месячного лимита.** При исчерпании квоты автозвонков Битрикс24 возвращает `BITRIX_ERROR` с сообщением `"Infocall limit for this month is exceeded"`. Квота обновляется в начале следующего расчётного периода. **Базовая линия не поддерживается.** Попытка использовать базовую линию портала вместо выделенной возвращает `BITRIX_ERROR: "Making infocall using LINK_BASE_NUMBER is not allowed"`. **Запись в статистике.** После завершения звонок появляется в [статистике](../analytics/statistics.md) с `CALL_TYPE: "5"`. ## Смотрите также - [Обратный звонок](./callback.md) - [Автозвонок с аудиофайлом](./auto-call-audio.md) - [Справочник голосов](../analytics/voices.md) - [Статистика звонков](../analytics/statistics.md) - [Список линий Voximplant](../lines/voximplant.md) --- # Telephony Outbound: Auto Call Audio ## Запустить автозвонок с воспроизведением аудиофайла `POST /v1/calls/auto-call-audio` Набирает `toNumber` и после принятия звонка воспроизводит MP3-файл по ссылке `url`. Битрикс24 загружает файл в момент звонка. Оператор не задействован. Применяется для обзвонов с заранее записанным голосовым сообщением. ## Поля запроса (body) | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `fromLine` | string | да | — | ID линии исходящего звонка. Список линий — [`GET /v1/voximplant-lines`](../lines/voximplant.md) | | `toNumber` | string | да | — | Номер телефона в международном формате | | `url` | string | да | — | Прямая HTTPS-ссылка на MP3-файл | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/calls/auto-call-audio \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "fromLine": "YOUR_LINE_ID", "toNumber": "+79161234567", "url": "https://example.com/audio/greeting.mp3" }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/calls/auto-call-audio \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "fromLine": "YOUR_LINE_ID", "toNumber": "+79161234567", "url": "https://example.com/audio/greeting.mp3" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calls/auto-call-audio', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ fromLine: 'YOUR_LINE_ID', toNumber: '+79161234567', url: 'https://example.com/audio/greeting.mp3', }), }) const { success, data } = await res.json() const callId = data.callId ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calls/auto-call-audio', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ fromLine: 'YOUR_LINE_ID', toNumber: '+79161234567', url: 'https://example.com/audio/greeting.mp3', }), }) const { success, data } = await res.json() const callId = data.callId ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `result` | boolean | `true` при успешном инициировании звонка | | `callId` | string | Идентификатор инициированного звонка с префиксом `infocall.` | ## Пример ответа HTTP 200 — звонок инициирован: ```json { "success": true, "data": { "result": true, "callId": "infocall.b7e1d4c2a9f03e8b6d5c2a1f4e9b7d03.1777975100" } } ``` ## Пример ответа при ошибке 400 — не переданы обязательные параметры: ```json { "success": false, "error": { "code": "MISSING_PARAMS", "message": "Required: fromLine (string — ID from GET /v1/voximplant-lines), toNumber (string), url (string — URL to audio file)" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_PARAMS` | Не передан `fromLine`, `toNumber` или `url` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `TOKEN_MISSING` | Ключ не имеет настроенных токенов Битрикс24 | | 401 | `KEY_INACTIVE` | API-ключ неактивен или отозван | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `telephony` | | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку (сообщение в `error.message`) | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Формат и доступность файла.** Файл должен быть в формате MP3 и доступен по прямой HTTPS-ссылке без авторизации. Битрикс24 загружает файл в момент совершения звонка — если ссылка недоступна, возвращается `BITRIX_ERROR`. **Запись в статистике.** После завершения звонок появляется в [статистике](../analytics/statistics.md) с `CALL_TYPE: "5"`. **Ограничения лимита и линии** — те же, что у [автозвонка с синтезом речи](./auto-call.md#известные-особенности): месячная квота и запрет базовой линии. ## Смотрите также - [Обратный звонок](./callback.md) - [Автозвонок с синтезом речи](./auto-call.md) - [Статистика звонков](../analytics/statistics.md) - [Список линий Voximplant](../lines/voximplant.md) --- # Telephony Outbound: Callback ## Инициировать обратный звонок `POST /v1/calls/callback` Инициирует обратный звонок: Битрикс24 сначала звонит на линию оператора (`fromLine`), после принятия звонка соединяет с клиентом (`toNumber`). Применяется для исходящих звонков из CRM без ручного набора номера. ## Поля запроса (body) | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `fromLine` | string | да | — | ID линии оператора. Список линий — [`GET /v1/voximplant-lines`](../lines/voximplant.md) | | `toNumber` | string | да | — | Номер телефона клиента в международном формате | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/calls/callback \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "fromLine": "YOUR_LINE_ID", "toNumber": "+79161234567" }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/calls/callback \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "fromLine": "YOUR_LINE_ID", "toNumber": "+79161234567" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calls/callback', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ fromLine: 'YOUR_LINE_ID', toNumber: '+79161234567', }), }) const { success, data } = await res.json() const callId = data.callId ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calls/callback', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ fromLine: 'YOUR_LINE_ID', toNumber: '+79161234567', }), }) const { success, data } = await res.json() const callId = data.callId ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `result` | boolean | `true` при успешном инициировании звонка | | `callId` | string | Идентификатор инициированного звонка с префиксом `callback.` | ## Пример ответа HTTP 200 — звонок инициирован: ```json { "success": true, "data": { "result": true, "callId": "callback.e7804636435209e12c9cef1ec1bcead1.1777974876" } } ``` ## Пример ответа при ошибке 400 — не переданы обязательные параметры: ```json { "success": false, "error": { "code": "MISSING_PARAMS", "message": "Required: fromLine (string), toNumber (string)" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_PARAMS` | Не передан `fromLine` или `toNumber` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `TOKEN_MISSING` | Ключ не имеет настроенных токенов Битрикс24 | | 401 | `KEY_INACTIVE` | API-ключ неактивен или отозван | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `telephony` | | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку (сообщение в `error.message`) | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Порядок соединения.** Битрикс24 сначала звонит на линию оператора. Звонок клиенту совершается только после того, как оператор принял звонок. Если оператор не отвечает — клиент не будет потревожен. **Префикс `callId`.** Идентификаторы обратных звонков начинаются с `callback.` — в отличие от зарегистрированных звонков (`externalCall.`) и информационных (`infocall.`). **Запись в статистике.** После завершения звонок появляется в [статистике](../analytics/statistics.md) с `CALL_TYPE: "4"`. **Реальные расходы.** Каждый вызов инициирует звонок на номер оператора и тратит средства портала. ## Смотрите также - [Автозвонок с синтезом речи](./auto-call.md) - [Автозвонок с аудиофайлом](./auto-call-audio.md) - [Статистика звонков](../analytics/statistics.md) - [Список линий Voximplant](../lines/voximplant.md) --- # Calls: Followup # Follow-up звонков > **Методы выходят в обновлении `call 26.600.0` и доступны пока не на всех порталах Битрикс24.** Если обновление на ваш портал ещё не пришло, API вернёт `422 METHOD_NOT_YET_AVAILABLE` — это признак того, что метод на портале ещё не выпущен, а не ошибка интеграции. Чтение AI Follow-up завершённых звонков: транскрипция, обзор встречи, краткое изложение, аналитические выводы и оценка эффективности. Методы только читают данные и ничего не изменяют. **Скоуп:** `call` | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` ## Операции - [Список Follow-up](./followup/list.md) — `POST /v1/calls/followups/list` - [Follow-up по одному звонку](./followup/get.md) — `GET /v1/calls/followups/:callId` ## Доступ Нужен скоуп `call`. Он не расширяет видимость данных: внутри метода действует проверка прав на конкретный звонок. Сотрудник видит Follow-up тех звонков, в которых участвовал или состоит в связанном чате — в том числе если его добавили в чат уже после разговора. Администратор портала видит все Follow-up портала. ## Аналитические выводы Разбор участников — `insights.speakerAnalysis`, сильные и слабые стороны встречи, рекомендации — доступен не на каждом портале. Если он недоступен, `insights.speakerEvaluationAvailable` приходит со значением `false`, структура ответа при этом не меняется. ## Типовой сценарий 1. Получить список за период: [`POST /v1/calls/followups/list`](./followup/list.md) с фильтром по дате начала. Из ответа взять `callId` нужного звонка. 2. Запросить полные данные: [`GET /v1/calls/followups/:callId`](./followup/get.md). Если нужны не все блоки, ограничить выдачу параметром `select`. ## Смотрите также - [Звонки](/docs/calls) - [Расшифровка звонка клиенту](/docs/entities/activities/transcript) - [Ошибки](/docs/errors) --- # Calls Followup: Get ## Follow-up по одному звонку > **Метод выходит в обновлении `call 26.600.0` и доступен пока не на всех порталах Битрикс24.** Если обновление на ваш портал ещё не пришло, API вернёт `422 METHOD_NOT_YET_AVAILABLE` — это признак того, что метод на портале ещё не выпущен, а не ошибка интеграции. `GET /v1/calls/followups/:callId` Возвращает AI Follow-up одного завершённого звонка. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `callId` (path) | integer | да | Идентификатор звонка. Положительное целое. Где взять — [`POST /v1/calls/followups/list`](./list.md) | | `select` (query) | string[] | нет | Какие поля вернуть. Передаётся повторяющимся параметром или списком через запятую. Словарь значений общий со списком — раздел «Поле select» страницы [Список Follow-up](./list.md) | | `mentionFormat` (query) | string | нет | Формат `@`-упоминаний в текстовых полях: `bb`, `html` или `none`. По умолчанию — `bb` | ## Поле select | Значение `select` | Что в ответе | |---|---| | Не указан | Полный объект Follow-up. Присутствуют все поля, отсутствующие данные приходят как `null` | | Пустой массив | Только базовые метаданные: `callId`, `callType`, `initiatorId`, `startDate`, `endDate`, `durationSeconds` | | Список полей | Только перечисленные поля и всегда `callId`. Запрошенное, но незаполненное поле приходит как `null` | ## Примеры Запрос без `select` — возвращается весь Follow-up целиком. `mentionFormat: none` убирает разметку упоминаний, поэтому текст готов к передаче в нейросеть или к сохранению в задачу. Чтобы забрать только часть блоков, добавьте `select` — например `?select=overview.actionItems&select=evaluation.efficiencyValue`. ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/calls/followups/12345?mentionFormat=none" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/calls/followups/12345?mentionFormat=none" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const params = new URLSearchParams({ mentionFormat: 'none' }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/calls/followups/12345?${params}`, { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const body = await res.json() if (!body.success) { // Ошибку разбираем явно: иначе на 403 или 422 код упадёт на обращении к data throw new Error(`${body.error.code}: ${body.error.message}`) } const { data } = body const call = data.item // Готовые AI-блоки перечислены в outcomes, неготовые приходят как null console.log(call.outcomes, `${call.durationSeconds} сек`) console.log(call.overview?.topic ?? 'обзор ещё не сформирован') for (const item of call.overview?.actionItems ?? []) { console.log('задача:', item.actionItem, '— цитата:', item.quote) } // speakerAnalysis отсутствует, если разбор участников на портале недоступен for (const speaker of call.insights?.speakerAnalysis ?? []) { console.log(`участник ${speaker.userId}: ${speaker.talkPercentage}% времени, оценка ${speaker.efficiencyValue}`) } // Критерии — карта, ключи зависят от типа встречи: обходим по ключам for (const [code, criterion] of Object.entries(call.evaluation?.criteria ?? {})) { console.log(code, criterion.value ? 'выполнен' : 'не выполнен', '—', criterion.thoughts) } ``` ### JavaScript — OAuth-приложение ```javascript const params = new URLSearchParams({ mentionFormat: 'none' }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/calls/followups/12345?${params}`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const body = await res.json() if (!body.success) { // Ошибку разбираем явно: иначе на 403 или 422 код упадёт на обращении к data throw new Error(`${body.error.code}: ${body.error.message}`) } const { data } = body console.log(data.item) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.item` | object | Follow-up звонка. Поля — в таблице ниже | Поля объекта `item`: | Поле | Тип | Описание | |------|-----|---------| | `item.callId` | number | Идентификатор звонка | | `item.callType` | number | Вид звонка: `1` — мгновенный, `2` — конференция, `3` — большая комната | | `item.initiatorId` | number | Инициатор звонка. Карточка сотрудника — `GET /v1/users/:id` | | `item.startDate` | string | Начало звонка, ISO 8601 в UTC | | `item.endDate` | string \| null | Окончание звонка, ISO 8601 в UTC | | `item.durationSeconds` | number | Длительность звонка в секундах | | `item.uuid` | string | Идентификатор сессии звонка | | `item.language` | string | Код языка транскрипции | | `item.version` | number | Версия схемы AI-данных | | `item.participants` | object[] | Участники звонка | | `item.outcomes` | string[] | Готовые AI-блоки этого звонка | | `item.createdAt` | string | Время последней AI-записи | | `item.tracks` | object[] | Записи звонка | | `item.transcription` | object \| null | Транскрипция разговора | | `item.overview` | object \| null | Обзор встречи | | `item.summary` | object \| null | Краткое изложение по фрагментам | | `item.evaluation` | object \| null | Оценка эффективности встречи | | `item.insights` | object \| null | Аналитические выводы и разбор участников | ### Участники — `participants[]` | Поле | Тип | Описание | |------|-----|---------| | `userId` | number | Идентификатор сотрудника | | `name` | string | Имя сотрудника | | `avatar` | string | Ссылка на аватар | | `workPosition` | string | Должность | | `talkedSeconds` | number | Сколько секунд участник говорил | ### Записи звонка — `tracks[]` | Поле | Тип | Описание | |------|-----|---------| | `trackId` | number | Идентификатор записи | | `type` | string | Вид дорожки, например `mixed_audio` | | `duration` | number | Длительность записи в секундах | | `fileName` | string | Имя файла | | `mimeType` | string | MIME-тип файла | | `url` | string | Ссылка на скачивание | | `dateCreate` | string | Когда запись создана, ISO 8601 | ### Транскрипция — `transcription` | Поле | Тип | Описание | |------|-----|---------| | `language` | string | Код языка расшифровки | | `segments[]` | object[] | Реплики в хронологическом порядке | | `segments[].userId` | number | Кто говорит | | `segments[].userName` | string | Имя говорящего | | `segments[].start` | number | Начало реплики, секунды от начала звонка | | `segments[].end` | number | Конец реплики, секунды от начала звонка | | `segments[].text` | string | Текст реплики | ### Обзор встречи — `overview` | Поле | Тип | Описание | |------|-----|---------| | `topic` | string | Тема встречи | | `detailedTakeaways` | string | Развёрнутые выводы | | `meetingType` | object | Тип встречи: `typeTag` — код, `title` — название, `explanation` — обоснование | | `agenda` | object | Повестка: `explanation` — формулировка, `quote` — цитата из разговора | | `agreements[]` | object[] | Договорённости: `agreement` — формулировка, `quote` — цитата | | `actionItems[]` | object[] | Задачи: `actionItem` — формулировка, `quote` — цитата | | `meetings[]` | object[] | Назначенные встречи: `meeting` — формулировка, `quote` — цитата | ### Краткое изложение — `summary` | Поле | Тип | Описание | |------|-----|---------| | `segments[]` | object[] | Фрагменты разговора | | `segments[].start` | number | Начало фрагмента, секунды | | `segments[].end` | number | Конец фрагмента, секунды | | `segments[].title` | string | Заголовок фрагмента | | `segments[].summary` | string | Изложение фрагмента | ### Аналитические выводы — `insights` | Поле | Тип | Описание | |------|-----|---------| | `speakerEvaluationAvailable` | boolean | Доступен ли разбор участников на портале | | `speakerAnalysis[]` | object[] | Разбор участников, по убыванию `talkPercentage` | | `speakerAnalysis[].userId` | number | Идентификатор сотрудника. Карточка — `GET /v1/users/:id` | | `speakerAnalysis[].detailedInsight` | string | Вывод по участнику | | `speakerAnalysis[].efficiencyValue` | number | Оценка эффективности участника, от 0 до 100 | | `speakerAnalysis[].evaluationCriteria` | string | Критерий, по которому дана оценка | | `speakerAnalysis[].talkPercentage` | number | Доля времени, которую участник говорил, в процентах | | `speakerAnalysis[].duration` | number | Сколько секунд участник говорил | | `speakerAnalysis[].durationFormat` | string | То же время в виде `ММ:СС` | | `meetingStrengths[]` | object[] | Сильные стороны: `strengthTitle` и `strengthExplanation` | | `meetingWeaknesses[]` | object[] | Слабые стороны: `weaknessTitle` и `weaknessExplanation` | | `speechStyleInfluence` | string | Как манера речи повлияла на встречу | | `engagementLevel` | string | Вовлечённость участников | | `areasOfResponsibility` | string | Кто за что отвечает по итогам | | `finalRecommendations` | string | Рекомендации к следующей встрече | ### Оценка эффективности — `evaluation` | Поле | Тип | Описание | |------|-----|---------| | `efficiencyValue` | number | Общая эффективность встречи, от 0 до 100 | | `calendar.overhead` | boolean | Была ли встреча избыточной по времени | | `criteria` | object | Карта критериев. Ключ — код критерия, значение — объект с полями ниже | | `criteria.<код>.value` | boolean | Выполнен ли критерий | | `criteria.<код>.title` | string | Название критерия | | `criteria.<код>.criteria` | string | Формулировка критерия | | `criteria.<код>.thoughts` | string | Обоснование оценки | ## Пример ответа ```json { "success": true, "data": { "item": { "callId": 12345, "callType": 1, "initiatorId": 7, "startDate": "2026-01-15T10:00:00+00:00", "endDate": "2026-01-15T10:42:00+00:00", "durationSeconds": 2520, "uuid": "bb085e5d-5160-4a63-9ac4-152248046c39", "language": "ru", "version": 3, "participants": [ { "userId": 7, "name": "Иван Петров", "workPosition": "Руководитель проекта", "talkedSeconds": 600 } ], "outcomes": ["transcription", "overview", "summary", "insights", "evaluation"], "createdAt": "2026-01-15T11:05:00+00:00", "tracks": [ { "trackId": 100, "type": "mixed_audio", "duration": 2520, "fileName": "call_12345.wav", "mimeType": "audio/wav", "url": "https://example.bitrix24.ru/disk/call_12345.wav", "dateCreate": "2026-01-15T11:00:00+00:00" } ], "transcription": { "language": "ru", "segments": [ { "userId": 7, "userName": "Иван Петров", "start": 12, "end": 25, "text": "Давайте зафиксируем объём спринта. Что берём в работу?" }, { "userId": 42, "userName": "Мария Иванова", "start": 26, "end": 48, "text": "Предлагаю оставить только импорт каталога, остальное не успеем." }, { "userId": 7, "userName": "Иван Петров", "start": 49, "end": 70, "text": "Согласен. Тогда прототип показываем в пятницу." } ] }, "overview": { "topic": "Планирование спринта", "detailedTakeaways": "Команда сократила объём спринта до импорта каталога и договорилась показать прототип в пятницу.", "meetingType": { "typeTag": "planning", "title": "Планирование", "explanation": "Участники распределяли задачи и сроки на ближайшую итерацию." }, "agenda": { "explanation": "Определить объём спринта и сроки демонстрации.", "quote": "Давайте зафиксируем объём спринта." }, "agreements": [ { "agreement": "В спринт берём только импорт каталога", "quote": "Предлагаю оставить только импорт каталога, остальное не успеем." } ], "actionItems": [ { "actionItem": "Подготовить прототип к пятнице", "quote": "Тогда прототип показываем в пятницу." } ], "meetings": [ { "meeting": "Демонстрация прототипа в пятницу", "quote": "Тогда прототип показываем в пятницу." } ] }, "summary": { "segments": [ { "start": 0, "end": 600, "title": "Объём спринта", "summary": "Обсудили, что успеет команда, и сократили набор задач до импорта каталога." }, { "start": 601, "end": 2520, "title": "Сроки и демонстрация", "summary": "Договорились показать прототип в пятницу и вернуться к остальным задачам в следующем спринте." } ] }, "insights": { "speakerEvaluationAvailable": true, "speakerAnalysis": [ { "userId": 42, "detailedInsight": "Участник предложил сократить объём и обосновал это оценкой сроков.", "efficiencyValue": 82, "evaluationCriteria": "Конструктивность предложений", "talkPercentage": 66, "duration": 1200, "durationFormat": "20:00" }, { "userId": 7, "detailedInsight": "Участник вёл встречу и зафиксировал договорённости.", "efficiencyValue": 74, "evaluationCriteria": "Управление обсуждением", "talkPercentage": 34, "duration": 600, "durationFormat": "10:00" } ], "meetingStrengths": [ { "strengthTitle": "Чёткий итог", "strengthExplanation": "Встреча завершилась зафиксированным решением и сроком." } ], "meetingWeaknesses": [ { "weaknessTitle": "Неравное участие", "weaknessExplanation": "Две трети времени говорил один участник." } ], "speechStyleInfluence": "Спокойный темп речи помог быстро прийти к решению.", "engagementLevel": "Высокая вовлечённость обоих участников.", "areasOfResponsibility": "Импорт каталога закреплён за Марией Ивановой.", "finalRecommendations": "Заранее рассылать повестку, чтобы сократить обсуждение объёма." }, "evaluation": { "efficiencyValue": 75, "calendar": { "overhead": false }, "criteria": { "agenda_defined": { "value": true, "criteria": "Повестка обозначена в начале встречи", "title": "Повестка", "thoughts": "Ведущий сформулировал цель первой репликой." }, "decisions_made": { "value": true, "criteria": "Приняты решения по обсуждаемым вопросам", "title": "Решения", "thoughts": "Объём спринта и срок демонстрации зафиксированы." }, "all_participants_involved": { "value": false, "criteria": "Все участники вовлечены в обсуждение", "title": "Вовлечённость", "thoughts": "Распределение реплик — 66 на 34 процента." } } } } } } ``` Ключи в `evaluation.criteria` — коды критериев. Их набор зависит от типа встречи, поэтому обходите карту по ключам, а не по фиксированному списку. ## Пример ответа при ошибке 422 — звонок не найден или его Follow-up недоступен: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Нет доступа к данным Follow-up" } } ``` Текст `error.message` приходит от Битрикс24, поэтому его формулировка и язык зависят от языка портала. Ветвитесь по `error.code`, а не по тексту сообщения. ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `callId` в пути — не положительное целое число. Проверяется до обращения к Битрикс24 | | 400 | `INVALID_PARAMS` | Значение query-параметра вне списка допустимых — например `mentionFormat`. Если Битрикс24 отклонил значение по полю, ответ дополнительно содержит массив `error.validation` с именем поля | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `TOKEN_MISSING` | У ключа нет токенов портала. Ключ OAuth-приложения требует заголовок `Authorization: Bearer` | | 403 | `SCOPE_DENIED` | У ключа нет скоупа `call` | | 403 | `BITRIX_ACCESS_DENIED` | Битрикс24 отказал в доступе. Частый случай — набор скоупов, с которым ключ обращается к порталу, не содержит `call`. Полный разбор причин и что делать по типу ключа — [Ошибки](/docs/errors#bitrix_access_denied-403) | | 422 | `METHOD_NOT_YET_AVAILABLE` | Обновление `call 26.600.0` на портале ещё не выпущено. Ответ содержит поле `error.release` со значением `call 26.600.0` | | 422 | `BITRIX_ERROR` | Запрос отклонён Битрикс24. Звонка с таким `callId` нет либо к его Follow-up нет доступа — сообщение «Нет доступа к данным Follow-up». Причина конкретного отказа — в `error.message` | | 429 | `RATE_LIMITED` | Превышена частота запросов на стороне Битрикс24 | | 429 | `QUEUE_OVERFLOW`, `QUEUE_TIMEOUT` | Очередь запросов портала переполнена или запрос не дождался очереди. Заголовок `Retry-After` подсказывает задержку перед повтором | | 503 | `BITRIX_TIMEOUT` | Битрикс24 принял запрос, но не ответил за 15 секунд. Для чтения повтор безопасен | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Отличить несуществующий звонок от отказа в доступе по ответу нельзя.** Оба случая приходят одинаковым ответом. [Список Follow-up](./list.md) тоже не даёт ответа: в него попадают только звонки с готовым Follow-up и только те, к которым у сотрудника есть доступ, — отсутствие звонка в списке не означает, что звонка нет. **Звонки без AI-обработки.** Если звонок завершён, но Follow-up по нему не сформирован, метод возвращает объект с метаданными: AI-блоки приходят как `null`, а `outcomes` — пустым массивом. **Разбор участников доступен не на каждом портале.** Если на портале он недоступен, блок `insights` приходит с `speakerEvaluationAvailable: false` и пустым разбором участников. Это не ошибка запроса — структура ответа не меняется. **Доступ ограничен правами сотрудника.** Follow-up доступен тому, кто участвовал в звонке или состоит в связанном чате — в том числе если его добавили в чат уже после разговора. Администратор портала видит Follow-up любого звонка портала. ## Смотрите также - [Список Follow-up](/docs/calls/followup/list) - [Follow-up звонков](/docs/calls/followup) - [Звонки](/docs/calls) - [Ошибки](/docs/errors) --- # Calls Followup: List ## Список Follow-up > **Метод выходит в обновлении `call 26.600.0` и доступен пока не на всех порталах Битрикс24.** Если обновление на ваш портал ещё не пришло, API вернёт `422 METHOD_NOT_YET_AVAILABLE` — это признак того, что метод на портале ещё не выпущен, а не ошибка интеграции. `POST /v1/calls/followups/list` Возвращает список AI Follow-up завершённых звонков за указанный период. Навигация по выдаче — курсорная. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `filter` | object | да | Условия выборки. Без этого объекта запрос отклоняется | | `filter.startDate.from` | string | да | Начало периода, ISO 8601 — `2026-01-01T00:00:00Z` | | `filter.startDate.to` | string | да | Конец периода, ISO 8601. Значение раньше `from` отклоняется | | `filter.participantId` | integer | нет | Выборка по одному участнику. Только для администратора портала: рядовому сотруднику фильтр по другому участнику недоступен. Список сотрудников — `GET /v1/users` | | `select` | string[] | нет | Какие поля вернуть. Словарь значений — в разделе «Поле select» | | `order` | object | нет | Сортировка по дате начала: `{ "startDate": "asc" }` или `{ "startDate": "desc" }`. По умолчанию — `desc` | | `pagination` | object | нет | Размер страницы и курсор. Правила — в разделе «Навигация» | | `pagination.limit` | integer | нет | Записей на страницу. По умолчанию 50, максимум 200. При выборе полей с большим объёмом данных максимум снижается до 20 | | `pagination.afterCursor` | object | нет | Курсор следующей страницы. Копируется целиком из `data.afterCursor` предыдущего ответа. В первом запросе не передаётся | | `mentionFormat` | string | нет | Формат `@`-упоминаний в текстовых полях: `bb`, `html` или `none`. По умолчанию — `bb` | ## Поле select Без `select` возвращаются только метаданные звонка. Остальные поля запрашиваются явно. Неизвестное значение отклоняется с `422 BITRIX_ERROR` и сообщением, которое называет отклонённое поле. ### Метаданные | Значение | Что вернётся | |---|---| | `callId`, `callType`, `initiatorId`, `startDate`, `endDate`, `durationSeconds` | Базовые поля. В списке возвращаются всегда | | `uuid` | Идентификатор сессии звонка | | `participants` | Список участников | | `tracks` | Записи звонка со ссылками на скачивание | | `outcomes` | Перечень готовых AI-блоков | | `language` | Язык транскрипции | | `version` | Версия схемы AI-данных | | `createdAt` | Время последней AI-записи | ### AI-блоки Блок запрашивается целиком или отдельным подполем через точку. | Блок | Подполя | |---|---| | `transcription` | `transcription.language`, `transcription.segments` | | `overview` | `overview.topic`, `overview.detailedTakeaways`, `overview.meetingType`, `overview.agenda`, `overview.agreements`, `overview.actionItems`, `overview.meetings` | | `summary` | Запрашивается только целиком | | `insights` | `insights.speakerEvaluationAvailable`, `insights.speakerAnalysis`, `insights.meetingStrengths`, `insights.meetingWeaknesses`, `insights.speechStyleInfluence`, `insights.engagementLevel`, `insights.areasOfResponsibility`, `insights.finalRecommendations` | | `evaluation` | `evaluation.efficiencyValue`, `evaluation.calendar`, `evaluation.criteria` | Правила выбора: - Запрос блока целиком (`["overview"]`) возвращает все его подполя. - Запрос подполя (`["overview.topic"]`) возвращает только это подполе, остальные опускаются. - `transcription`, `transcription.segments`, `overview` и `insights` содержат много данных. Их выбор снижает максимальный размер страницы до 20 записей. ## Навигация 1. Первый запрос отправляется без `pagination.afterCursor`. 2. Если в ответе `hasMore` равно `true`, скопируйте `data.afterCursor` целиком в `pagination.afterCursor` следующего запроса. 3. Повторяйте, пока `hasMore` не станет `false`. `pagination.limit` — по умолчанию 50, максимум 200. При выборе полей с большим объёмом данных максимум снижается до 20. ```jsonc { "pagination": { "limit": 50, "afterCursor": { "startDate": "2026-01-12T14:30:00.000000+00:00", "id": 12330 } } } ``` ## Формат упоминаний `mentionFormat` управляет тем, как выглядят `@`-упоминания сотрудников во всех текстовых AI-полях — `transcription.segments[].text`, `overview.*`, `insights.*`, `evaluation.criteria.*.thoughts`. | Значение | Текст в ответе | Когда выбирать | |---|---|---| | `bb` | `[USER=7]Иван Петров[/USER]` | Вывод в интерфейсе, который понимает BB-код | | `html` | `Иван Петров` | Вывод в вебе | | `none` | `Иван Петров` | Передача текста в нейросеть, поиск, экспорт | ## Примеры Разбор встреч одного сотрудника за январь: берём метаданные звонка, тему, договорённости и задачи из обзора, разбор участников и общую оценку. Сортировка — от новых к старым, упоминания приходят чистым текстом. Это первый запрос, поэтому `afterCursor` в нём нет — курсор для следующей страницы придёт в ответе. ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/calls/followups/list \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "startDate": { "from": "2026-01-01T00:00:00Z", "to": "2026-01-31T23:59:59Z" }, "participantId": 42 }, "select": [ "callId", "startDate", "durationSeconds", "participants", "outcomes", "overview.topic", "overview.agreements", "overview.actionItems", "insights.speakerAnalysis", "evaluation.efficiencyValue" ], "order": { "startDate": "desc" }, "pagination": { "limit": 20 }, "mentionFormat": "none" }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/calls/followups/list \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "startDate": { "from": "2026-01-01T00:00:00Z", "to": "2026-01-31T23:59:59Z" }, "participantId": 42 }, "select": [ "callId", "startDate", "durationSeconds", "participants", "outcomes", "overview.topic", "overview.agreements", "overview.actionItems", "insights.speakerAnalysis", "evaluation.efficiencyValue" ], "order": { "startDate": "desc" }, "pagination": { "limit": 20 }, "mentionFormat": "none" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calls/followups/list', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { startDate: { from: '2026-01-01T00:00:00Z', to: '2026-01-31T23:59:59Z' }, participantId: 42, }, select: [ 'callId', 'startDate', 'durationSeconds', 'participants', 'outcomes', 'overview.topic', 'overview.agreements', 'overview.actionItems', 'insights.speakerAnalysis', 'evaluation.efficiencyValue', ], order: { startDate: 'desc' }, pagination: { limit: 20 }, mentionFormat: 'none', }), }) const body = await res.json() if (!body.success) { // Ошибку разбираем явно: иначе на 403 или 422 код упадёт на обращении к data throw new Error(`${body.error.code}: ${body.error.message}`) } const { data } = body for (const call of data.items) { // AI-блоки готовы не у каждого звонка: у части из них приходит null const topic = call.overview?.topic ?? 'тема не определена' const score = call.evaluation?.efficiencyValue ?? '—' console.log(call.startDate, topic, `оценка: ${score}`) for (const item of call.overview?.actionItems ?? []) { console.log(' задача:', item.actionItem) } } // Следующая страница: курсор из ответа кладём в pagination.afterCursor нового запроса console.log(data.hasMore, data.afterCursor) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/calls/followups/list', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { startDate: { from: '2026-01-01T00:00:00Z', to: '2026-01-31T23:59:59Z' }, participantId: 42, }, select: [ 'callId', 'startDate', 'durationSeconds', 'participants', 'outcomes', 'overview.topic', 'overview.agreements', 'overview.actionItems', 'insights.speakerAnalysis', 'evaluation.efficiencyValue', ], order: { startDate: 'desc' }, pagination: { limit: 20 }, mentionFormat: 'none', }), }) const body = await res.json() if (!body.success) { // Ошибку разбираем явно: иначе на 403 или 422 код упадёт на обращении к data throw new Error(`${body.error.code}: ${body.error.message}`) } const { data } = body console.log(data.items, data.hasMore, data.afterCursor) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.items` | object[] | Массив Follow-up. Поля элемента — в таблице ниже | | `data.hasMore` | boolean | Есть ли записи за пределами текущей страницы | | `data.afterCursor` | object \| null | Курсор следующей страницы. `null` — записей больше нет | Поля элемента массива: | Поле | Тип | Описание | |------|-----|---------| | `items[].callId` | number | Идентификатор звонка. Передаётся в [`GET /v1/calls/followups/:callId`](./get.md) | | `items[].callType` | number | Вид звонка: `1` — мгновенный, `2` — конференция, `3` — большая комната | | `items[].initiatorId` | number | Инициатор звонка. Карточка сотрудника — `GET /v1/users/:id` | | `items[].startDate` | string | Начало звонка, ISO 8601 в UTC | | `items[].endDate` | string \| null | Окончание звонка, ISO 8601 в UTC | | `items[].durationSeconds` | number | Длительность звонка в секундах | | `items[].uuid` | string | Идентификатор сессии звонка | | `items[].language` | string | Код языка транскрипции | | `items[].version` | number | Версия схемы AI-данных | | `items[].participants` | object[] | Участники звонка | | `items[].outcomes` | string[] | Готовые AI-блоки этого звонка | | `items[].createdAt` | string | Время последней AI-записи | | `items[].tracks` | object[] | Записи звонка | | `items[].transcription` | object | Транскрипция разговора | | `items[].overview` | object | Обзор встречи | | `items[].summary` | object | Краткое изложение по фрагментам | | `items[].evaluation` | object | Оценка эффективности встречи | | `items[].insights` | object | Аналитические выводы и разбор участников | ### Участники — `participants[]` | Поле | Тип | Описание | |------|-----|---------| | `userId` | number | Идентификатор сотрудника | | `name` | string | Имя сотрудника | | `avatar` | string | Ссылка на аватар | | `workPosition` | string | Должность | | `talkedSeconds` | number | Сколько секунд участник говорил | ### Записи звонка — `tracks[]` | Поле | Тип | Описание | |------|-----|---------| | `trackId` | number | Идентификатор записи | | `type` | string | Вид дорожки, например `mixed_audio` | | `duration` | number | Длительность записи в секундах | | `fileName` | string | Имя файла | | `mimeType` | string | MIME-тип файла | | `url` | string | Ссылка на скачивание | | `dateCreate` | string | Когда запись создана, ISO 8601 | ### Транскрипция — `transcription` | Поле | Тип | Описание | |------|-----|---------| | `language` | string | Код языка расшифровки | | `segments[]` | object[] | Реплики в хронологическом порядке | | `segments[].userId` | number | Кто говорит | | `segments[].userName` | string | Имя говорящего | | `segments[].start` | number | Начало реплики, секунды от начала звонка | | `segments[].end` | number | Конец реплики, секунды от начала звонка | | `segments[].text` | string | Текст реплики | ### Обзор встречи — `overview` | Поле | Тип | Описание | |------|-----|---------| | `topic` | string | Тема встречи | | `detailedTakeaways` | string | Развёрнутые выводы | | `meetingType` | object | Тип встречи: `typeTag` — код, `title` — название, `explanation` — обоснование | | `agenda` | object | Повестка: `explanation` — формулировка, `quote` — цитата из разговора | | `agreements[]` | object[] | Договорённости: `agreement` — формулировка, `quote` — цитата | | `actionItems[]` | object[] | Задачи: `actionItem` — формулировка, `quote` — цитата | | `meetings[]` | object[] | Назначенные встречи: `meeting` — формулировка, `quote` — цитата | ### Краткое изложение — `summary` | Поле | Тип | Описание | |------|-----|---------| | `segments[]` | object[] | Фрагменты разговора | | `segments[].start` | number | Начало фрагмента, секунды | | `segments[].end` | number | Конец фрагмента, секунды | | `segments[].title` | string | Заголовок фрагмента | | `segments[].summary` | string | Изложение фрагмента | ### Аналитические выводы — `insights` | Поле | Тип | Описание | |------|-----|---------| | `speakerEvaluationAvailable` | boolean | Доступен ли разбор участников на портале | | `speakerAnalysis[]` | object[] | Разбор участников, по убыванию `talkPercentage` | | `speakerAnalysis[].userId` | number | Идентификатор сотрудника. Карточка — `GET /v1/users/:id` | | `speakerAnalysis[].detailedInsight` | string | Вывод по участнику | | `speakerAnalysis[].efficiencyValue` | number | Оценка эффективности участника, от 0 до 100 | | `speakerAnalysis[].evaluationCriteria` | string | Критерий, по которому дана оценка | | `speakerAnalysis[].talkPercentage` | number | Доля времени, которую участник говорил, в процентах | | `speakerAnalysis[].duration` | number | Сколько секунд участник говорил | | `speakerAnalysis[].durationFormat` | string | То же время в виде `ММ:СС` | | `meetingStrengths[]` | object[] | Сильные стороны: `strengthTitle` и `strengthExplanation` | | `meetingWeaknesses[]` | object[] | Слабые стороны: `weaknessTitle` и `weaknessExplanation` | | `speechStyleInfluence` | string | Как манера речи повлияла на встречу | | `engagementLevel` | string | Вовлечённость участников | | `areasOfResponsibility` | string | Кто за что отвечает по итогам | | `finalRecommendations` | string | Рекомендации к следующей встрече | ### Оценка эффективности — `evaluation` | Поле | Тип | Описание | |------|-----|---------| | `efficiencyValue` | number | Общая эффективность встречи, от 0 до 100 | | `calendar.overhead` | boolean | Была ли встреча избыточной по времени | | `criteria` | object | Карта критериев. Ключ — код критерия, значение — объект с полями ниже | | `criteria.<код>.value` | boolean | Выполнен ли критерий | | `criteria.<код>.title` | string | Название критерия | | `criteria.<код>.criteria` | string | Формулировка критерия | | `criteria.<код>.thoughts` | string | Обоснование оценки | ## Пример ответа Ответ на запрос из примеров выше. Базовые поля звонка приходят всегда, а из AI-блоков вернулось ровно то, что перечислено в `select`: внутри `overview` — только тема, договорённости и задачи, внутри `insights` — только разбор участников, внутри `evaluation` — только общая оценка. Упоминания сотрудников идут чистым текстом, потому что запрошен `mentionFormat: "none"`. ```json { "success": true, "data": { "items": [ { "callId": 12345, "callType": 1, "initiatorId": 7, "startDate": "2026-01-15T10:00:00+00:00", "endDate": "2026-01-15T10:42:00+00:00", "durationSeconds": 2520, "participants": [ { "userId": 7, "name": "Иван Петров", "avatar": "https://example.bitrix24.ru/upload/avatar.png", "workPosition": "Руководитель проекта", "talkedSeconds": 600 }, { "userId": 42, "name": "Мария Иванова", "avatar": "https://example.bitrix24.ru/upload/avatar-2.png", "workPosition": "Разработчик", "talkedSeconds": 1200 } ], "outcomes": ["transcription", "overview", "summary", "insights", "evaluation"], "overview": { "topic": "Планирование спринта", "agreements": [ { "agreement": "В спринт берём только импорт каталога", "quote": "Предлагаю оставить только импорт каталога, остальное не успеем." } ], "actionItems": [ { "actionItem": "Подготовить прототип к пятнице", "quote": "Тогда прототип показываем в пятницу." } ] }, "insights": { "speakerAnalysis": [ { "userId": 42, "detailedInsight": "Участник предложил сократить объём и обосновал это оценкой сроков.", "efficiencyValue": 82, "evaluationCriteria": "Конструктивность предложений", "talkPercentage": 66, "duration": 1200, "durationFormat": "20:00" }, { "userId": 7, "detailedInsight": "Участник вёл встречу и зафиксировал договорённости.", "efficiencyValue": 74, "evaluationCriteria": "Управление обсуждением", "talkPercentage": 34, "duration": 600, "durationFormat": "10:00" } ] }, "evaluation": { "efficiencyValue": 75 } }, { "callId": 12318, "callType": 2, "initiatorId": 42, "startDate": "2026-01-12T09:00:00+00:00", "endDate": "2026-01-12T09:25:00+00:00", "durationSeconds": 1500, "participants": [ { "userId": 42, "name": "Мария Иванова", "avatar": "https://example.bitrix24.ru/upload/avatar-2.png", "workPosition": "Разработчик", "talkedSeconds": 900 } ], "outcomes": ["transcription", "overview"], "overview": { "topic": "Разбор обращений за неделю", "agreements": [], "actionItems": [ { "actionItem": "Собрать частые вопросы в базу знаний", "quote": "Давай соберём повторяющиеся вопросы в одну статью." } ] }, "insights": null, "evaluation": null } ], "hasMore": true, "afterCursor": { "startDate": "2026-01-12T09:00:00.000000+00:00", "id": 12318 } } } ``` Второй звонок показывает частый случай: у него готовы не все AI-блоки. В `outcomes` перечислено то, что сформировано, а запрошенные, но отсутствующие блоки приходят как `null` — проверяйте их перед обращением к полям. Как выглядит звонок со всеми заполненными блоками, показано на странице [Follow-up по одному звонку](./get.md). ## Пример ответа при ошибке 400 — в теле запроса нет объекта `filter`: ```json { "success": false, "error": { "code": "MISSING_PARAMS", "message": "Required: filter.startDate.from/to (ISO 8601)" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `MISSING_PARAMS` | В теле запроса нет объекта `filter` | | 400 | `INVALID_PARAMS` | Значение поля запроса вне списка допустимых — например `mentionFormat`. Если Битрикс24 отклонил значение по полю, ответ дополнительно содержит массив `error.validation` с именем поля | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `TOKEN_MISSING` | У ключа нет токенов портала. Ключ OAuth-приложения требует заголовок `Authorization: Bearer` | | 403 | `SCOPE_DENIED` | У ключа нет скоупа `call` | | 403 | `BITRIX_ACCESS_DENIED` | Битрикс24 отказал в доступе. Частый случай — набор скоупов, с которым ключ обращается к порталу, не содержит `call`. Полный разбор причин и что делать по типу ключа — [Ошибки](/docs/errors#bitrix_access_denied-403) | | 422 | `METHOD_NOT_YET_AVAILABLE` | Обновление `call 26.600.0` на портале ещё не выпущено. Ответ содержит поле `error.release` со значением `call 26.600.0` | | 422 | `BITRIX_ERROR` | Запрос отклонён: некорректный диапазон дат, недопустимое поле в `select`, некорректные `pagination` или `order`, нет доступа к данным. Причина — в `error.message` | | 429 | `RATE_LIMITED` | Превышена частота запросов на стороне Битрикс24 | | 429 | `QUEUE_OVERFLOW`, `QUEUE_TIMEOUT` | Очередь запросов портала переполнена или запрос не дождался очереди. Заголовок `Retry-After` подсказывает задержку перед повтором | | 503 | `BITRIX_TIMEOUT` | Битрикс24 принял запрос, но не ответил за 15 секунд. Для чтения повтор безопасен | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Звонки без AI-обработки в список не попадают.** В выдаче только те звонки, по которым Follow-up уже сформирован. Пустой массив `items` означает, что за период таких звонков нет. **Неполный период отклоняется кодом `422`, а не `400`.** Код `400 MISSING_PARAMS` приходит только тогда, когда объекта `filter` нет в теле запроса вовсе. Пропущенный `to` или период, где `from` позже `to`, возвращают `422 BITRIX_ERROR` с описанием причины. **Разбор участников доступен не на каждом портале.** Если на портале он недоступен, блок `insights` приходит с `speakerEvaluationAvailable: false` и пустым разбором участников. Это не ошибка запроса — структура ответа не меняется. **Выдача ограничена правами сотрудника.** Ключ возвращает Follow-up тех звонков, в которых владелец ключа участвовал или состоит в связанном чате. Администратор портала видит все звонки портала. Поэтому один и тот же период у разных сотрудников даёт разные списки. ## Смотрите также - [Follow-up по одному звонку](/docs/calls/followup/get) - [Follow-up звонков](/docs/calls/followup) - [Звонки](/docs/calls) - [Ошибки](/docs/errors) --- # Mail: Conversions # Создание объектов из письма Создание объектов портала на основе входящего письма: задача, событие, чат, пост и привязка к делу CRM. Созданное дело CRM можно удалить. Битрикс24 API: `mail.message.create*`, `mail.message.removecrmactivity` Скоуп: `mail` ## Операции - [Создать задачу](./conversions/task.md) — `POST /v1/mail/messages/:id/task` - [Создать событие](./conversions/calendar-event.md) — `POST /v1/mail/messages/:id/calendar-event` - [Создать чат](./conversions/chat.md) — `POST /v1/mail/messages/:id/chat` - [Создать пост Живой ленты](./conversions/feed-post.md) — `POST /v1/mail/messages/:id/feed-post` - [Создать дело CRM](./conversions/crm-activity-create.md) — `POST /v1/mail/messages/:id/crm-activity` - [Удалить дело CRM](./conversions/crm-activity-delete.md) — `DELETE /v1/mail/messages/:id/crm-activity` ## Смотрите также - [Почта](/docs/mail) --- # Mail Conversions: Calendar Event ## Создать событие из письма `POST /v1/mail/messages/:id/calendar-event` Создаёт событие календаря из письма. Идентификатор письма берётся из пути, тело запроса задаёт поля события. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | integer | да | Идентификатор письма, из которого создаётся событие. Список: `GET /v1/mail/messages` | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|----------| | `dateFrom` | string | да | Дата и время начала события, формат `YYYY-MM-DD HH:MM:SS` | | `dateTo` | string | да | Дата и время окончания события, формат `YYYY-MM-DD HH:MM:SS` | | `name` | string | нет | Название события. По умолчанию — тема письма | | `description` | string | нет | Описание события | ## Примеры ### curl — личный ключ ```bash curl -X POST \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"dateFrom": "2026-06-01 10:00:00", "dateTo": "2026-06-01 11:00:00", "name": "Встреча по запросу"}' \ https://vibecode.bitrix24.tech/v1/mail/messages/123/calendar-event ``` ### curl — OAuth-приложение ```bash curl -X POST \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"dateFrom": "2026-06-01 10:00:00", "dateTo": "2026-06-01 11:00:00", "name": "Встреча по запросу"}' \ https://vibecode.bitrix24.tech/v1/mail/messages/123/calendar-event ``` ### JavaScript — личный ключ ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/mail/messages/123/calendar-event', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ dateFrom: '2026-06-01 10:00:00', dateTo: '2026-06-01 11:00:00', name: 'Встреча по запросу', }), } ) const body = await res.json() if (!body.success) throw new Error(body.error.code) console.log(`Событие создано: ${body.data.eventId}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/mail/messages/123/calendar-event', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ dateFrom: '2026-06-01 10:00:00', dateTo: '2026-06-01 11:00:00', name: 'Встреча по запросу', }), } ) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | `true` при успешном создании | | `data.success` | boolean | Внутренний признак успеха операции | | `data.eventId` | integer | Идентификатор созданного события | | `data.messageId` | integer | Идентификатор письма, из которого создано событие | ## Пример ответа ```json { "success": true, "data": { "success": true, "eventId": 712, "messageId": 123 } } ``` ## Пример ответа при ошибке 400 — не передана дата начала: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "Ошибка при валидации объекта запроса", "validation": [ { "field": "MISSING_DATEFROM", "message": "Parameter \"dateFrom\" is required." } ] } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_PARAMS` | Нечисловой или отрицательный `:id` в пути — сообщение `id must be a positive integer` | | 400 | `INVALID_PARAMS` | Не передан `dateFrom` или `dateTo` — `validation[].field` равен `MISSING_DATEFROM` или `MISSING_DATETO` | | 400 | `INVALID_PARAMS` | Значение `dateFrom` или `dateTo` не в формате `YYYY-MM-DD HH:MM:SS`. Сообщение в массиве `validation` называет отклонённое значение | | 400 | `INVALID_PARAMS` | Письмо удалено или перемещено в другую папку. Причина — в массиве `validation` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный ключ | | 401 | `KEY_INACTIVE` | Ключ деактивирован | | 401 | `KEY_EXPIRED` | Срок действия ключа истёк | | 401 | `TOKEN_MISSING` | Ключ не привязан к порталу Битрикс24 | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `mail` | | 422 | `BITRIX_ERROR` | Прочие ошибки Битрикс24 | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать задачу из письма](./task.md) - [Создать чат из письма](./chat.md) - [Создание объектов из письма](/docs/mail/conversions) - [Почта](/docs/mail) - [Ошибки](/docs/errors) --- # Mail Conversions: Chat ## Создать чат из письма `POST /v1/mail/messages/:id/chat` Создаёт групповой чат из письма. Тело запроса не требуется — идентификатор письма берётся из пути. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | integer | да | Идентификатор письма, из которого создаётся чат. Список: `GET /v1/mail/messages` | ## Примеры ### curl — личный ключ ```bash curl -X POST \ -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/mail/messages/123/chat ``` ### curl — OAuth-приложение ```bash curl -X POST \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ https://vibecode.bitrix24.tech/v1/mail/messages/123/chat ``` ### JavaScript — личный ключ ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/mail/messages/123/chat', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, } ) const body = await res.json() if (!body.success) throw new Error(body.error.code) console.log(`Чат: ${body.data.chatId}, уже существовал: ${body.data.existing}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/mail/messages/123/chat', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, } ) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | `true` при успешном выполнении | | `data.success` | boolean | Внутренний признак успеха операции | | `data.chatId` | integer | Идентификатор чата | | `data.messageId` | integer | Идентификатор письма, из которого создан чат | | `data.existing` | boolean | `true`, если чат уже существовал до этого вызова | ## Пример ответа ```json { "success": true, "data": { "success": true, "chatId": 89, "messageId": 123, "existing": false } } ``` ## Пример ответа при ошибке 400 — письмо не найдено: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "Ошибка при валидации объекта запроса", "validation": [ { "message": "Сообщение удалено или перемещено в другую папку" } ] } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_PARAMS` | Нечисловой или отрицательный `:id` в пути — сообщение `id must be a positive integer` | | 400 | `INVALID_PARAMS` | Письмо удалено или перемещено в другую папку. Причина — в массиве `validation` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный ключ | | 401 | `KEY_INACTIVE` | Ключ деактивирован | | 401 | `KEY_EXPIRED` | Срок действия ключа истёк | | 401 | `TOKEN_MISSING` | Ключ не привязан к порталу Битрикс24 | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `mail` | | 422 | `BITRIX_ERROR` | Прочие ошибки Битрикс24 | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать задачу из письма](./task.md) - [Создать событие из письма](./calendar-event.md) - [Создание объектов из письма](/docs/mail/conversions) - [Почта](/docs/mail) - [Ошибки](/docs/errors) --- # Mail Conversions: Crm Activity Create ## Создать дело CRM из письма `POST /v1/mail/messages/:id/crm-activity` Создаёт дело CRM из письма и привязывает письмо к CRM. Тело запроса не требуется — идентификатор письма берётся из пути. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | integer | да | Идентификатор письма. Список: `GET /v1/mail/messages` | ## Примеры ### curl — личный ключ ```bash curl -X POST \ -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/mail/messages/123/crm-activity ``` ### curl — OAuth-приложение ```bash curl -X POST \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ https://vibecode.bitrix24.tech/v1/mail/messages/123/crm-activity ``` ### JavaScript — личный ключ ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/mail/messages/123/crm-activity', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, } ) const body = await res.json() if (!body.success) throw new Error(body.error.code) console.log(`Дело создано: ${body.data.result}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/mail/messages/123/crm-activity', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, } ) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | `true` при успешном выполнении | | `data.result` | boolean | `true` при успешном создании дела CRM | ## Пример ответа ```json { "success": true, "data": { "result": true } } ``` ## Пример ответа при ошибке 400 — письмо от сотрудника портала: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "Ошибка при валидации объекта запроса", "validation": [ { "message": "Письма сотрудникам не могут быть сохранены в CRM" } ] } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_PARAMS` | Нечисловой или отрицательный `:id` в пути — сообщение `id must be a positive integer` | | 400 | `INVALID_PARAMS` | Письмо от сотрудника портала или письмо удалено. Причина — в массиве `validation` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный ключ | | 401 | `KEY_INACTIVE` | Ключ деактивирован | | 401 | `KEY_EXPIRED` | Срок действия ключа истёк | | 401 | `TOKEN_MISSING` | Ключ не привязан к порталу Битрикс24 | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `mail` | | 422 | `BITRIX_ERROR` | Прочие ошибки Битрикс24 | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - Дело создаётся только для писем от внешних адресатов. - Повторный вызов для письма, у которого дело уже создано, возвращает тот же успешный ответ и второе дело не создаёт — операция идемпотентна. ## Смотрите также - [Удалить дело CRM из письма](./crm-activity-delete.md) - [Создать задачу из письма](./task.md) - [Создать чат из письма](./chat.md) - [Создать пост из письма](./feed-post.md) - [Создание объектов из письма](/docs/mail/conversions) - [Почта](/docs/mail) - [Ошибки](/docs/errors) --- # Mail Conversions: Crm Activity Delete ## Удалить дело CRM из письма `DELETE /v1/mail/messages/:id/crm-activity` Удаляет дело CRM, созданное из письма, и снимает привязку письма к CRM. Тело запроса не требуется — идентификатор письма берётся из пути. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | integer | да | Идентификатор письма. Список: `GET /v1/mail/messages` | ## Примеры ### curl — личный ключ ```bash curl -X DELETE \ -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/mail/messages/123/crm-activity ``` ### curl — OAuth-приложение ```bash curl -X DELETE \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ https://vibecode.bitrix24.tech/v1/mail/messages/123/crm-activity ``` ### JavaScript — личный ключ ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/mail/messages/123/crm-activity', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, } ) const body = await res.json() if (!body.success) throw new Error(body.error.code) console.log(`Дело удалено: ${body.data.result}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/mail/messages/123/crm-activity', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, } ) const body = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | `true` при успешном выполнении | | `data.result` | boolean | `true` при успешном удалении дела CRM | ## Пример ответа ```json { "success": true, "data": { "result": true } } ``` ## Пример ответа при ошибке 400 — письмо не найдено: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "Ошибка при валидации объекта запроса", "validation": [ { "message": "Сообщение удалено или перемещено в другую папку" } ] } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_PARAMS` | Нечисловой или отрицательный `:id` в пути — сообщение `id must be a positive integer` | | 400 | `INVALID_PARAMS` | Письмо удалено или перемещено в другую папку. Причина — в массиве `validation` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный ключ | | 401 | `KEY_INACTIVE` | Ключ деактивирован | | 401 | `KEY_EXPIRED` | Срок действия ключа истёк | | 401 | `TOKEN_MISSING` | Ключ не привязан к порталу Битрикс24 | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `mail` | | 422 | `BITRIX_ERROR` | Прочие ошибки Битрикс24 | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - Повторный вызов для письма, у которого дела CRM нет, возвращает тот же успешный ответ — операция идемпотентна. - Запись CRM, созданная вместе с делом, остаётся на портале — удаляйте её отдельно. ## Смотрите также - [Создать дело CRM из письма](./crm-activity-create.md) - [Создание объектов из письма](/docs/mail/conversions) - [Почта](/docs/mail) - [Ошибки](/docs/errors) --- # Mail Conversions: Feed Post ## Создать пост из письма `POST /v1/mail/messages/:id/feed-post` Создаёт пост в Живой ленте из письма. Идентификатор письма берётся из пути, тело запроса задаёт только поля поста и может быть пустым. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | integer | да | Идентификатор письма, из которого создаётся пост. Список: `GET /v1/mail/messages` | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|----------| | `title` | string | нет | Заголовок поста. По умолчанию — тема письма | ## Примеры ### curl — личный ключ ```bash curl -X POST \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"title": "Обработать запрос клиента"}' \ https://vibecode.bitrix24.tech/v1/mail/messages/123/feed-post ``` ### curl — OAuth-приложение ```bash curl -X POST \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"title": "Обработать запрос клиента"}' \ https://vibecode.bitrix24.tech/v1/mail/messages/123/feed-post ``` ### JavaScript — личный ключ ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/mail/messages/123/feed-post', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Обработать запрос клиента' }), } ) const body = await res.json() if (!body.success) throw new Error(body.error.code) console.log(`Пост создан: ${body.data.postId}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/mail/messages/123/feed-post', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Обработать запрос клиента' }), } ) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | `true` при успешном выполнении | | `data.success` | boolean | Внутренний признак успеха операции | | `data.postId` | integer | Идентификатор созданного поста | | `data.messageId` | integer | Идентификатор письма, из которого создан пост | ## Пример ответа ```json { "success": true, "data": { "success": true, "postId": 3308, "messageId": 123 } } ``` ## Пример ответа при ошибке 400 — письмо не найдено: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "Ошибка при валидации объекта запроса", "validation": [ { "message": "Сообщение удалено или перемещено в другую папку" } ] } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_PARAMS` | Нечисловой или отрицательный `:id` в пути — сообщение `id must be a positive integer` | | 400 | `INVALID_PARAMS` | Письмо удалено или перемещено в другую папку. Причина — в массиве `validation` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный ключ | | 401 | `KEY_INACTIVE` | Ключ деактивирован | | 401 | `KEY_EXPIRED` | Срок действия ключа истёк | | 401 | `TOKEN_MISSING` | Ключ не привязан к порталу Битрикс24 | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `mail` | | 422 | `BITRIX_ERROR` | Прочие ошибки Битрикс24 | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать дело CRM из письма](./crm-activity-create.md) - [Создать задачу из письма](./task.md) - [Создать чат из письма](./chat.md) - [Создание объектов из письма](/docs/mail/conversions) - [Почта](/docs/mail) - [Ошибки](/docs/errors) --- # Mail Conversions: Task ## Создать задачу из письма `POST /v1/mail/messages/:id/task` Создаёт задачу из письма. Идентификатор письма берётся из пути, тело запроса задаёт только поля задачи и может быть пустым. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | integer | да | Идентификатор письма, из которого создаётся задача. Список: `GET /v1/mail/messages` | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|----------| | `title` | string | нет | Заголовок задачи. По умолчанию — тема письма | | `responsibleId` | integer | нет | Идентификатор ответственного. Список: `GET /v1/users`. По умолчанию — текущий пользователь | | `description` | string | нет | Описание задачи | ## Примеры ### curl — личный ключ ```bash curl -X POST \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"title": "Обработать запрос клиента"}' \ https://vibecode.bitrix24.tech/v1/mail/messages/123/task ``` ### curl — OAuth-приложение ```bash curl -X POST \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"title": "Обработать запрос клиента"}' \ https://vibecode.bitrix24.tech/v1/mail/messages/123/task ``` ### JavaScript — личный ключ ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/mail/messages/123/task', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Обработать запрос клиента' }), } ) const body = await res.json() if (!body.success) throw new Error(body.error.code) console.log(`Задача создана: ${body.data.taskId}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/mail/messages/123/task', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Обработать запрос клиента' }), } ) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | `true` при успешном создании | | `data.success` | boolean | Внутренний признак успеха операции | | `data.taskId` | integer | Идентификатор созданной задачи | | `data.messageId` | integer | Идентификатор письма, из которого создана задача | ## Пример ответа ```json { "success": true, "data": { "success": true, "taskId": 4567, "messageId": 123 } } ``` ## Пример ответа при ошибке 400 — письмо не найдено: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "Ошибка при валидации объекта запроса", "validation": [ { "message": "Сообщение удалено или перемещено в другую папку" } ] } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_PARAMS` | Нечисловой или отрицательный `:id` в пути — сообщение `id must be a positive integer` | | 400 | `INVALID_PARAMS` | Письмо удалено или перемещено в другую папку. Причина — в массиве `validation` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный ключ | | 401 | `KEY_INACTIVE` | Ключ деактивирован | | 401 | `KEY_EXPIRED` | Срок действия ключа истёк | | 401 | `TOKEN_MISSING` | Ключ не привязан к порталу Битрикс24 | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `mail` | | 422 | `BITRIX_ERROR` | Прочие ошибки Битрикс24 | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - Задача заполняется только заголовком, ответственным, описанием и привязкой к письму. Если на портале настроены обязательные пользовательские поля задач, создание завершается ошибкой. ## Смотрите также - [Создать событие из письма](./calendar-event.md) - [Создать чат из письма](./chat.md) - [Создание объектов из письма](/docs/mail/conversions) - [Почта](/docs/mail) - [Ошибки](/docs/errors) --- # Mail: Mailboxes # Почтовые ящики Список почтовых ящиков портала и получение сведений об отдельном ящике и его адресах отправителей. Битрикс24 API: `mail.mailbox.*` Скоуп: `mail` ## Операции - [Список ящиков](./mailboxes/list.md) — `GET /v1/mail/mailboxes` - [Получить ящик](./mailboxes/get.md) — `GET /v1/mail/mailboxes/:id` - [Адреса отправителя](./mailboxes/senders.md) — `GET /v1/mail/mailboxes/:id/senders` ## Смотрите также - [Почта](/docs/mail) --- # Mail Mailboxes: Get ## Получить почтовый ящик `GET /v1/mail/mailboxes/:id` Возвращает данные одного почтового ящика по его идентификатору. ## Параметры | Параметр | В | Тип | Обяз. | По умолч. | Описание | |----------|---|-----|:-----:|-----------|----------| | `id` | path | number | да | — | Идентификатор почтового ящика (из [списка ящиков](./list.md)) | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/mail/mailboxes/1" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/mail/mailboxes/1" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/mail/mailboxes/1', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() console.log(data.email) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/mail/mailboxes/1', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Идентификатор ящика | | `data.name` | string | Отображаемое имя ящика | | `data.email` | string | Адрес электронной почты ящика | | `data.senderName` | string | Имя отправителя, подставляемое в поле «От» | ## Пример ответа ```json { "success": true, "data": { "id": 1, "name": "Рабочая почта", "email": "info@example.com", "senderName": "Компания" } } ``` ## Пример ответа при ошибке 404 — ящик не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Запись с ID = `42` не найдена" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_PARAMS` | Нечисловой или отрицательный `:id` в пути — сообщение `id must be a non-negative integer` | | 404 | `ENTITY_NOT_FOUND` | Ящик с указанным ID не найден | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `mail` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Портал Битрикс24 недоступен | | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список почтовых ящиков](./list.md) - [Адреса отправителя ящика](./senders.md) --- # Mail Mailboxes: List ## Список почтовых ящиков `GET /v1/mail/mailboxes` Возвращает список почтовых ящиков, подключённых к порталу. ## Параметры | Параметр | В | Тип | Обяз. | По умолч. | Описание | |----------|---|-----|:-----:|-----------|----------| | `limit` | query | number | нет | `50` | Количество записей на страницу. Максимум — `5000`, большее значение усекается до него | | `offset` | query | number | нет | `0` | Смещение от начала списка | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/mail/mailboxes" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/mail/mailboxes" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/mail/mailboxes', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data, meta } = await res.json() console.log(`Почтовых ящиков: ${meta.total}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/mail/mailboxes', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, meta } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив почтовых ящиков | | `data[].id` | number | Идентификатор ящика | | `data[].name` | string | Отображаемое имя ящика | | `data[].email` | string | Адрес электронной почты ящика | | `data[].senderName` | string | Имя отправителя, подставляемое в поле «От» | | `meta.total` | number | Общее количество ящиков на портале | | `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` | URL любого ящика из массива `data` — его `id`: ``` https://.bitrix24.ru/mail/list// ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. ## Пример ответа ```json { "success": true, "data": [ { "id": 1, "name": "Рабочая почта", "email": "info@example.com", "senderName": "Компания" }, { "id": 2, "name": "Поддержка", "email": "support@example.com", "senderName": "Служба поддержки" } ], "meta": { "total": 2, "hasMore": false } } ``` ## Пример ответа при ошибке 403 — нет скоупа `mail`: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'mail' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `mail` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Портал Битрикс24 недоступен | | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - Список приходит массивом в `data` с пагинацией в `meta` (`total`, `hasMore`); в `GET /v1/mail/messages` письма возвращаются иначе — в `data.items`. ## Смотрите также - [Получить почтовый ящик](./get.md) - [Адреса отправителя ящика](./senders.md) --- # Mail Mailboxes: Senders ## Адреса отправителя ящика `GET /v1/mail/mailboxes/:id/senders` Возвращает список адресов, от имени которых можно отправлять письма из указанного почтового ящика. ## Параметры | Параметр | В | Тип | Обяз. | По умолч. | Описание | |----------|---|-----|:-----:|-----------|----------| | `id` | path | number | да | — | Идентификатор почтового ящика (из [списка ящиков](./list.md)) | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/mail/mailboxes/1/senders" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/mail/mailboxes/1/senders" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/mail/mailboxes/1/senders', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() console.log(data.items) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/mail/mailboxes/1/senders', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data.items` | array | Список адресов отправителя | | `data.items[].email` | string | Адрес электронной почты отправителя | | `data.items[].name` | string | Отображаемое имя отправителя | | `data.items[].sender` | string | Строка для заголовка `From` в формате `"Имя "` | ## Пример ответа ```json { "success": true, "data": { "items": [ { "email": "info@example.com", "name": "Рабочая почта", "sender": "Компания " }, { "email": "support@example.com", "name": "Поддержка", "sender": "Служба поддержки " }, { "email": "sales@example.com", "name": "Отдел продаж", "sender": "Отдел продаж " } ] } } ``` ## Пример ответа при ошибке 400 — нечисловой ID: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "id must be a positive integer" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_PARAMS` | `id` не является положительным целым числом | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `mail` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Портал Битрикс24 недоступен | | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Адреса для отправки.** Вызывайте этот эндпоинт перед составлением письма, чтобы получить список допустимых адресов отправителя и дать пользователю выбрать нужный. ## Смотрите также - [Список почтовых ящиков](./list.md) - [Получить почтовый ящик](./get.md) --- # Mail: Messages # Письма Список, чтение и отправка писем, работа с цепочками переписки, ответы, пересылка и перемещение между папками. Битрикс24 API: `mail.message.*` Скоуп: `mail` ## Операции - [Список писем](./messages/list.md) — `GET /v1/mail/messages` - [Получить письмо](./messages/get.md) — `GET /v1/mail/messages/:id` - [Цепочка переписки](./messages/thread.md) — `GET /v1/mail/messages/:id/thread` - [Отправить письмо](./messages/send.md) — `POST /v1/mail/messages` - [Ответить на письмо](./messages/reply.md) — `POST /v1/mail/messages/:id/reply` - [Переслать письмо](./messages/forward.md) — `POST /v1/mail/messages/:id/forward` - [Переместить письма](./messages/move.md) — `POST /v1/mail/messages/move` ## Смотрите также - [Почта](/docs/mail) --- # Mail Messages: Forward ## Переслать письмо `POST /v1/mail/messages/:id/forward` Пересылает письмо: включает все вложения исходного и цитирует его текст. Сохраняется в папку Отправленные. Пересылаемое письмо задаётся путём. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | integer | да | Идентификатор пересылаемого письма. Список: `GET /v1/mail/messages` | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|----------| | `from` | string | да | Адрес отправителя. Допустимые значения — из `GET /v1/mail/mailboxes/:id/senders` | | `to` | array of strings | да | Адреса получателей | | `subject` | string | да | Тема письма | | `body` | string | да | Текст письма | | `cc` | array of strings | нет | Адреса для копии | | `bcc` | array of strings | нет | Адреса для скрытой копии | ## Примеры ### curl — личный ключ ```bash curl -X POST \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ https://vibecode.bitrix24.tech/v1/mail/messages/1234/forward \ -d '{ "from": "sender@example.com", "to": ["recipient@example.com"], "subject": "Fwd: Тема письма", "body": "Пересылаю письмо" }' ``` ### curl — OAuth-приложение ```bash curl -X POST \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ https://vibecode.bitrix24.tech/v1/mail/messages/1234/forward \ -d '{ "from": "sender@example.com", "to": ["recipient@example.com"], "subject": "Fwd: Тема письма", "body": "Пересылаю письмо" }' ``` ### JavaScript — личный ключ ```javascript const messageId = 1234 const res = await fetch( `https://vibecode.bitrix24.tech/v1/mail/messages/${messageId}/forward`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ from: 'sender@example.com', to: ['recipient@example.com'], subject: 'Fwd: Тема письма', body: 'Пересылаю письмо', }), } ) const data = await res.json() console.log(data.data.to) ``` ### JavaScript — OAuth-приложение ```javascript const messageId = 1234 const res = await fetch( `https://vibecode.bitrix24.tech/v1/mail/messages/${messageId}/forward`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ from: 'sender@example.com', to: ['recipient@example.com'], subject: 'Fwd: Тема письма', body: 'Пересылаю письмо', }), } ) const data = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | `true` при успешном выполнении запроса | | `data.success` | boolean | `true` при успешной пересылке | | `data.to` | array of strings | Список адресов, которым отправлено письмо | ## Пример ответа ```json { "success": true, "data": { "success": true, "to": ["recipient@example.com"] } } ``` ## Пример ответа при ошибке 400 — не переданы получатели: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "Ошибка при валидации объекта запроса", "validation": [ { "field": "MISSING_TO", "message": "Parameter \"to\" is required and must be a non-empty array." } ] } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_PARAMS` | Параметр `id` в пути не является положительным целым числом | | 400 | `INVALID_PARAMS` | Не передан `to` или массив пуст — `validation[].field` равен `MISSING_TO` | | 400 | `INVALID_PARAMS` | Адрес в `from` недоступен пользователю. Допустимые адреса: `GET /v1/mail/mailboxes/:id/senders` | | 400 | `INVALID_PARAMS` | Письмо удалено или перемещено в другую папку. Причина — в массиве `validation` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `mail` | | 401 | `TOKEN_MISSING` | У API-ключа не настроены токены доступа к почтовому ящику | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `KEY_INACTIVE` | API-ключ неактивен | | 401 | `KEY_EXPIRED` | Срок действия API-ключа истёк | | 422 | `BITRIX_ERROR` | Прочие ошибки Битрикс24 | | 429 | `RATE_LIMITED` | Превышен общий лимит запросов платформы | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Отправить письмо](./send.md) - [Ответить на письмо](./reply.md) - [Список писем](./list.md) - [Письма](/docs/mail/messages) - [Почта](/docs/mail) - [Ошибки](/docs/errors) --- # Mail Messages: Get ## Получить письмо `GET /v1/mail/messages/:id` Возвращает одно письмо по идентификатору, включая полный текст сообщения. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|----------| | `id` (path) | number | да | Идентификатор письма. Список: `GET /v1/mail/messages` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/mail/messages/1761" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/mail/messages/1761" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/mail/messages/1761', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success, data } = await res.json() console.log('Тема:', data.item.subject) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/mail/messages/1761', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data.item` | object | Объект письма | | `data.item.id` | number | Идентификатор письма | | `data.item.mailboxId` | number | Идентификатор почтового ящика | | `data.item.mailboxEmail` | string | Адрес почтового ящика | | `data.item.subject` | string | Тема письма | | `data.item.from` | string | Отправитель в формате `Имя <адрес>` | | `data.item.to` | string | Получатель в формате `Имя <адрес>` | | `data.item.cc` | string | Копия письма; пустая строка `""` когда копий нет | | `data.item.date` | string | Дата отправки в формате `YYYY-MM-DD HH:MM:SS` (без часового пояса) | | `data.item.isSeen` | boolean | Прочитано ли письмо | | `data.item.hasAttachments` | boolean | Есть ли вложения | | `data.item.url` | string | Ссылка на письмо в интерфейсе Битрикс24 | | `data.item.bindings` | array | Привязки письма к объектам CRM | | `data.item.body` | string | Полный текст письма с переносами строк (`\r\n`) | ## Пример ответа ```json { "success": true, "data": { "item": { "id": 1761, "mailboxId": 5, "mailboxEmail": "support@example.com", "subject": "Запрос по интеграции", "from": "Поддержка ", "to": "anna@example.com ", "cc": "", "date": "2026-05-18 15:35:10", "isSeen": true, "hasAttachments": false, "url": "https://example.bitrix24.ru/mail/message/1761", "bindings": [], "body": "Здравствуйте! Уточните, пожалуйста, сроки по интеграции.\r\n\r\n-- \r\nС уважением, отдел поддержки" } } } ``` ## Пример ответа при ошибке 404 — письмо не найдено: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Запись с ID = `999999999` не найдена" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_PARAMS` | `id` не является положительным целым числом (сообщение: `id must be a positive integer`) | | 404 | `ENTITY_NOT_FOUND` | Письмо с указанным `id` не найдено | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `mail` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов Битрикс24 | | 429 | `RATE_LIMITED` | Превышен лимит запросов (заголовок `Retry-After: 2`) | | 502 | `BITRIX_UNAVAILABLE` | Портал Битрикс24 вернул ошибку 5xx | | 422 | `BITRIX_ERROR` | Прочие ошибки Битрикс24 | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `KEY_INACTIVE` | API-ключ деактивирован | | 401 | `KEY_EXPIRED` | Срок действия API-ключа истёк | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список писем](./list.md) - [Цепочка переписки](./thread.md) - [Письма](/docs/mail/messages) - [Почта](/docs/mail) - [Ключи и авторизация](/docs/keys-auth) - [Ошибки](/docs/errors) --- # Mail Messages: List ## Список писем `GET /v1/mail/messages` Возвращает список писем подключённых почтовых ящиков с поддержкой фильтров и постраничной загрузки. ## Параметры | Параметр | Тип | По умолч. | Описание | |----------|-----|-----------|----------| | `mailboxId` | number | — | Идентификатор ящика. Список ящиков: `GET /v1/mail/mailboxes` | | `searchQuery` | string | — | Полнотекстовый поиск по письмам | | `folder` | string | — | Имя папки (например, `INBOX`) | | `isSeen` | boolean | — | `true` — только прочитанные, `false` — только непрочитанные | | `hasAttachments` | boolean | — | `true` — только письма с вложениями | | `dateFrom` | string | — | Начало периода, формат ISO 8601 (`2026-05-01T00:00:00+00:00`) | | `dateTo` | string | — | Конец периода, формат ISO 8601 (`2026-05-01T00:00:00+00:00`) | | `limit` | number | `50` | Размер страницы, от 1 до 500 | | `offset` | number | `0` | Смещение от начала списка | При `limit` больше 50 страницы собираются автоматически на стороне сервера, и в ответ добавляется поле `total` — общее число писем, удовлетворяющих фильтру. При `limit` от 1 до 50 возвращается одна страница без поля `total`. Максимум за один запрос — 500 писем. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/mail/messages?mailboxId=5&limit=10" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/mail/messages?mailboxId=5&limit=10" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/mail/messages?mailboxId=5&limit=10', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, } ) const { success, data } = await res.json() console.log(`Писем: ${data.items.length}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/mail/messages?mailboxId=5&limit=10', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, } ) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `total` | number | Общее число писем, удовлетворяющих фильтру. Возвращается при `limit` больше 50 | | `data.items` | array | Массив писем | | `data.items[].id` | number | Идентификатор письма | | `data.items[].mailboxId` | number | Идентификатор почтового ящика | | `data.items[].mailboxEmail` | string | Адрес почтового ящика | | `data.items[].subject` | string | Тема письма | | `data.items[].from` | string | Отправитель в формате `Имя <адрес>` | | `data.items[].to` | string | Получатель в формате `Имя <адрес>` | | `data.items[].cc` | string \| null | Адреса в копии, `null` при отсутствии копий | | `data.items[].date` | string | Дата отправки в формате `YYYY-MM-DD HH:MM:SS` (без часового пояса) | | `data.items[].isSeen` | boolean | Прочитано ли письмо | | `data.items[].hasAttachments` | boolean | Есть ли вложения | | `data.items[].url` | string | Ссылка на письмо в интерфейсе Битрикс24 | | `data.items[].bindings` | array | Привязки письма к объектам Битрикс24. Пустой массив, если письмо ни к чему не привязано | | `data.items[].bindings[].type` | string | Тип привязанного объекта (например, `task`) | | `data.items[].bindings[].entityId` | number | Идентификатор привязанного объекта | | `data.items[].body` | null | Полный текст письма в списке не возвращается (доступен в `GET /v1/mail/messages/:id`) | URL любого письма из массива `data.items` — его `id`: ``` https://.bitrix24.ru/mail/message/?source=mail ``` `` — домен портала. Доступ ограничен правами сотрудника в Битрикс24. В ответе также возвращается готовый URL в поле `data.items[].url`. ## Пример ответа ```json { "success": true, "data": { "items": [ { "id": 1763, "mailboxId": 5, "mailboxEmail": "support@example.com", "subject": "Re: Запрос по интеграции", "from": "Анна Иванова ", "to": "Поддержка ", "cc": null, "date": "2026-05-18 15:35:32", "isSeen": true, "hasAttachments": false, "url": "https://example.bitrix24.ru/mail/message/1763", "bindings": [], "body": null }, { "id": 1761, "mailboxId": 5, "mailboxEmail": "support@example.com", "subject": "Запрос по интеграции", "from": "Поддержка ", "to": "anna@example.com ", "cc": null, "date": "2026-05-18 15:35:10", "isSeen": true, "hasAttachments": false, "url": "https://example.bitrix24.ru/mail/message/1761", "bindings": [], "body": null } ] } } ``` При `limit` больше 50 структура ответа та же, дополнительно приходит поле `total` с общим числом писем, удовлетворяющих фильтру. ## Пример ответа при ошибке 403 — нет скоупа `mail`: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'mail' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `mail` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов Битрикс24 | | 429 | `RATE_LIMITED` | Превышен лимит запросов (заголовок `Retry-After: 2`) | | 502 | `BITRIX_UNAVAILABLE` | Портал Битрикс24 вернул ошибку 5xx | | 422 | `BITRIX_ERROR` | Прочие ошибки Битрикс24 | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `KEY_INACTIVE` | API-ключ деактивирован | | 401 | `KEY_EXPIRED` | Срок действия API-ключа истёк | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить письмо](./get.md) - [Цепочка переписки](./thread.md) - [Письма](/docs/mail/messages) - [Почта](/docs/mail) - [Ключи и авторизация](/docs/keys-auth) - [Ошибки](/docs/errors) --- # Mail Messages: Move ## Переместить письма `POST /v1/mail/messages/move` Выполняет массовое действие над письмами: перемещает в папку, помечает как спам или удаляет. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|----------| | `messageIds` | array of integers | да | Идентификаторы писем | | `action` | string | да | Действие: `move` — переместить в папку, `spam` — пометить как спам, `delete` — удалить | | `folder` | string | условно | Целевая папка. Обязателен при `action: "move"` | ## Примеры ### curl — личный ключ ```bash curl -X POST \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ https://vibecode.bitrix24.tech/v1/mail/messages/move \ -d '{ "messageIds": [1234], "action": "move", "folder": "INBOX" }' ``` ### curl — OAuth-приложение ```bash curl -X POST \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ https://vibecode.bitrix24.tech/v1/mail/messages/move \ -d '{ "messageIds": [1234], "action": "move", "folder": "INBOX" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/mail/messages/move', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ messageIds: [1234], action: 'move', folder: 'INBOX', }), }) const data = await res.json() console.log(data.data.movedCount) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/mail/messages/move', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ messageIds: [1234], action: 'move', folder: 'INBOX', }), }) const data = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | `true` при успешном выполнении запроса | | `data.success` | boolean | `true` при успешном выполнении действия | | `data.movedCount` | integer | Количество обработанных писем | | `data.action` | string | Выполненное действие — `move`, `spam` или `delete` | ## Пример ответа ```json { "success": true, "data": { "success": true, "movedCount": 1, "action": "move" } } ``` ## Пример ответа при ошибке 400 — недопустимое значение `action`: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "Ошибка при валидации объекта запроса", "validation": [ { "field": "INVALID_ACTION", "message": "Parameter \"action\" must be \"move\", \"spam\", or \"delete\"." } ] } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_PARAMS` | Значение `action` не из допустимых — `validation[].field` равен `INVALID_ACTION` | | 400 | `INVALID_PARAMS` | Не передан `messageIds` или `folder` при `action: "move"`. Причина — в массиве `validation` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `mail` | | 401 | `TOKEN_MISSING` | У API-ключа не настроены токены доступа к почтовому ящику | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `KEY_INACTIVE` | API-ключ неактивен | | 401 | `KEY_EXPIRED` | Срок действия API-ключа истёк | | 422 | `BITRIX_ERROR` | Прочие ошибки Битрикс24 | | 429 | `RATE_LIMITED` | Превышен общий лимит запросов платформы | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Действия `spam` и `delete` необратимы.** Пометка как спам и удаление не имеют операции отмены через API. ## Смотрите также - [Отправить письмо](./send.md) - [Ответить на письмо](./reply.md) - [Переслать письмо](./forward.md) - [Список писем](./list.md) - [Письма](/docs/mail/messages) - [Почта](/docs/mail) - [Ошибки](/docs/errors) --- # Mail Messages: Reply ## Ответить на письмо `POST /v1/mail/messages/:id/reply` Отправляет ответ на письмо: добавляет заголовок In-Reply-To, цитирует исходное письмо и переносит вложения. Сохраняется в папку Отправленные. Письмо, на которое отвечаем, задаётся путём. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | integer | да | Идентификатор письма, на которое отвечаем. Список: `GET /v1/mail/messages` | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|----------| | `from` | string | да | Адрес отправителя. Допустимые значения — из `GET /v1/mail/mailboxes/:id/senders` | | `to` | array of strings | да | Адреса получателей | | `subject` | string | да | Тема письма | | `body` | string | да | Текст письма | | `cc` | array of strings | нет | Адреса для копии | | `bcc` | array of strings | нет | Адреса для скрытой копии | ## Примеры ### curl — личный ключ ```bash curl -X POST \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ https://vibecode.bitrix24.tech/v1/mail/messages/1234/reply \ -d '{ "from": "sender@example.com", "to": ["recipient@example.com"], "subject": "Re: Тема письма", "body": "Текст ответа" }' ``` ### curl — OAuth-приложение ```bash curl -X POST \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ https://vibecode.bitrix24.tech/v1/mail/messages/1234/reply \ -d '{ "from": "sender@example.com", "to": ["recipient@example.com"], "subject": "Re: Тема письма", "body": "Текст ответа" }' ``` ### JavaScript — личный ключ ```javascript const messageId = 1234 const res = await fetch( `https://vibecode.bitrix24.tech/v1/mail/messages/${messageId}/reply`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ from: 'sender@example.com', to: ['recipient@example.com'], subject: 'Re: Тема письма', body: 'Текст ответа', }), } ) const data = await res.json() console.log(data.data.to) ``` ### JavaScript — OAuth-приложение ```javascript const messageId = 1234 const res = await fetch( `https://vibecode.bitrix24.tech/v1/mail/messages/${messageId}/reply`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ from: 'sender@example.com', to: ['recipient@example.com'], subject: 'Re: Тема письма', body: 'Текст ответа', }), } ) const data = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | `true` при успешном выполнении запроса | | `data.success` | boolean | `true` при успешной отправке | | `data.to` | array of strings | Список адресов, которым отправлено письмо | ## Пример ответа ```json { "success": true, "data": { "success": true, "to": ["recipient@example.com"] } } ``` ## Пример ответа при ошибке 400 — не переданы получатели: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "Ошибка при валидации объекта запроса", "validation": [ { "field": "MISSING_TO", "message": "Parameter \"to\" is required and must be a non-empty array." } ] } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_PARAMS` | Параметр `id` в пути не является положительным целым числом | | 400 | `INVALID_PARAMS` | Не передан `to` или массив пуст — `validation[].field` равен `MISSING_TO` | | 400 | `INVALID_PARAMS` | Адрес в `from` недоступен пользователю — `validation[].field` равен `MESSAGE_REPLY_FAILED`. Допустимые адреса: `GET /v1/mail/mailboxes/:id/senders` | | 400 | `INVALID_PARAMS` | Письмо удалено или перемещено в другую папку. Причина — в массиве `validation` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `mail` | | 401 | `TOKEN_MISSING` | У API-ключа не настроены токены доступа к почтовому ящику | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `KEY_INACTIVE` | API-ключ неактивен | | 401 | `KEY_EXPIRED` | Срок действия API-ключа истёк | | 422 | `BITRIX_ERROR` | Прочие ошибки Битрикс24 | | 429 | `RATE_LIMITED` | Превышен общий лимит запросов платформы | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Отправить письмо](./send.md) - [Переслать письмо](./forward.md) - [Список писем](./list.md) - [Письма](/docs/mail/messages) - [Почта](/docs/mail) - [Ошибки](/docs/errors) --- # Mail Messages: Send ## Отправить письмо `POST /v1/mail/messages` Отправляет письмо от имени указанного отправителя. Отправленное письмо сохраняется в папку Отправленные почтового ящика. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|----------| | `from` | string | да | Адрес отправителя. Допустимые значения — из `GET /v1/mail/mailboxes/:id/senders` | | `to` | array of strings | да | Адреса получателей | | `subject` | string | да | Тема письма | | `body` | string | да | Текст письма | | `cc` | array of strings | нет | Адреса для копии | | `bcc` | array of strings | нет | Адреса для скрытой копии | ## Примеры ### curl — личный ключ ```bash curl -X POST \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ https://vibecode.bitrix24.tech/v1/mail/messages \ -d '{ "from": "sender@example.com", "to": ["recipient@example.com"], "subject": "Тема письма", "body": "Текст письма" }' ``` ### curl — OAuth-приложение ```bash curl -X POST \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ https://vibecode.bitrix24.tech/v1/mail/messages \ -d '{ "from": "sender@example.com", "to": ["recipient@example.com"], "subject": "Тема письма", "body": "Текст письма" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/mail/messages', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ from: 'sender@example.com', to: ['recipient@example.com'], subject: 'Тема письма', body: 'Текст письма', }), }) const data = await res.json() console.log(data.data.to) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/mail/messages', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ from: 'sender@example.com', to: ['recipient@example.com'], subject: 'Тема письма', body: 'Текст письма', }), }) const data = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | `true` при успешном выполнении запроса | | `data.success` | boolean | `true` при успешной отправке | | `data.to` | array of strings | Список адресов, которым отправлено письмо | ## Пример ответа ```json { "success": true, "data": { "success": true, "to": ["recipient@example.com"] } } ``` ## Пример ответа при ошибке 400 — не переданы получатели: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "Ошибка при валидации объекта запроса", "validation": [ { "field": "MISSING_TO", "message": "Parameter \"to\" is required and must be a non-empty array." } ] } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_PARAMS` | Не передан `to` или массив пуст — `validation[].field` равен `MISSING_TO` | | 400 | `INVALID_PARAMS` | Не передано другое обязательное поле или адрес в `from` недоступен пользователю. Причина — в массиве `validation` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `mail` | | 401 | `TOKEN_MISSING` | У API-ключа не настроены токены доступа к почтовому ящику | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `KEY_INACTIVE` | API-ключ неактивен | | 401 | `KEY_EXPIRED` | Срок действия API-ключа истёк | | 422 | `BITRIX_ERROR` | Прочие ошибки Битрикс24 | | 429 | `RATE_LIMITED` | Превышен общий лимит запросов платформы | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Ответить на письмо](./reply.md) - [Переслать письмо](./forward.md) - [Переместить письма](./move.md) - [Список писем](./list.md) - [Письма](/docs/mail/messages) - [Почта](/docs/mail) - [Ошибки](/docs/errors) --- # Mail Messages: Thread ## Цепочка переписки `GET /v1/mail/messages/:id/thread` Возвращает все письма цепочки переписки, к которой относится указанное письмо. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|----------| | `id` (path) | number | да | Идентификатор любого письма из цепочки. Список: `GET /v1/mail/messages` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/mail/messages/1763/thread" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/mail/messages/1763/thread" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/mail/messages/1763/thread', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, } ) const { success, data } = await res.json() console.log(`Писем в цепочке: ${data.length}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/mail/messages/1763/thread', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, } ) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив писем цепочки, отсортированный по дате | | `data[].id` | number | Идентификатор письма | | `data[].subject` | string | Тема письма | | `data[].from` | string | Отправитель в формате `Имя <адрес>` | | `data[].to` | string | Получатель в формате `Имя <адрес>` | | `data[].cc` | string | Копия письма; пустая строка `""` когда копий нет | | `data[].date` | string | Дата отправки в формате `YYYY-MM-DD HH:MM:SS` (без часового пояса) | | `data[].body` | string | Полный текст письма с переносами строк (`\r\n`) | ## Пример ответа ```json { "success": true, "data": [ { "id": 1761, "subject": "Запрос по интеграции", "from": "Поддержка ", "to": "anna@example.com ", "cc": "", "date": "2026-05-18 15:35:10", "body": "Здравствуйте! Уточните, пожалуйста, сроки по интеграции.\r\n\r\n-- \r\nС уважением, отдел поддержки" }, { "id": 1763, "subject": "Re: Запрос по интеграции", "from": "Анна Иванова ", "to": "Поддержка ", "cc": "", "date": "2026-05-18 15:35:32", "body": "Сроки устроят. Спасибо!" } ] } ``` ## Пример ответа при ошибке 404 — письмо не найдено: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Запись с ID = `999999999` не найдена" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_PARAMS` | `id` не является положительным целым числом (сообщение: `id must be a positive integer`) | | 404 | `ENTITY_NOT_FOUND` | Письмо с указанным `id` не найдено | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `mail` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов Битрикс24 | | 429 | `RATE_LIMITED` | Превышен лимит запросов (заголовок `Retry-After: 2`) | | 502 | `BITRIX_UNAVAILABLE` | Портал Битрикс24 вернул ошибку 5xx | | 422 | `BITRIX_ERROR` | Прочие ошибки Битрикс24 | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `KEY_INACTIVE` | API-ключ деактивирован | | 401 | `KEY_EXPIRED` | Срок действия API-ключа истёк | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **ID любого письма цепочки возвращает полную цепочку.** Запрос с `id` любого участника переписки возвращает одинаковый полный набор писем. ## Смотрите также - [Список писем](./list.md) - [Получить письмо](./get.md) - [Письма](/docs/mail/messages) - [Почта](/docs/mail) - [Ключи и авторизация](/docs/keys-auth) - [Ошибки](/docs/errors) --- # Mail: Recipients # Получатели Поиск контактов CRM и сотрудников портала для использования в качестве получателей исходящих писем. Битрикс24 API: `mail.recipient.*` Скоуп: `mail` ## Операции - [Поиск контактов CRM](./recipients/contacts.md) — `POST /v1/mail/recipients/contacts` - [Поиск сотрудников](./recipients/employees.md) — `POST /v1/mail/recipients/employees` ## Смотрите также - [Почта](/docs/mail) --- # Mail Recipients: Contacts ## Поиск контактов CRM `POST /v1/mail/recipients/contacts` Ищет контакты CRM для подстановки в поле получателей письма. При отсутствии тела запроса или пустом `query` возвращает последние контакты. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|----------| | `query` | string | нет | Строка поиска по имени или адресу электронной почты. При отсутствии или пустом значении возвращаются последние контакты | ## Примеры ### curl — личный ключ ```bash curl -X POST \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "Иванова"}' \ https://vibecode.bitrix24.tech/v1/mail/recipients/contacts ``` ### curl — OAuth-приложение ```bash curl -X POST \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"query": "Иванова"}' \ https://vibecode.bitrix24.tech/v1/mail/recipients/contacts ``` ### JavaScript — личный ключ ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/mail/recipients/contacts', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ query: 'Иванова' }), } ) const body = await res.json() if (!body.success) throw new Error(body.error.code) console.log(body.data.items) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/mail/recipients/contacts', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ query: 'Иванова' }), } ) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | `true` при успешном выполнении | | `data.items` | array | Массив найденных контактов | | `data.items[].id` | number | Идентификатор контакта | | `data.items[].email` | string | Адрес электронной почты | | `data.items[].name` | string | Отображаемое имя контакта | ## Пример ответа ```json { "success": true, "data": { "items": [ { "id": 101, "email": "client@example.com", "name": "Анна Иванова" }, { "id": 102, "email": "sales@example.com", "name": "Отдел продаж" } ] } } ``` ## Пример ответа при ошибке 403 — нет скоупа `mail`: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "This endpoint requires 'mail' scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `mail` | | 401 | `TOKEN_MISSING` | Ключ не привязан к порталу Битрикс24 | | 422 | `BITRIX_ERROR` | Прочие ошибки Битрикс24 | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный ключ | | 401 | `KEY_INACTIVE` | Ключ деактивирован | | 401 | `KEY_EXPIRED` | Срок действия ключа истёк | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Поиск сотрудников портала](./employees.md) - [Получатели](/docs/mail/recipients) - [Почта](/docs/mail) - [Отправить письмо](/docs/mail/messages/send) - [Ключи и авторизация](/docs/keys-auth) - [Ошибки](/docs/errors) --- # Mail Recipients: Employees ## Поиск сотрудников портала `POST /v1/mail/recipients/employees` Ищет сотрудников портала Битрикс24 для подстановки в поле получателей письма. При отсутствии совпадений возвращается пустой массив `items`. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|----------| | `query` | string | **да** | Строка поиска по имени или адресу электронной почты сотрудника. Минимум 1 символ | ## Примеры ### curl — личный ключ ```bash curl -X POST \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "Мен"}' \ https://vibecode.bitrix24.tech/v1/mail/recipients/employees ``` ### curl — OAuth-приложение ```bash curl -X POST \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"query": "Мен"}' \ https://vibecode.bitrix24.tech/v1/mail/recipients/employees ``` ### JavaScript — личный ключ ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/mail/recipients/employees', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ query: 'Мен' }), } ) const body = await res.json() if (!body.success) throw new Error(body.error.code) console.log(body.data.items) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/mail/recipients/employees', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ query: 'Мен' }), } ) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | `true` при успешном выполнении | | `data.items` | array | Массив найденных сотрудников. Пустой массив при отсутствии совпадений | | `data.items[].id` | number | Идентификатор сотрудника | | `data.items[].email` | string | Адрес электронной почты | | `data.items[].name` | string | Отображаемое имя сотрудника | ## Пример ответа ```json { "success": true, "data": { "items": [ { "id": 1, "email": "manager@example.com", "name": "Менеджер" } ] } } ``` ## Пример ответа при ошибке 400 — не передан обязательный `query`: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "Ошибка при валидации объекта запроса", "validation": [ { "field": "MISSING_QUERY", "message": "Parameter \"query\" is required." } ] } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_PARAMS` | Не передан или пустой `query` — `validation[].field` равен `MISSING_QUERY` | | 422 | `BITRIX_ERROR` | Прочие ошибки Битрикс24 | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `mail` | | 401 | `TOKEN_MISSING` | Ключ не привязан к порталу Битрикс24 | | 429 | `RATE_LIMITED` | Превышен лимит запросов | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный ключ | | 401 | `KEY_INACTIVE` | Ключ деактивирован | | 401 | `KEY_EXPIRED` | Срок действия ключа истёк | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Поиск контактов CRM](./contacts.md) - [Получатели](/docs/mail/recipients) - [Почта](/docs/mail) - [Отправить письмо](/docs/mail/messages/send) - [Ключи и авторизация](/docs/keys-auth) - [Ошибки](/docs/errors) --- # Note: Collections # Базы знаний База знаний — контейнер документов в Базе знаний 2.0 Битрикс24. В путях API называется `collection`, в интерфейсе Битрикс24 — базой знаний. Здесь собраны операции создания, чтения, переименования, архивирования и удаления баз знаний, а также получение дерева их документов. **Скоуп:** `note` | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` ## Операции - [Создать базу знаний](./collections/create.md) — `POST /v1/note/collections` - [Список баз знаний](./collections/list.md) — `GET /v1/note/collections` - [Получить базу знаний](./collections/get.md) — `GET /v1/note/collections/:id` - [Переименовать базу знаний](./collections/update.md) — `PATCH /v1/note/collections/:id` - [Архивировать базу знаний](./collections/archive.md) — `POST /v1/note/collections/:id/archive` - [Удалить базу знаний](./collections/delete.md) — `DELETE /v1/note/collections/:id` - [Дерево документов](./collections/tree.md) — `GET /v1/note/collections/:collectionId/documents` ## Смотрите также - [Документы](/docs/note/documents) - [Файлы](/docs/note/files) - [Обзор Базы знаний](/docs/note) --- # Note Collections: Archive ## Архивировать базу знаний `POST /v1/note/collections/:id/archive` Архивирует базу знаний. Каскадно архивирует все её документы — они переходят в режим чтения. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` | integer | да | Идентификатор базы знаний (path-параметр) | Тело запроса пустое. ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/note/collections/42/archive \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/note/collections/42/archive \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/collections/42/archive', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() console.log(data.archived) // true ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/collections/42/archive', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.archived` | boolean | `true` при успешной архивации | ## Пример ответа ```json { "success": true, "data": { "archived": true } } ``` ## Пример ответа при ошибке 404 — база знаний не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Запись с ID = `999999` не найдена" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `id` не положительное целое | | 404 | `ENTITY_NOT_FOUND` | База знаний не существует или уже архивирована | | 403 | `BITRIX_ACCESS_DENIED` | Нет права управления базой знаний | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ в режиме «только чтение» | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `note` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - Документы архивированной базы знаний не возвращаются в [дереве документов](/docs/note/documents). ## Смотрите также - [Удалить базу знаний](./delete.md) - [Документы](/docs/note/documents) - [Обзор Базы знаний](/docs/note) --- # Note Collections: Create ## Создать базу знаний `POST /v1/note/collections` Создаёт базу знаний — контейнер для документов в Базе знаний 2.0 Битрикс24. Тело передаётся плоско, без обёртки `fields`. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `name` | string | да | Название базы знаний | | `position` | integer | нет | Позиция в списке. Сортировка по убыванию значения. По умолчанию `0` — база знаний размещается в начале списка | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/note/collections \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Продуктовая документация", "position": 100 }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/note/collections \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Продуктовая документация", "position": 100 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/collections', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Продуктовая документация', position: 100, }), }) const { success, data } = await res.json() console.log('ID базы знаний:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/collections', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Продуктовая документация', position: 100, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.id` | number | Идентификатор созданной базы знаний | ## Пример ответа ```json { "success": true, "data": { "id": 42 } } ``` ## Пример ответа при ошибке 400 — не передан `name`: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "`name` is required and must be a non-empty string" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Не передан `name`, либо `position` не является неотрицательным целым числом | | 403 | `BITRIX_ACCESS_DENIED` | На портале Битрикс24 нет права создавать базы знаний | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `note` | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ работает в режиме «только чтение» | | 401 | `TOKEN_MISSING` | У ключа нет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Переименовать базу знаний](/docs/note/collections/update) - [Список баз знаний](/docs/note/collections/list) - [Базы знаний](/docs/note/collections) --- # Note Collections: Delete ## Удалить базу знаний `DELETE /v1/note/collections/:id` Перемещает базу знаний и её документы в корзину. Удалить можно и уже архивированную базу знаний. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` | integer | да | Идентификатор базы знаний (path-параметр) | ## Примеры ### curl — личный ключ ```bash curl -X DELETE https://vibecode.bitrix24.tech/v1/note/collections/42 \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE https://vibecode.bitrix24.tech/v1/note/collections/42 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/collections/42', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() console.log(data.deleted) // true ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/collections/42', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) ``` ## Ответ При успешном удалении возвращается `{ deleted: true }` с HTTP-статусом `200`. ## Пример ответа ```json { "success": true, "data": { "deleted": true } } ``` ## Пример ответа при ошибке 404 — база знаний не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Запись с ID = `999999` не найдена" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `id` не положительное целое | | 404 | `ENTITY_NOT_FOUND` | База знаний не существует или уже удалена | | 422 | `BITRIX_ERROR` | По базе знаний идёт фоновый импорт документов — удаление возможно после его завершения. Текст — в `error.message` | | 403 | `BITRIX_ACCESS_DENIED` | Нет права управления базой знаний | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ в режиме «только чтение» | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `note` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - Восстановить базу знаний через API нельзя. Восстановление доступно из корзины в интерфейсе Битрикс24. ## Смотрите также - [Архивировать базу знаний](./archive.md) - [Документы](/docs/note/documents) - [Обзор Базы знаний](/docs/note) --- # Note Collections: Get ## Получить базу знаний `GET /v1/note/collections/:id` Возвращает одну базу знаний по её идентификатору. Используйте, когда известен идентификатор базы знаний и нужны её данные. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор базы знаний. Список: `GET /v1/note/collections` | ## Примеры ### curl — личный ключ ```bash curl https://vibecode.bitrix24.tech/v1/note/collections/9 \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl https://vibecode.bitrix24.tech/v1/note/collections/9 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/collections/9', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() console.log('База знаний:', data) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/collections/9', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Идентификатор базы знаний | | `data.name` | string | Название базы знаний | | `data.position` | number | Числовая позиция базы знаний | | `data.policyLevel` | string | Уровень политики доступа базы знаний, например `none` | | `data.createdBy` | number | Идентификатор сотрудника, создавшего базу знаний. Список: `GET /v1/users` | | `data.createdAt` | string | Дата создания в формате ISO 8601 | | `data.updatedBy` | number | Идентификатор сотрудника, изменившего базу знаний последним. Список: `GET /v1/users` | | `data.updatedAt` | string | Дата последнего изменения в формате ISO 8601 | ## Пример ответа ```json { "success": true, "data": { "id": 9, "name": "Документация продукта", "position": 100, "policyLevel": "none", "createdBy": 1269, "createdAt": "2026-06-23T19:01:03Z", "updatedBy": 1269, "updatedAt": "2026-06-23T19:05:39Z" } } ``` ## Пример ответа при ошибке 404 — база знаний не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Запись с ID = `999999` не найдена" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `id` не является положительным целым числом | | 404 | `ENTITY_NOT_FOUND` | База знаний с указанным `id` не найдена | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `note` | | 401 | `TOKEN_MISSING` | У ключа нет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список баз знаний](/docs/note/collections/list) - [Дерево документов](/docs/note/collections/tree) - [Базы знаний](/docs/note/collections) --- # Note Collections: List ## Список баз знаний `GET /v1/note/collections` Возвращает базы знаний, доступные текущему API-ключу на портале. Поддерживает курсорную пагинацию для обхода больших списков. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `limit` (query) | integer | нет | Размер страницы. По умолчанию 50, от 1 до 200 | | `afterPosition` (query) | integer | нет | Значение `position` из `meta.nextCursor` предыдущего ответа. Передаётся вместе с `afterId` | | `afterId` (query) | integer | нет | Значение `id` из `meta.nextCursor` предыдущего ответа. Передаётся вместе с `afterPosition` | **Пагинация.** Курсорная. `limit` задаёт размер страницы. Для следующей страницы передайте `afterPosition` и `afterId` из `meta.nextCursor` предыдущего ответа. Когда `meta.nextCursor` равен `null`, страниц больше нет. ## Примеры ### curl — личный ключ ```bash curl https://vibecode.bitrix24.tech/v1/note/collections \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl https://vibecode.bitrix24.tech/v1/note/collections \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/collections', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() console.log('Базы знаний:', data) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/collections', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив баз знаний | | `data[].id` | number | Идентификатор базы знаний | | `data[].name` | string | Название базы знаний | | `data[].position` | number | Числовая позиция базы знаний | | `data[].policyLevel` | string | Уровень политики доступа базы знаний, например `none` | | `data[].createdBy` | number | Идентификатор сотрудника, создавшего базу знаний. Список: `GET /v1/users` | | `data[].createdAt` | string | Дата создания в формате ISO 8601 | | `data[].updatedBy` | number | Идентификатор сотрудника, изменившего базу знаний последним. Список: `GET /v1/users` | | `data[].updatedAt` | string | Дата последнего изменения в формате ISO 8601 | | `meta.nextCursor` | object или null | Курсор следующей страницы — объект с полями `position` и `id`. `null`, когда страниц больше нет | ## Пример ответа ```json { "success": true, "data": [ { "id": 1, "name": "Моя компания", "position": 1000, "policyLevel": "none", "createdBy": 0, "createdAt": "2026-05-21T17:36:10Z", "updatedBy": 0, "updatedAt": "2026-05-21T17:36:10Z" }, { "id": 9, "name": "Документация продукта", "position": 100, "policyLevel": "none", "createdBy": 1269, "createdAt": "2026-06-23T19:01:03Z", "updatedBy": 1269, "updatedAt": "2026-06-23T19:05:39Z" }, { "id": 7, "name": "Тест БЗ", "position": 100, "policyLevel": "none", "createdBy": 1269, "createdAt": "2026-06-22T09:16:33Z", "updatedBy": 1269, "updatedAt": "2026-06-22T09:16:33Z" } ], "meta": { "nextCursor": null } } ``` ## Пример ответа при ошибке 400 — некорректный `limit`: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "`limit` must be an integer between 1 and 200" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `limit` вне диапазона от 1 до 200, либо передан только один из `afterPosition` / `afterId` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `note` | | 401 | `TOKEN_MISSING` | У ключа нет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить базу знаний](/docs/note/collections/get) - [Дерево документов](/docs/note/collections/tree) - [Базы знаний](/docs/note/collections) - [Лимиты и оптимизация](/docs/optimization) --- # Note Collections: Tree ## Дерево документов базы знаний `GET /v1/note/collections/:collectionId/documents` Возвращает дерево документов базы знаний: документы верхнего уровня и вложенные в них дочерние документы. Используйте, чтобы обойти структуру базы знаний или получить идентификаторы её документов. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `collectionId` (path) | number | да | Идентификатор базы знаний. Список: `GET /v1/note/collections` | ## Примеры ### curl — личный ключ ```bash curl https://vibecode.bitrix24.tech/v1/note/collections/9/documents \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl https://vibecode.bitrix24.tech/v1/note/collections/9/documents \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/collections/9/documents', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() console.log('Дерево документов:', data) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/collections/9/documents', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Документы верхнего уровня базы знаний | | `data[].id` | number | Идентификатор документа | | `data[].collectionId` | number | Идентификатор базы знаний, которой принадлежит документ. Список: `GET /v1/note/collections` | | `data[].parentId` | number или null | Идентификатор родительского документа. `null` у документа верхнего уровня | | `data[].title` | string | Заголовок документа | | `data[].position` | number | Числовая позиция документа среди соседних | | `data[].children` | array | Вложенные документы той же структуры | | `meta.truncated` | boolean | `true`, если дерево показано не полностью | ## Пример ответа ```json { "success": true, "data": [ { "id": 11, "collectionId": 9, "parentId": null, "title": "Глава 1", "position": 1000, "children": [] } ], "meta": { "truncated": false } } ``` ## Пример ответа при ошибке 404 — база знаний не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Запись с ID = `999999` не найдена" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `collectionId` не является положительным целым числом | | 404 | `ENTITY_NOT_FOUND` | База знаний с указанным `collectionId` не найдена | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `note` | | 401 | `TOKEN_MISSING` | У ключа нет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности Архивные документы в дерево не входят. Возвращаются только активные документы базы знаний. Поле `meta.truncated` приходит `true`, когда дерево достигло внутреннего предела в 5000 узлов. В этом случае показана только часть структуры. ## Смотрите также - [Список баз знаний](/docs/note/collections/list) - [Получить базу знаний](/docs/note/collections/get) - [Документы](/docs/note/documents) - [Базы знаний](/docs/note/collections) --- # Note Collections: Update ## Переименовать базу знаний `PATCH /v1/note/collections/:id` Изменяет название существующей базы знаний. Тело передаётся плоско, без обёртки `fields`. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | integer | да | Идентификатор базы знаний | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `name` | string | да | Новое название базы знаний | ## Примеры ### curl — личный ключ ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/note/collections/42 \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Документация продукта" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/note/collections/42 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Документация продукта" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/collections/42', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Документация продукта', }), }) const { success, data } = await res.json() console.log('Переименовано:', data.updated) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/collections/42', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Документация продукта', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.updated` | boolean | `true` при успешном переименовании | ## Пример ответа ```json { "success": true, "data": { "updated": true } } ``` ## Пример ответа при ошибке 400 — не передан `name`: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "`name` is required and must be a non-empty string" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Не передан `name`, либо `id` не является положительным целым числом | | 404 | `ENTITY_NOT_FOUND` | База знаний не существует, удалена или архивирована | | 403 | `BITRIX_ACCESS_DENIED` | Нет права управлять этой базой знаний | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `note` | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ работает в режиме «только чтение» | | 401 | `TOKEN_MISSING` | У ключа нет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Создать базу знаний](/docs/note/collections/create) - [Список баз знаний](/docs/note/collections/list) - [Базы знаний](/docs/note/collections) --- # Note: Documents # Документы Документы Базы знаний 2.0 — страницы с содержимым в Markdown, организованные в дерево внутри базы знаний. Здесь собраны операции создания, чтения, обновления, архивирования, удаления и полнотекстового поиска документов. **Скоуп:** `note` | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` ## Операции - [Создать документ](./documents/create.md) — `POST /v1/note/documents` - [Получить документ](./documents/get.md) — `GET /v1/note/documents/:id` - [Обновить документ](./documents/update.md) — `PATCH /v1/note/documents/:id` - [Архивировать документ](./documents/archive.md) — `POST /v1/note/documents/:id/archive` - [Удалить документ](./documents/delete.md) — `DELETE /v1/note/documents/:id` - [Поиск документов](./documents/search.md) — `GET /v1/note/documents/search` Список документов одной базы знаний возвращает [Дерево документов](./collections/tree.md) — `GET /v1/note/collections/:collectionId/documents`. Поиск документов принимает и `POST /v1/note/documents/search` с JSON-телом `{ "query": "...", "limit": 20 }` — алиас для агентов, ожидающих поиск POST-запросом. Каноническая форма — GET с query-параметрами, при передаче параметра в обеих формах приоритет у тела. ## Смотрите также - [Базы знаний](/docs/note/collections) - [Файлы](/docs/note/files) - [Обзор Базы знаний](/docs/note) --- # Note Documents: Archive ## Архивировать документ `POST /v1/note/documents/:id/archive` Архивирует документ вместе со всем его поддеревом. Архивные документы доступны для чтения, но не для редактирования. ## Параметры | Параметр | Где | Тип | Обяз. | Описание | |----------|-----|-----|:-----:|---------| | `id` | path | integer | да | Идентификатор корневого документа поддерева | Тело запроса пустое. ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/note/documents/77/archive \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/note/documents/77/archive \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/documents/77/archive', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() console.log(data.archived) // true ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/documents/77/archive', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `data.archived` | boolean | `true` при успешной архивации | ## Пример ответа ```json { "success": true, "data": { "archived": true } } ``` ## Пример ответа при ошибке 404 — документ не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Запись с ID = `999999` не найдена" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `id` не положительное целое | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ доступа работает только на чтение | | 403 | `BITRIX_ACCESS_DENIED` | Нет права редактировать документ | | 404 | `ENTITY_NOT_FOUND` | Документ не существует, в корзине или уже архивирован | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `note` | | 401 | `TOKEN_MISSING` | У ключа не настроены токены | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Архивный документ нельзя обновить.** Вызов [`PATCH /v1/note/documents/:id`](./update.md) на архивном документе возвращает `404 ENTITY_NOT_FOUND`. ## Смотрите также - [Обновить документ](./update.md) - [Удалить документ](./delete.md) - [Документы](/docs/note/documents) --- # Note Documents: Create ## Создать документ `POST /v1/note/documents` Создаёт документ в базе знаний. Непустой `markdown` создаёт документ с готовым содержимым, без него создаётся пустой документ для совместного редактирования. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `collectionId` | integer | да | Идентификатор базы знаний. Список: `GET /v1/note/collections` | | `title` | string | да | Заголовок документа | | `parentId` | integer | нет | Родительский документ для вложенности. Принадлежит той же базе знаний. Дерево документов: `GET /v1/note/collections/:collectionId/documents` | | `markdown` | string | нет | Начальное содержимое в Markdown. Максимум `1 048 576` байт (1 МиБ) | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/note/documents \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "collectionId": 42, "title": "Глава 1", "parentId": 10, "markdown": "# Глава 1\n\nТекст" }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/note/documents \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "collectionId": 42, "title": "Глава 1", "parentId": 10, "markdown": "# Глава 1\n\nТекст" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/documents', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ collectionId: 42, title: 'Глава 1', parentId: 10, markdown: '# Глава 1\n\nТекст', }), }) const { success, data } = await res.json() console.log(data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/documents', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ collectionId: 42, title: 'Глава 1', parentId: 10, markdown: '# Глава 1\n\nТекст', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Идентификатор созданного документа | ## Пример ответа ```json { "success": true, "data": { "id": 77 } } ``` ## Пример ответа при ошибке 400 — не передан обязательный параметр: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "`collectionId` is required and must be a positive integer" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Не передан `collectionId` или `title`, либо параметр неверного типа | | 403 | `BITRIX_ACCESS_DENIED` | Нет права создавать документы в базе знаний | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ в режиме «только чтение» | | 404 | `ENTITY_NOT_FOUND` | База знаний или родительский документ не существуют | | 422 | `BITRIX_ERROR` | `parentId` из другой базы знаний, либо размер `markdown` превышает лимит. Текст ошибки в `error.message` | | 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `note` | | 401 | `TOKEN_MISSING` | У API-ключа не настроены токены | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Обновить документ](/docs/note/documents/update) - [Получить документ](/docs/note/documents/get) - [Базы знаний](/docs/note/collections) - [Обзор Базы знаний](/docs/note) --- # Note Documents: Delete ## Удалить документ `DELETE /v1/note/documents/:id` Перемещает документ вместе со всем его поддеревом в корзину. Восстановить документ через API нельзя — это доступно только в интерфейсе Битрикс24. ## Параметры | Параметр | Где | Тип | Обяз. | Описание | |----------|-----|-----|:-----:|---------| | `id` | path | integer | да | Идентификатор корневого документа поддерева | ## Примеры ### curl — личный ключ ```bash curl -X DELETE https://vibecode.bitrix24.tech/v1/note/documents/77 \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE https://vibecode.bitrix24.tech/v1/note/documents/77 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/documents/77', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() console.log(data.deleted) // true ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/documents/77', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) ``` ## Ответ При успешном удалении возвращается объект `{ deleted: true }`. | Поле | Тип | Описание | |------|-----|---------| | `data.deleted` | boolean | `true` при успешном удалении | ## Пример ответа ```json { "success": true, "data": { "deleted": true } } ``` ## Пример ответа при ошибке 404 — документ не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Запись с ID = `999999` не найдена" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `id` не положительное целое | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ доступа работает только на чтение | | 403 | `BITRIX_ACCESS_DENIED` | Нет права редактировать документ | | 404 | `ENTITY_NOT_FOUND` | Документ не существует или уже в корзине | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `note` | | 401 | `TOKEN_MISSING` | У ключа не настроены токены | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Документ исчезает из выдачи.** После удаления документ пропадает из дерева [`GET /v1/note/collections/:collectionId/documents`](../collections/tree.md) и из результатов поиска [`GET /v1/note/documents/search`](./search.md). ## Смотрите также - [Архивировать документ](./archive.md) - [Создать документ](./create.md) - [Документы](/docs/note/documents) --- # Note Documents: Get ## Получить документ `GET /v1/note/documents/:id` Возвращает один документ базы знаний по его идентификатору. Используйте, чтобы прочитать содержимое конкретного документа. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Идентификатор документа. Список документов базы знаний — `GET /v1/note/collections/:collectionId/documents` | ## Примеры ### curl — личный ключ ```bash curl https://vibecode.bitrix24.tech/v1/note/documents/11 \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl https://vibecode.bitrix24.tech/v1/note/documents/11 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/documents/11', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() console.log('Документ:', data) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/documents/11', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Идентификатор документа | | `data.collectionId` | number | База знаний, которой принадлежит документ. Список: `GET /v1/note/collections` | | `data.parentId` | number или null | Родительский документ в дереве базы знаний. `null` у документа верхнего уровня | | `data.title` | string | Заголовок документа | | `data.markdown` | string | Содержимое документа в разметке Markdown | | `data.position` | number | Порядок сортировки среди соседних документов | | `data.createdBy` | number | Идентификатор создателя. Список: `GET /v1/users` | | `data.updatedBy` | number | Идентификатор автора последнего изменения. Список: `GET /v1/users` | | `data.createdAt` | string | Дата создания в формате ISO 8601 | | `data.updatedAt` | string | Дата последнего изменения в формате ISO 8601 | ## Пример ответа ```json { "success": true, "data": { "id": 11, "collectionId": 9, "parentId": null, "title": "Глава 1", "markdown": "# Глава 1\n\nТекст документа", "position": 1000, "createdBy": 1269, "updatedBy": 1269, "createdAt": "2026-06-23T19:07:29Z", "updatedAt": "2026-06-23T19:07:29Z" } } ``` ## Пример ответа при ошибке 404 — документ не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Запись с ID = `999999` не найдена" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `id` не является положительным целым числом | | 404 | `ENTITY_NOT_FOUND` | Документа с указанным `id` не существует | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `note` | | 401 | `TOKEN_MISSING` | У API-ключа не настроены токены | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Вставки прикреплённых файлов в тексте.** Поле `markdown` может содержать блоки вида `[[image fileId=17]]`, где тип — `image`, `video` или `file`. Так в текст документа встраиваются загруженные к нему файлы. При отображении документа обрабатывайте эти блоки отдельно от остальной разметки Markdown. ## Смотрите также - [Поиск документов](/docs/note/documents/search) - [Обновить документ](/docs/note/documents/update) - [Дерево документов](/docs/note/collections/tree) - [Документы](/docs/note/documents) --- # Note Documents: Search ## Поиск документов `GET /v1/note/documents/search` Выполняет полнотекстовый поиск по заголовкам и содержимому документов из баз знаний, доступных ключу, а также документов, к которым выдан прямой доступ. Используйте, чтобы найти документы по ключевым словам, когда идентификатор заранее неизвестен. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `query` (query) | string | да | Поисковый запрос. Минимум 3 символа, максимум 200 | | `limit` (query) | integer | нет | Количество результатов, от 1 до 200 | ## Примеры ### curl — личный ключ ```bash curl -G https://vibecode.bitrix24.tech/v1/note/documents/search \ --data-urlencode "query=договор" \ --data-urlencode "limit=20" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -G https://vibecode.bitrix24.tech/v1/note/documents/search \ --data-urlencode "query=договор" \ --data-urlencode "limit=20" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const params = new URLSearchParams({ query: 'договор', limit: '20' }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/note/documents/search?${params}`, { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() console.log('Найдено:', data) ``` ### JavaScript — OAuth-приложение ```javascript const params = new URLSearchParams({ query: 'договор', limit: '20' }) const res = await fetch(`https://vibecode.bitrix24.tech/v1/note/documents/search?${params}`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив найденных документов | | `data[].documentId` | number | Идентификатор документа. Получить документ: `GET /v1/note/documents/:id` | | `data[].collectionId` | number | База знаний документа. Список: `GET /v1/note/collections` | | `data[].title` | string | Заголовок документа | | `data[].score` | number | Оценка релевантности совпадения | | `data[].snippet` | string | Фрагмент документа с подсветкой совпадений в формате HTML | | `data[].sharedAccess` | boolean | `true`, если документ доступен по прямому доступу, а не через членство в базе знаний | | `meta.hasMore` | boolean | Есть ли ещё результаты за пределами `limit` | ## Пример ответа ```json { "success": true, "data": [ { "documentId": 11, "collectionId": 9, "title": "Глава 1", "score": 0.0984337329864502, "snippet": "Глава 1\nТекст документа", "sharedAccess": false }, { "documentId": 5, "collectionId": 7, "title": "Глава 1 (обновлено)", "score": 0.0984337329864502, "snippet": "Глава 1\nОбновленный текст", "sharedAccess": false } ], "meta": { "hasMore": false } } ``` ## Пример ответа при ошибке 400 — запрос короче 3 символов: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "`query` must be at least 3 characters" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | `query` отсутствует или короче 3 символов | | 400 | `INVALID_PARAMS` | `limit` вне диапазона от 1 до 200 | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `note` | | 401 | `TOKEN_MISSING` | У API-ключа не настроены токены | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Поле `snippet` содержит HTML.** Фрагмент приходит с HTML-разметкой — совпадения обёрнуты в теги ``, а не в разметку Markdown. Приложение, которое выводит `snippet` в интерфейс, обязано очищать этот HTML от небезопасных конструкций перед отображением. Иначе через содержимое документа возможно внедрение стороннего кода в страницу (XSS). ## Смотрите также - [Получить документ](/docs/note/documents/get) - [Дерево документов](/docs/note/collections/tree) - [Документы](/docs/note/documents) --- # Note Documents: Update ## Обновить документ `PATCH /v1/note/documents/:id` Обновляет заголовок и/или содержимое документа. Передача `markdown` полностью заменяет текущее содержимое. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | integer | да | Идентификатор документа | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `title` | string | да¹ | Новый заголовок документа | | `markdown` | string | да¹ | Новое содержимое в Markdown. Полностью заменяет текущее. Максимум `1 048 576` байт (1 МиБ) | | `overwrite` | boolean | нет | Переписать содержимое при несохранённых изменениях. По умолчанию `false` | ¹ Хотя бы одно из полей `title` или `markdown` обязано присутствовать. ## Примеры ### curl — личный ключ ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/note/documents/77 \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Глава 1 (ред.)", "markdown": "# Глава 1\n\nОбновлённый текст", "overwrite": false }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/note/documents/77 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Глава 1 (ред.)", "markdown": "# Глава 1\n\nОбновлённый текст", "overwrite": false }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/documents/77', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Глава 1 (ред.)', markdown: '# Глава 1\n\nОбновлённый текст', overwrite: false, }), }) const { success, data } = await res.json() console.log(data.updated) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/documents/77', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Глава 1 (ред.)', markdown: '# Глава 1\n\nОбновлённый текст', overwrite: false, }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.updated` | boolean | `true` при успешном обновлении | ## Пример ответа ```json { "success": true, "data": { "updated": true } } ``` ## Пример ответа при ошибке 400 — не передано ни одного изменяемого поля: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "at least one of `title` or `markdown` must be provided" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Не передан ни `title`, ни `markdown`, либо `id` неверного типа | | 403 | `BITRIX_ACCESS_DENIED` | Нет права редактировать документ | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ в режиме «только чтение» | | 404 | `ENTITY_NOT_FOUND` | Документ не существует, архивный или в корзине | | 422 | `BITRIX_ERROR` | Есть несохранённые изменения и передан `overwrite: false`, либо размер `markdown` превышает лимит. Текст ошибки в `error.message` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `note` | | 401 | `TOKEN_MISSING` | У API-ключа не настроены токены | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Разрешение конфликта совместного редактирования.** Если у документа остались несохранённые изменения совместного редактора, запрос с `overwrite: false` содержимое не перезаписывает и возвращает `422 BITRIX_ERROR`. Повторный запрос с `overwrite: true` записывает `markdown` поверх несохранённых изменений. ## Смотрите также - [Создать документ](/docs/note/documents/create) - [Получить документ](/docs/note/documents/get) - [Базы знаний](/docs/note/collections) - [Обзор Базы знаний](/docs/note) --- # Note: Files # Файлы Вложения к документам Базы знаний 2.0. Файл добавляется в два шага: сначала [загрузка](./files/upload.md) сохраняет содержимое и привязывает файл к документу, затем [получение метаданных](./files/get.md) возвращает готовый фрагмент `assetMarkdown` для вставки в содержимое документа через `PATCH /v1/note/documents/:id`. **Скоуп:** `note` | **Базовый URL:** `https://vibecode.bitrix24.tech/v1` | **Авторизация:** `X-Api-Key` ## Операции - [Загрузить файл](./files/upload.md) — `POST /v1/note/documents/:documentId/files` - [Получить метаданные файла](./files/get.md) — `GET /v1/note/documents/:documentId/files/:id` ## Типовой сценарий 1. Создать документ: `POST /v1/note/documents`. 2. Загрузить файл: `POST /v1/note/documents/:documentId/files` — запомнить `id` из ответа. 3. Получить фрагмент для вставки: `GET /v1/note/documents/:documentId/files/:id` — взять `assetMarkdown`. 4. Вставить фрагмент в содержимое: `PATCH /v1/note/documents/:id` с обновлённым `markdown`. Полный пример с curl — [Обзор Базы знаний](/docs/note). ## Смотрите также - [Базы знаний](/docs/note/collections) - [Документы](/docs/note/documents) - [Обзор Базы знаний](/docs/note) --- # Note Files: Get ## Получить метаданные файла `GET /v1/note/documents/:documentId/files/:id` Возвращает метаданные файла и готовый фрагмент разметки для вставки вложения в содержимое документа. Доступно и ключу в режиме «только чтение». ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `documentId` (path) | integer | да | Документ, к которому привязан файл. Идентификатор — из [`POST /v1/note/documents`](/docs/note/documents) | | `id` (path) | integer | да | Идентификатор файла. Возвращается из [`POST /v1/note/documents/:documentId/files`](./upload.md) | ## Примеры ### curl — личный ключ ```bash curl https://vibecode.bitrix24.tech/v1/note/documents/77/files/5001 \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl https://vibecode.bitrix24.tech/v1/note/documents/77/files/5001 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/documents/77/files/5001', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log(data.assetMarkdown) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/documents/77/files/5001', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Идентификатор файла | | `data.documentId` | number | Документ, к которому привязан файл | | `data.name` | string | Оригинальное имя файла | | `data.size` | number | Размер файла в байтах | | `data.mimeType` | string | Тип содержимого файла в формате MIME, определённый при сохранении | | `data.assetType` | string | Категория вложения: `image`, `video` или `file` | | `data.assetMarkdown` | string | Готовый фрагмент `[[ fileId=]]` для вставки в содержимое | ## Пример ответа ```json { "success": true, "data": { "id": 5001, "documentId": 77, "name": "diagram.png", "size": 6321, "mimeType": "image/png", "assetType": "image", "assetMarkdown": "[[image fileId=5001]]" } } ``` ## Пример ответа при ошибке 404 — документ или файл не найдены: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Запись с ID = `999999` не найдена" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Не передан `documentId` или `id`, либо параметр неверного типа | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `note` | | 404 | `ENTITY_NOT_FOUND` | Документ или файл не существуют, нет доступа, либо файл не привязан к документу | | 401 | `TOKEN_MISSING` | У ключа нет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Формат `assetMarkdown` и вставка вложения.** Чтобы вложение появилось в документе, добавьте `assetMarkdown` отдельной строкой в `markdown` и вызовите [`PATCH /v1/note/documents/:id`](/docs/note/documents). Фрагмент должен начинаться с начала строки, без других символов в той же строке. Тип пишется в нижнем регистре, `fileId` — целое положительное число. ## Смотрите также - [Загрузить файл](/docs/note/files/upload) - [Документы](/docs/note/documents) - [Файлы](/docs/note/files) - [Обзор Базы знаний](/docs/note) --- # Note Files: Upload ## Загрузить файл `POST /v1/note/documents/:documentId/files` Сохраняет содержимое файла в Base64 и привязывает его к документу Базы знаний. Сам файл в содержимое документа не вставляется — чтобы вложение появилось в тексте, вставьте в него `assetMarkdown` и сохраните документ через [`PATCH /v1/note/documents/:id`](/docs/note/documents). Готовый `assetMarkdown` приходит уже в ответе на загрузку, второй запрос за ним не нужен; [`GET /v1/note/documents/:documentId/files/:id`](./get.md) отдаёт тот же объект позже. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `documentId` (path) | integer | да | Документ, к которому привязывается файл. Идентификатор — из [`POST /v1/note/documents`](/docs/note/documents) | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `fileName` | string | да | Имя файла с расширением. Расширение определяет тип вложения | | `fileContent` | string | да | Содержимое файла, закодированное в Base64 | Размер запроса ограничен 40 МБ. Точный лимит размера файла задаёт Битрикс24 и проверяет на своей стороне. ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/note/documents/77/files \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "fileName": "diagram.png", "fileContent": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/note/documents/77/files \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "fileName": "diagram.png", "fileContent": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/documents/77/files', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ fileName: 'diagram.png', fileContent: base64Content }), }) const { success, data } = await res.json() console.log(data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/note/documents/77/files', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ fileName: 'diagram.png', fileContent: base64Content }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | Идентификатор загруженного файла, он же `fileId`. Передаётся в [`GET /v1/note/documents/:documentId/files/:id`](./get.md) | | `data.documentId` | number | Документ, к которому привязан файл | | `data.name` | string | Оригинальное имя файла | | `data.size` | number | Размер файла в байтах | | `data.mimeType` | string | Тип содержимого файла в формате MIME, определённый при сохранении | | `data.assetType` | string | Категория вложения: `image`, `video` или `file` | | `data.assetMarkdown` | string | Готовый фрагмент `[[ fileId=]]` для вставки в содержимое | Ответ повторяет форму [`GET /v1/note/documents/:documentId/files/:id`](./get.md). Поля приходят от Битрикс24 как есть: если портал какое-то из них не вернул, платформа его не достраивает, а `data.id` присутствует всегда. ## Пример ответа ```json { "success": true, "data": { "id": 5001, "documentId": 77, "name": "diagram.png", "size": 6321, "mimeType": "image/png", "assetType": "image", "assetMarkdown": "[[image fileId=5001]]" } } ``` ## Пример ответа при ошибке 404 — документ не найден: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "Запись с ID = `999999` не найдена" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Не передан `fileName` или `fileContent`, либо `documentId` неверного типа | | 403 | `BITRIX_ACCESS_DENIED` | Нет права редактировать документ | | 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ в режиме «только чтение» | | 404 | `ENTITY_NOT_FOUND` | Документ не существует, архивный или в корзине | | 413 | — | Размер запроса превышает 40 МБ | | 422 | `BITRIX_ERROR` | Размер файла превышает лимит, тип файла не разрешён, либо повреждён Base64. Текст в `error.message` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `note` | | 401 | `TOKEN_MISSING` | У ключа нет настроенных токенов | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Получить метаданные файла](/docs/note/files/get) - [Документы](/docs/note/documents) - [Файлы](/docs/note/files) - [Обзор Базы знаний](/docs/note) --- # Search: Credentials # Свои ключи (BYOK) Управление личными ключами для платных движков веб-поиска. После добавления своего ключа последующие вызовы [`POST /v1/search`](/docs/search/run) и [`POST /v1/research`](/docs/search/research) с этим провайдером не списывают Ꝟ — оплата идёт напрямую с вашего аккаунта у поставщика. Раздел поддерживает восемь BYOK-провайдеров: `tavily`, `brave`, `exa`, `you-com`, `linkup`, `perplexity`, `jina`, `z-ai`. Платформенный `bitrix-search` через эти эндпоинты не настраивается — токен выпускает платформа централизованно. Скоуп: `vibe:search` ## Операции - [Список своих ключей](./credentials/list.md) — `GET /v1/search/credentials` - [Добавить ключ](./credentials/create.md) — `POST /v1/search/credentials` - [Удалить ключ](./credentials/delete.md) — `DELETE /v1/search/credentials/:id` - [Проверить ключ](./credentials/test.md) — `POST /v1/search/credentials/:id/test` ## Типовой сценарий 1. Получить токен у выбранного провайдера: например, `tvly-…` в [личном кабинете Tavily](https://tavily.com), токен подписки в [Brave Search API](https://brave.com/search/api/) или ключ в кабинете Exa, You.com, Linkup, Perplexity, Jina, Z.AI. 2. Добавить ключ через [`POST /v1/search/credentials`](./credentials/create.md) с `isDefault: true`. Сервер проверяет ключ у провайдера и сохраняет запись только при успешной проверке. 3. Запросы [`POST /v1/search`](/docs/search/run) и [`POST /v1/research`](/docs/search/research) без поля `provider` теперь идут через ваш дефолтный BYOK-ключ. 4. Если ключ был отозван у провайдера — повторный вызов [`POST /v1/search/credentials/:id/test`](./credentials/test.md) обновит статус, поле `lastError` зафиксирует причину. ## Известные особенности **Восемь BYOK-провайдеров.** Платформенный `bitrix-search` не принимает пользовательские ключи — токен выпускает платформа централизованно. При попытке передать `provider: "bitrix-search"` приходит `400 INVALID_REQUEST` с сообщением `Expected 'tavily' | 'brave' | 'exa' | 'you-com' | 'linkup' | 'perplexity' | 'jina' | 'z-ai'`. **Корректность ключа проверяется при создании.** Сервер делает пробный вызов к провайдеру до сохранения записи. Если ключ отклонён — возвращается `400 INVALID_CREDENTIAL` с сообщением провайдера, запись не создаётся. Это закрывает класс ошибок «дефолтным выбран ключ, который провайдер уже отозвал». **Один дефолтный ключ на провайдер.** При добавлении нового ключа с `isDefault: true` предыдущий дефолтный ключ того же провайдера автоматически перестаёт быть дефолтным. **Ротация токена — через удаление и создание.** Отдельного `PATCH` для обновления токена нет. Чтобы заменить ключ — сначала [`POST /v1/search/credentials`](./credentials/create.md) с новым токеном (с `isDefault: true`, если старый был дефолтным), затем [`DELETE /v1/search/credentials/:id`](./credentials/delete.md) для прежнего. **Скоуп USER.** Через v1-эндпоинты добавляется только USER-ключ — он действует для запросов конкретного пользователя. **OAuth-приложения требуют Bearer.** При вызове через ключ `vibe_app_…` нужен заголовок `Authorization: Bearer ` — без него сервер возвращает `401 UNAUTHORIZED`. Подробнее в [Ключи и авторизация](/docs/keys-auth). ## Смотрите также - [Web Search для AI](/docs/search) - [Поиск (POST /v1/search)](/docs/search/run) - [Глубокий поиск (POST /v1/research)](/docs/search/research) - [Провайдеры](/docs/search/providers) - [Ключи и авторизация](/docs/keys-auth) --- # Search Credentials: Create ## Добавить ключ `POST /v1/search/credentials` Сохраняет BYOK-ключ выбранного провайдера для текущего пользователя. После добавления вызовы [`POST /v1/search`](/docs/search/run) и [`POST /v1/research`](/docs/search/research) с этим провайдером не списывают Ꝟ — оплата идёт напрямую с вашего аккаунта у поставщика. Перед сохранением сервер делает пробный вызов к провайдеру с присланным ключом. Если провайдер отклоняет ключ — возвращается `400 INVALID_CREDENTIAL`, запись не создаётся. Только после успешной проверки ключ шифруется и сохраняется. После сохранения исходное значение через API не вернуть — в выдаче только маска `<первые 5>********<последние 4>`. ## Поля запроса (body) | Поле | Тип | Обяз. | По умолч. | Описание | |------|-----|:-----:|-----------|---------| | `provider` | string | да | — | Один из BYOK-провайдеров: `tavily`, `brave`, `exa`, `you-com`, `linkup`, `perplexity`, `jina`, `z-ai`. `bitrix-search` через v1 не принимается | | `apiKey` | string | да | — | Токен у выбранного провайдера. Tavily — формат `tvly-…`, Brave — токен подписки из кабинета Brave, остальные — токен из кабинета соответствующего поставщика | | `name` | string | да | — | Произвольная подпись ключа для отображения в списке. От 1 до 64 символов | | `isDefault` | boolean | нет | `false` | Сделать дефолтным для провайдера. Запросы к `POST /v1/search` и `POST /v1/research` без поля `provider` пойдут через этот ключ | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/search/credentials \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "provider": "tavily", "apiKey": "tvly-abc123def456", "name": "Мой Tavily", "isDefault": true }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/search/credentials \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "provider": "tavily", "apiKey": "tvly-abc123def456", "name": "Мой Tavily", "isDefault": true }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/search/credentials', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ provider: 'tavily', apiKey: 'tvly-abc123def456', name: 'Мой Tavily', isDefault: true, }), }) const cred = await res.json() console.log('Создан ключ:', cred.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/search/credentials', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ provider: 'tavily', apiKey: 'tvly-abc123def456', name: 'Мой Tavily', isDefault: true, }), }) const cred = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `id` | string | Идентификатор созданного ключа. Передаётся в [`DELETE /v1/search/credentials/:id`](/docs/search/credentials/delete) и [`POST /v1/search/credentials/:id/test`](/docs/search/credentials/test) | | `provider` | string | Идентификатор провайдера: один из восьми BYOK-провайдеров | | `scope` | string | Уровень видимости. При создании через v1 — всегда `USER` | | `name` | string | Подпись из запроса | | `maskedKey` | string | Маска `<первые 5>********<последние 4>` | | `isDefault` | boolean | Стал ли ключ дефолтным для провайдера | | `createdAt` | string | Дата создания в формате ISO 8601 | ## Пример ответа 201 — ключ создан: ```json { "id": "cmol3pnk5001fo70zefbwb6dl", "provider": "tavily", "scope": "USER", "name": "Мой Tavily", "maskedKey": "tvly-********f456", "isDefault": true, "createdAt": "2026-04-30T06:26:51.653Z" } ``` ## Пример ответа при ошибке 400 — провайдер отклонил ключ при предварительной проверке: ```json { "error": { "code": "INVALID_CREDENTIAL", "message": "Upstream HTTP 401" } } ``` 400 — попытка добавить `bitrix-search`: ```json { "error": { "code": "INVALID_REQUEST", "message": "provider: Invalid enum value. Expected 'tavily' | 'brave' | 'exa' | 'you-com' | 'linkup' | 'perplexity' | 'jina' | 'z-ai', received 'bitrix-search'" } } ``` Остальные ситуации перечислены в таблице ошибок ниже. ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_CREDENTIAL` | Провайдер отклонил ключ при предварительной проверке. Запись не сохранена. Сообщение содержит причину — например, `Upstream HTTP 401` для отозванного ключа Tavily, `Upstream HTTP 422` для неверного токена подписки Brave | | 400 | `INVALID_REQUEST` | Не указан `apiKey`, `name` пустой или длиннее 64 символов, `provider` не из списка восьми BYOK-провайдеров | | 401 | `MISSING_API_KEY` | Отсутствует заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `UNAUTHORIZED` | Запрос идёт через ключ `vibe_app_…` без `Authorization: Bearer ` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `vibe:search` | | 404 | `PROVIDER_NOT_FOUND` | Провайдер с таким идентификатором отсутствует или отключён | | 429 | `RATE_LIMITED` | Превышен общий лимит запросов | | 500 | `INTERNAL_ERROR` | Внутренняя ошибка сервера | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Дефолтный ключ — один на провайдер.** При создании нового ключа с `isDefault: true` все остальные USER-ключи того же провайдера автоматически перестают быть дефолтными. Прежний ключ остаётся в системе — его можно использовать через явный `provider` в [`POST /v1/search`](/docs/search/run) или удалить. **Несколько ключей одного провайдера без дефолта.** Когда у пользователя несколько USER-ключей одного провайдера, ни один не помечен `isDefault: true`, и в [`POST /v1/search`](/docs/search/run) указан только `provider` — берётся самый поздний по `createdAt`. Для предсказуемого поведения отметьте нужный ключ как дефолтный. **Ключ проверяется у провайдера до сохранения.** Сервер делает пробный вызов выбранного провайдера с переданным `apiKey`. Запись создаётся только при положительном результате; в этом случае поле `lastVerifiedAt` сразу заполняется текущей датой. Это закрывает класс ошибок «дефолтным выбран ключ, который провайдер уже отозвал» и устраняет необходимость отдельного шага [`POST /v1/search/credentials/:id/test`](/docs/search/credentials/test) сразу после создания. Тестовый эндпоинт нужен позже — для перепроверки уже сохранённого ключа после ротации у поставщика. **Сетевые ошибки до провайдера маскируются под `INVALID_CREDENTIAL`.** Если запрос проверки не дошёл до провайдера (DNS, тайм-аут сети между Вайбкод и поставщиком), пользователь увидит ту же `400 INVALID_CREDENTIAL` с сообщением о причине. Это безопасный дефолт — не сохранять ключ, статус которого не подтверждён. Повторите попытку через короткое время. ## Смотрите также - [Свои ключи (BYOK)](/docs/search/credentials) - [Список своих ключей](/docs/search/credentials/list) - [Удалить ключ](/docs/search/credentials/delete) - [Проверить ключ](/docs/search/credentials/test) - [Поиск (POST /v1/search)](/docs/search/run) - [Провайдеры](/docs/search/providers) - [Ошибки](/docs/errors) --- # Search Credentials: Delete ## Удалить ключ `DELETE /v1/search/credentials/:id` Удаляет BYOK-ключ текущего пользователя. Восстановить ключ через API нельзя — добавьте новый через [`POST /v1/search/credentials`](/docs/search/credentials/create) при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | string | да | Идентификатор ключа из ответа [`GET /v1/search/credentials`](/docs/search/credentials/list) или из ответа на создание | ## Примеры ### curl — личный ключ ```bash curl -X DELETE \ -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/search/credentials/cmol3pnk5001fo70zefbwb6dl ``` ### curl — OAuth-приложение ```bash curl -X DELETE \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ https://vibecode.bitrix24.tech/v1/search/credentials/cmol3pnk5001fo70zefbwb6dl ``` ### JavaScript — личный ключ ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/search/credentials/cmol3pnk5001fo70zefbwb6dl', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }, ) if (res.status === 204) { console.log('Ключ удалён') } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/search/credentials/cmol3pnk5001fo70zefbwb6dl', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }, ) if (res.status === 204) { console.log('Ключ удалён') } ``` ## Ответ При успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом. Признак успеха — код ответа, не содержимое. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 404 — ключ не найден или принадлежит другому пользователю: ```json { "error": { "code": "CREDENTIAL_NOT_FOUND", "message": "cmol3pnk5001fo70zefbwb6dl" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `MISSING_API_KEY` | Отсутствует заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `UNAUTHORIZED` | Запрос идёт через ключ `vibe_app_…` без `Authorization: Bearer ` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `vibe:search` | | 404 | `CREDENTIAL_NOT_FOUND` | Ключ с таким `id` отсутствует у текущего пользователя | | 429 | `RATE_LIMITED` | Превышен общий лимит запросов | | 500 | `INTERNAL_ERROR` | Внутренняя ошибка сервера | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Чужой ключ не доступен.** При попытке удалить ключ другого пользователя сервер возвращает `404 CREDENTIAL_NOT_FOUND` — без указания, существует ли запись в системе. **Удаление дефолтного ключа.** Когда удалён дефолтный ключ, последующие [`POST /v1/search`](/docs/search/run) без явного `provider` снова идут по каскаду USER → PORTAL → PLATFORM. Если других USER-ключей не осталось, запросы пойдут через движок по умолчанию, настроенный на инстансе (его показывает поле `defaultProvider` в [`GET /v1/me`](/docs/keys-auth)). **Повтор удаления.** Повторный `DELETE` на тот же `id` возвращает `404 CREDENTIAL_NOT_FOUND`. Используйте 204 как сигнал «удалено сейчас», 404 — как «ключа уже нет». ## Смотрите также - [Свои ключи (BYOK)](/docs/search/credentials) - [Список своих ключей](/docs/search/credentials/list) - [Добавить ключ](/docs/search/credentials/create) - [Проверить ключ](/docs/search/credentials/test) - [Поиск (POST /v1/search)](/docs/search/run) - [Ошибки](/docs/errors) --- # Search Credentials: List ## Список своих ключей `GET /v1/search/credentials` Возвращает все BYOK-ключи текущего пользователя со скрытым телом ключа. Сервер хранит ключи в зашифрованном виде — вернуть исходное значение нельзя, в выдаче только маска. ## Параметры Параметров нет. ## Примеры ### curl — личный ключ ```bash curl -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/search/credentials ``` ### curl — OAuth-приложение ```bash curl \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ https://vibecode.bitrix24.tech/v1/search/credentials ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/search/credentials', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { credentials } = await res.json() credentials.forEach((c) => { console.log(`${c.provider} · ${c.maskedKey} · ${c.isDefault ? 'дефолтный' : 'обычный'}`) }) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/search/credentials', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { credentials } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `credentials` | array | Массив BYOK-ключей пользователя. Может быть пустым | | `credentials[].id` | string | Идентификатор ключа. Передаётся в [`DELETE /v1/search/credentials/:id`](/docs/search/credentials/delete) и [`POST /v1/search/credentials/:id/test`](/docs/search/credentials/test) | | `credentials[].provider` | string | Идентификатор провайдера: один из восьми BYOK (`tavily`, `brave`, `exa`, `you-com`, `linkup`, `perplexity`, `jina`, `z-ai`) | | `credentials[].scope` | string | Уровень видимости ключа. Через v1 возвращается только `USER` | | `credentials[].name` | string | Произвольная подпись ключа | | `credentials[].maskedKey` | string | Маска `<первые 5>********<последние 4>`. Полный ключ через API получить нельзя | | `credentials[].isDefault` | boolean | Считается дефолтным для провайдера. Берётся, когда в [`POST /v1/search`](/docs/search/run) поле `provider` опущено | | `credentials[].lastVerifiedAt` | string \| null | Дата последней успешной проверки через [`POST /v1/search/credentials/:id/test`](/docs/search/credentials/test) в формате ISO 8601 | | `credentials[].lastError` | string \| null | Текст последней ошибки проверки. `null`, если последняя проверка прошла успешно или проверок не было | | `credentials[].createdAt` | string | Дата добавления ключа в формате ISO 8601 | ## Пример ответа ```json { "credentials": [ { "id": "cmol3pnk5001fo70zefbwb6dl", "provider": "tavily", "scope": "USER", "name": "Мой Tavily", "maskedKey": "tvly-********a1b2", "isDefault": true, "lastVerifiedAt": "2026-04-30T06:30:00.000Z", "lastError": null, "createdAt": "2026-04-30T06:26:51.653Z" } ] } ``` Пустой список: ```json { "credentials": [] } ``` ## Пример ответа при ошибке 401 — для OAuth-ключа не передан `Authorization: Bearer`: ```json { "error": { "code": "UNAUTHORIZED", "message": "No user context." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `MISSING_API_KEY` | Отсутствует заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `UNAUTHORIZED` | Запрос идёт через ключ `vibe_app_…` без `Authorization: Bearer ` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `vibe:search` | | 429 | `RATE_LIMITED` | Превышен общий лимит запросов | | 500 | `INTERNAL_ERROR` | Внутренняя ошибка сервера | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Восстановление утерянного ключа.** Получить исходное значение из системы нельзя — единственный путь после потери токена удалить запись через [`DELETE /v1/search/credentials/:id`](/docs/search/credentials/delete) и добавить ключ заново. **`lastVerifiedAt` обновляется только через `test`.** Обычные поисковые запросы через [`POST /v1/search`](/docs/search/run) дату не двигают — даже если фактическое использование ключа прошло успешно. Для свежей метки вызывайте [`POST /v1/search/credentials/:id/test`](/docs/search/credentials/test). ## Смотрите также - [Свои ключи (BYOK)](/docs/search/credentials) - [Добавить ключ](/docs/search/credentials/create) - [Удалить ключ](/docs/search/credentials/delete) - [Проверить ключ](/docs/search/credentials/test) - [Поиск (POST /v1/search)](/docs/search/run) - [Ошибки](/docs/errors) --- # Search Credentials: Test ## Проверить ключ `POST /v1/search/credentials/:id/test` Проверяет, принимает ли провайдер сохранённый BYOK-ключ. Внутри отправляет минимальный валидационный запрос к API провайдера и возвращает результат. Поля `lastVerifiedAt` и `lastError` ключа обновляются в любом случае — успешная или нет проверка. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | string | да | Идентификатор ключа из ответа [`GET /v1/search/credentials`](/docs/search/credentials/list) или из ответа на создание | Тело запроса не передаётся. Неизвестные поля игнорируются. ## Примеры ### curl — личный ключ ```bash curl -X POST \ -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/search/credentials/cmol3pnk5001fo70zefbwb6dl/test ``` ### curl — OAuth-приложение ```bash curl -X POST \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ https://vibecode.bitrix24.tech/v1/search/credentials/cmol3pnk5001fo70zefbwb6dl/test ``` ### JavaScript — личный ключ ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/search/credentials/cmol3pnk5001fo70zefbwb6dl/test', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }, ) const result = await res.json() if (result.valid) { console.log('Ключ принят провайдером') } else { console.error('Проверка не прошла:', result.error) } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( 'https://vibecode.bitrix24.tech/v1/search/credentials/cmol3pnk5001fo70zefbwb6dl/test', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }, ) const result = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `valid` | boolean | `true` — провайдер принял ключ. `false` — провайдер ответил ошибкой | | `error` | string \| null | Текст ошибки провайдера. `null` при `valid: true` | ## Пример ответа Успешная проверка: ```json { "valid": true, "error": null } ``` Провайдер не принял ключ: ```json { "valid": false, "error": "Upstream HTTP 401" } ``` ## Пример ответа при ошибке 404 — ключ не найден: ```json { "error": { "code": "CREDENTIAL_NOT_FOUND", "message": "cmol3pnk5001fo70zefbwb6dl" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `MISSING_API_KEY` | Отсутствует заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 401 | `UNAUTHORIZED` | Запрос идёт через ключ `vibe_app_…` без `Authorization: Bearer ` | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `vibe:search` | | 404 | `CREDENTIAL_NOT_FOUND` | Ключ с таким `id` отсутствует у текущего пользователя | | 429 | `RATE_LIMITED` | Превышен общий лимит запросов | | 500 | `INTERNAL_ERROR` | Внутренняя ошибка сервера | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Различайте уровни ошибок.** HTTP 200 с `valid: false` — провайдер ответил, но отверг ключ (неверный токен, истекший срок). HTTP 4xx — ошибка авторизации в API Вайбкод. Проверяйте сначала статус ответа, потом поле `valid`. **Обновление состояния.** При `valid: true` поля ключа `lastVerifiedAt` и `lastError` сбрасываются в текущее время и `null`. При `valid: false` — `lastVerifiedAt` тоже обновляется (как факт проверки), `lastError` записывается. Получить текущее состояние можно через [`GET /v1/search/credentials`](/docs/search/credentials/list). **Проверка не списывает Ꝟ.** Эндпоинт делает минимальный валидационный вызов в обход биллинг-цикла, баланс пользователя не меняется. ## Смотрите также - [Свои ключи (BYOK)](/docs/search/credentials) - [Список своих ключей](/docs/search/credentials/list) - [Добавить ключ](/docs/search/credentials/create) - [Удалить ключ](/docs/search/credentials/delete) - [Поиск (POST /v1/search)](/docs/search/run) - [Ошибки](/docs/errors) --- # Search: Providers ## Список провайдеров `GET /v1/search/providers` Возвращает все доступные движки веб-поиска вместе с матрицей возможностей и актуальными тарифами по трём режимам — `basic`, `advanced`, `research`. Список фильтруется по флагу `isEnabled` — в ответ попадают только доступные провайдеры. Какой движок платформенный, его цена и движок по умолчанию различаются от инстанса к инстансу. Порядок элементов фиксированный: сначала платформенные движки, затем BYOK-провайдеры в каноническом порядке реестра. ## Параметры Параметров нет. ## Примеры ### curl — личный ключ ```bash curl -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/search/providers ``` ### curl — OAuth-приложение ```bash curl \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ https://vibecode.bitrix24.tech/v1/search/providers ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/search/providers', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { providers } = await res.json() providers.forEach((p) => { console.log(`${p.name} (${p.slug}) — basic ${p.pricing.basic} Ꝟ / advanced ${p.pricing.advanced} Ꝟ / research ${p.pricing.research} Ꝟ`) }) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/search/providers', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { providers } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `providers` | array | Массив включённых провайдеров | | `providers[].slug` | string | Идентификатор для поля `provider` в [`POST /v1/search`](/docs/search/run) и [`POST /v1/research`](/docs/search/research). Один из: `bitrix-search`, `tavily`, `brave`, `exa`, `you-com`, `linkup`, `perplexity`, `jina`, `z-ai` | | `providers[].name` | string | Отображаемое имя | | `providers[].description` | string | Краткое описание | | `providers[].requiresCredential` | boolean | Нужен ли BYOK-ключ. Для платформенных движков — `false`, ключ выпускает платформа | | `providers[].capabilities` | object | Матрица возможностей провайдера | | `providers[].capabilities.modes.search.basic` | boolean | Поддерживается ли режим `basic` в [`POST /v1/search`](/docs/search/run) | | `providers[].capabilities.modes.search.advanced` | boolean | Поддерживается ли режим `advanced` в [`POST /v1/search`](/docs/search/run) | | `providers[].capabilities.modes.research` | boolean | Поддерживается ли [`POST /v1/research`](/docs/search/research) | | `providers[].capabilities.modes.streaming` | boolean | Эмитит ли провайдер промежуточные события SSE (`thinking`, `tool_call`, `answer_delta`). `false` — поток буферизованный, приходит только `start` и `done` | | `providers[].capabilities.filters.includeDomains` | boolean | Принимается ли фильтр `include_domains` | | `providers[].capabilities.filters.excludeDomains` | boolean | Принимается ли фильтр `exclude_domains` | | `providers[].capabilities.filters.timeRange` | boolean | Принимается ли фильтр `time_range` | | `providers[].capabilities.filters.region` | boolean | Принимается ли региональный фильтр | | `providers[].capabilities.filters.safesearch` | boolean | Принимается ли фильтр безопасного поиска | | `providers[].capabilities.output.synthesizedAnswer` | boolean | Возвращает ли провайдер синтезированный ответ в поле `answer` по умолчанию | | `providers[].capabilities.output.citations` | boolean | Расставляет ли маркеры цитат `[N]` в синтезированном ответе | | `providers[].capabilities.output.relevanceScore` | boolean | Заполняет ли поле `score` в результатах | | `providers[].capabilities.output.publishedDate` | boolean | Заполняет ли поле `publishedDate` в результатах | | `providers[].capabilities.output.fullContent` | boolean | Возвращает ли полный текст страниц в `results[].rawContent` при `include_raw_content: true` | | `providers[].capabilities.output.followUpQuestions` | boolean | Возвращает ли уточняющие вопросы в режиме research | | `providers[].capabilities.verticals.news` | boolean | Поддерживает ли режим новостей через параметр `topic: "news"`. У поддерживающих движков он наполняет `publishedDate` для новостных результатов | | `providers[].capabilities.verticals.images` | boolean | Поддерживает ли запрос изображений через `include_images: true`. Ссылки приходят в верхнеуровневом массиве `images` | | `providers[].capabilities.algorithm` | string | Поисковый алгоритм: `keyword`, `neural` или `hybrid` | | `providers[].capabilities.liveData` | boolean | Делает ли провайдер свежий обход веб-страниц на каждый запрос | | `providers[].capabilities.summarizer` | boolean | Доступен ли отдельный суммаризатор по запросу. Для `brave` синтезированный ответ выдаётся только в режиме `advanced` через этот флаг, в остальных случаях `answer: null` | | `providers[].pricing.basic` | number | Стоимость одного запроса режима `basic` в Ꝟ. `0` для BYOK-провайдеров | | `providers[].pricing.advanced` | number | Стоимость одного запроса режима `advanced` в Ꝟ | | `providers[].pricing.research` | number | Стоимость одного запроса режима `research` в Ꝟ. `0` для всех BYOK-провайдеров с поддержкой research | ## Пример ответа ```json { "providers": [ { "slug": "bitrix-search", "name": "Bitrix AI-поиск", "description": "Платформенный AI-поиск с агентным режимом и цитированием источников", "requiresCredential": false, "capabilities": { "modes": { "search": { "basic": true, "advanced": true }, "research": true, "streaming": false }, "filters": { "includeDomains": true, "excludeDomains": true, "timeRange": true, "region": false, "safesearch": false }, "output": { "synthesizedAnswer": true, "citations": false, "relevanceScore": true, "publishedDate": true, "fullContent": true, "followUpQuestions": false }, "verticals": { "news": true, "images": true }, "algorithm": "hybrid", "liveData": false, "summarizer": false }, "pricing": { "basic": 2, "advanced": 5, "research": 0 } }, { "slug": "tavily", "name": "Tavily", "description": "Tavily web search API — англоязычный, BYOK", "requiresCredential": true, "capabilities": { "modes": { "search": { "basic": true, "advanced": true }, "research": true, "streaming": false }, "filters": { "includeDomains": true, "excludeDomains": true, "timeRange": true, "region": false, "safesearch": false }, "output": { "synthesizedAnswer": true, "citations": false, "relevanceScore": true, "publishedDate": true, "fullContent": true, "followUpQuestions": false }, "verticals": { "news": true, "images": true }, "algorithm": "hybrid", "liveData": false, "summarizer": false }, "pricing": { "basic": 0, "advanced": 0, "research": 0 } }, { "slug": "jina", "name": "Jina DeepSearch", "description": "Research-only iterative search/read/think loop", "requiresCredential": true, "capabilities": { "modes": { "search": { "basic": false, "advanced": false }, "research": true, "streaming": false }, "filters": { "includeDomains": true, "excludeDomains": true, "timeRange": false, "region": false, "safesearch": false }, "output": { "synthesizedAnswer": true, "citations": true, "relevanceScore": false, "publishedDate": true, "fullContent": true, "followUpQuestions": false }, "verticals": { "news": false, "images": false }, "algorithm": "hybrid", "liveData": false, "summarizer": false }, "pricing": { "basic": 0, "advanced": 0, "research": 0 } } ] } ``` Показаны три характерных провайдера: платформенный `bitrix-search`, универсальный BYOK `tavily` и research-only `jina`. Значения `capabilities` и `pricing` платформенного движка зависят от инстанса — здесь приведены для примера. Фактические возвращает этот же эндпоинт. Какие движки платформенные и какой движок по умолчанию — также определяется настройками инстанса. Полный список идентификаторов — `bitrix-search`, `tavily`, `brave`, `exa`, `you-com`, `linkup`, `perplexity`, `jina`, `z-ai`. ## Пример ответа при ошибке 403 — не хватает скоупа: ```json { "error": { "code": "SCOPE_DENIED", "message": "vibe:search scope required." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `MISSING_API_KEY` | Отсутствует заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный API-ключ | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `vibe:search` | | 429 | `RATE_LIMITED` | Превышен общий лимит запросов | | 500 | `INTERNAL_ERROR` | Внутренняя ошибка сервера | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Каноническая последовательность провайдеров.** Порядок элементов в массиве не зависит от того, в какой день добавлен провайдер в платформу. Сначала идут платформенные движки, затем BYOK в фиксированном порядке реестра. Для UI это позволяет рендерить плитки без дополнительной сортировки. **Провайдер пропадает из списка, если становится недоступным.** Клиент с закешированным значением продолжит передавать его в `provider`, но [`POST /v1/search`](/docs/search/run) и [`POST /v1/research`](/docs/search/research) вернут `404 PROVIDER_NOT_FOUND` — это сигнал перечитать список через текущий эндпоинт. **`pricing` показывает только списание в Вайбах.** Реальная стоимость у поставщика BYOK оплачивается с вашего собственного аккаунта по тарифу провайдера и в этой таблице не отражается. Поле `pricing.research` равно нулю для всех BYOK-провайдеров с поддержкой research. Тариф платформенного движка (`pricing.basic` / `pricing.advanced` / `pricing.research`) различается от инстанса к инстансу — ориентируйтесь на значения из ответа этого эндпоинта, а не на фиксированные числа. **Capability `modes.streaming` отражает поведение адаптера, а не провайдера.** На стороне провайдера может работать нативный SSE-поток с прогрессивными событиями, но если адаптер Вайбкод собирает поток в один блок и отдаёт только `start` + `done`, флаг `streaming` будет `false`. Сегодня прогрессивный поток с `thinking`, `tool_call`, `answer_delta` доступен только для `bitrix-search`. **Признак «есть синтезированный ответ» — `output.synthesizedAnswer`.** Для `brave` поле имеет значение `false`, а опциональный суммаризатор сигнализируется отдельным флагом `summarizer: true`. Это означает: по умолчанию `answer` приходит как `null`, но при `search_depth: "advanced"` Brave подмешивает суммаризатор в ответ. ## Смотрите также - [Web Search для AI](/docs/search) - [Поиск (POST /v1/search)](/docs/search/run) - [Глубокий поиск (POST /v1/research)](/docs/search/research) - [Свои ключи (BYOK)](/docs/search/credentials) - [Ошибки](/docs/errors) --- # Search: Research ## Глубокий поиск (research) `POST /v1/research` Запускает глубокий итеративный поиск с многошаговым агентным циклом «искать → читать → анализировать». Возвращает структурированный отчёт с разделами, источниками и опциональными уточняющими вопросами. Эндпоинт всегда работает в потоковом режиме через Server-Sent Events — один запрос длится 10–60 секунд и не помещается в типичный таймаут синхронного HTTP. ## Поля запроса (body) | Поле | Тип | Обяз. | По умолч. | Описание | |------|-----|:-----:|-----------|---------| | `query` | string | да | — | Текст исследовательского запроса. От 1 до 2000 символов | | `provider` | string | нет | research-движок по умолчанию инстанса | Провайдер с поддержкой research: `tavily`, `exa`, `you-com`, `linkup`, `perplexity` или `jina`. Платформенный `bitrix-search` поддерживает research в зависимости от инстанса. Актуальный список — в [`GET /v1/search/providers`](/docs/search/providers) с `capabilities.modes.research: true` | | `maxSteps` | number | нет | 5 | Максимум шагов агентного цикла. От 1 до 10. Адаптер ограничивает значение, если внешний провайдер не принимает столько шагов | | `lang` | string | нет | `auto` | Язык исследования: `ru`, `en` или `auto` | | `includeDomains` | string[] | нет | `[]` | Поиск только по доменам из списка. До 50 имён хоста. Отдельные движки берут не больше 20 — при превышении список обрезается, а в кадре `done` появляется `ignored_filters` с `includeDomains_truncated` | | `excludeDomains` | string[] | нет | `[]` | Исключить домены. До 50 имён хоста. Отдельные движки берут не больше 20 — при превышении список обрезается, а в кадре `done` появляется `ignored_filters` с `excludeDomains_truncated` | ## Примеры ### curl — личный ключ ```bash curl -N -X POST https://vibecode.bitrix24.tech/v1/research \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "query": "Сравни возможности Cursor 3 и Windsurf для AI-кодинга", "provider": "tavily", "maxSteps": 5, "lang": "ru" }' ``` ### curl — OAuth-приложение ```bash curl -N -X POST https://vibecode.bitrix24.tech/v1/research \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "query": "Сравни возможности Cursor 3 и Windsurf для AI-кодинга", "provider": "tavily", "maxSteps": 5, "lang": "ru" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/research', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ query: 'Сравни возможности Cursor 3 и Windsurf для AI-кодинга', provider: 'tavily', maxSteps: 5, lang: 'ru', }), }) const reader = res.body.getReader() const decoder = new TextDecoder() let buffer = '' while (true) { const { value, done } = await reader.read() if (done) break buffer += decoder.decode(value, { stream: true }) const events = buffer.split('\n\n') buffer = events.pop() ?? '' for (const block of events) { const eventLine = block.split('\n').find(l => l.startsWith('event: ')) const dataLine = block.split('\n').find(l => l.startsWith('data: ')) if (!eventLine || !dataLine) continue const event = eventLine.slice(7) const data = JSON.parse(dataLine.slice(6)) if (event === 'done') { console.log('Готово:', data.synthesized_answer.slice(0, 200)) console.log('Источников:', data.sources.length) } } } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/research', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ query: 'Сравни возможности Cursor 3 и Windsurf для AI-кодинга', provider: 'tavily', maxSteps: 5, lang: 'ru', }), }) const reader = res.body.getReader() ``` ## Поток событий (SSE) Ответ приходит как поток `text/event-stream`. Каждое событие — пара `event: ` + `data: `, разделённая пустой строкой. Поток гарантированно завершается одним из двух событий: `done` (успех) или `error` (сбой). | Событие | Когда возникает | Поля `data` | |---------|-----------------|-------------| | `start` | В начале запроса | `research_id`, `provider` | | `thinking` | Промежуточные размышления агента | `content` — текстовый фрагмент | | `tool_call` | Агент вызвал внутренний инструмент | `tool` (`web_search` / `content_extraction` / `external_tool`), `description` | | `tool_result` | Инструмент вернул результат | `description`, `items_count` | | `section_complete` | Завершён раздел исследования с привязанными источниками | `section.title`, `section.content`, `section.sourceIds` | | `answer_delta` | Очередной фрагмент финального ответа | `content` — кусок текста | | `done` | Финальный блок | см. таблицу «Поля события `done`» ниже | | `error` | Сбой во время обработки | `error.code`, `error.message` | Какие именно промежуточные события придут — зависит от провайдера. Ни одно из них не обязательно: получение `start` и `done` достаточно для штатного завершения. ## Поля события `done` | Поле | Тип | Описание | |------|-----|---------| | `query` | string | Текст исходного запроса | | `provider` | string | Идентификатор провайдера, который обработал запрос (например, `tavily`, `exa`) | | `synthesized_answer` | string | Полный синтезированный ответ исследования | | `outline` | object \| null | Структура разделов отчёта. `null`, если провайдер не возвращает разбивку | | `outline.sections` | array | Массив разделов | | `outline.sections[].title` | string | Заголовок раздела | | `outline.sections[].content` | string | Текст раздела | | `outline.sections[].sourceIds` | number[] | Идентификаторы источников из `sources[]`, на которые опирается раздел | | `sources` | array | Массив источников исследования | | `sources[].id` | number | Порядковый номер источника | | `sources[].url` | string | Адрес страницы | | `sources[].title` | string | Заголовок страницы | | `sources[].fullContent` | string | Полный текст страницы. Длина ограничена провайдером | | `sources[].publishedDate` | string \| null | Дата публикации в формате ISO 8601 | | `follow_up_questions` | string[] \| null | Уточняющие вопросы для углубления исследования. `null`, если провайдер не предоставляет | | `reasoning` | array \| null | Шаги рассуждения агента. `null`, если провайдер не предоставляет | | `reasoning[].step` | number | Порядковый номер шага | | `reasoning[].description` | string | Краткое описание шага | | `research_id` | string | Идентификатор запроса в формате `wr_<14 цифр>_<8 hex>` | | `upstream_search_id` | string \| null | Идентификатор у внешнего провайдера. Полезен для разбора инцидентов | | `cost_vibes` | number | Сколько Ꝟ списано фактически | | `duration_ms` | number | Длительность обработки запроса в миллисекундах | | `partial_charge` | boolean | Присутствует, когда параллельные запросы исчерпали остаток баланса до конца текущего списания. Запрос завершился успешно, фактически списано меньше номинальной стоимости — итог в `cost_vibes` | | `charge_log_failed` | boolean | Присутствует, когда не удалось записать журнал использования. Результат отдан, средства не списаны (`cost_vibes: 0`) | | `ignored_filters` | string[] | Необязательное. Переданные фильтры, которые движок не смог применить. Например, `includeDomains_truncated`, когда передано больше 20 доменов и список обрезан до 20 | ## Пример потока событий ``` event: start data: {"research_id":"wr_20260504112304_a1b2c3d4","provider":"tavily"} event: tool_call data: {"tool":"web_search","description":"Web research started"} event: tool_result data: {"description":"got 8 sources","items_count":8} event: tool_call data: {"tool":"content_extraction","description":"reading top sources"} event: answer_delta data: {"content":"Cursor 3 — это переработанная среда "} event: answer_delta data: {"content":"для AI-разработки [1][2]. Windsurf, в свою очередь, "} event: done data: {"query":"Сравни возможности Cursor 3 и Windsurf для AI-кодинга","provider":"tavily","synthesized_answer":"Cursor 3 — это переработанная среда для AI-разработки [1][2]. Windsurf, в свою очередь, делает упор на agentic-flow [3]…","outline":null,"sources":[{"id":1,"url":"https://cursor.com/blog/cursor-3","title":"Meet the new Cursor","fullContent":"…","publishedDate":"2026-04-15T00:00:00Z"}],"follow_up_questions":null,"reasoning":null,"research_id":"wr_20260504112304_a1b2c3d4","upstream_search_id":"tvly-research-abc","cost_vibes":0,"duration_ms":18230} ``` ## Пример ответа при ошибке 402 — на балансе не хватает Ꝟ: ```json { "error": { "code": "INSUFFICIENT_BALANCE", "message": "Insufficient vibes for this research request.", "userMessage": "Недостаточно vibes — пополните баланс или добавьте свой BYOK-ключ (см. GET /v1/search/providers).", "hint": "Add a BYOK key to search for free — see GET /v1/search/providers", "required": 25 } } ``` Три поля приходят **внутри объекта `error`**, а не на верхнем уровне ответа: `userMessage` — текст на языке пользователя, `hint` — подсказка по дальнейшим действиям, `required` — сколько Ꝟ нужно на этот запрос. Набор общий для `INSUFFICIENT_BALANCE` и `BILLING_FROZEN`. Остальные ситуации — в таблице ошибок ниже. ## Ошибки Ошибки до открытия SSE-потока возвращаются обычным JSON-ответом. Ошибки, возникшие после установки соединения, приходят как событие `error` в потоке. | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_REQUEST` | Пустой `query`, `query` длиннее 2000 символов, `maxSteps` вне диапазона 1..10, `provider` не из списка поддерживаемых провайдеров, `includeDomains` или `excludeDomains` длиннее 50 элементов | | 402 | `INSUFFICIENT_BALANCE` | На балансе портала недостаточно Ꝟ для платного провайдера. Перейдите на BYOK или пополните баланс | | 402 | `BILLING_FROZEN` | Биллинг-аккаунт заморожен | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `vibe:search` | | 404 | `PROVIDER_NOT_FOUND` | Провайдер с таким идентификатором отсутствует или недоступен | | 404 | `CREDENTIAL_NOT_FOUND` | Для провайдера нет ни USER, ни PORTAL, ни PLATFORM-ключа | | 404 | `PROVIDER_DOES_NOT_SUPPORT_RESEARCH` | Запрошен провайдер без поддержки research: `brave`, `z-ai` или `bitrix-search`, когда у движка инстанса нет режима research. Такие провайдеры доступны только в [`POST /v1/search`](/docs/search/run) | | 429 | `RATE_LIMITED` | Превышен лимит 20 запросов в минуту на портал — общий для всех его API-ключей | | 503 | `FEATURE_NOT_ENABLED` | Глубокое исследование недоступно на этой платформе | Ошибки внутри SSE-потока: | Код | Описание | |-----|---------| | `UPSTREAM_ERROR` | Провайдер вернул ошибку во время обработки. Списания нет | | `PROVIDER_DOES_NOT_SUPPORT_RESEARCH` | Защитная проверка адаптера на стороне сервера — фактически дубль HTTP-кода 404, всплывает при рассинхронизации каталога | | `INTERNAL_ERROR` | Внутренняя ошибка сервера во время обработки | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Только потоковый режим.** Синхронного варианта `/v1/research` без SSE не существует — глубокое исследование длится 10–60 секунд и не вписывается в обычные HTTP-таймауты прокси. Если клиент не может работать с потоком, накапливайте события на сервере-посреднике и отдавайте их пакетом конечному приложению. **Лимит 20 запросов в минуту на портал.** Ниже, чем у [`POST /v1/search`](/docs/search/run), потому что один research-запрос потребляет ресурсы провайдера в десятки раз дольше обычного поиска. Лимит общий для всех API-ключей портала — они делят его между собой, поэтому распределение нагрузки по нескольким ключам предел не поднимает. При превышении возвращается `429 RATE_LIMITED`. **Тариф платформенного research-движка зависит от инстанса.** Сколько Ꝟ стоит режим `research` у платформенного движка, возвращает [`GET /v1/search/providers`](/docs/search/providers) в поле `pricing.research`. Для всех BYOK-провайдеров стоимость на стороне платформы — 0 Ꝟ, оплата идёт напрямую с вашего аккаунта у поставщика. **Каскад выбора ключа отличается от `/v1/search`.** В [`POST /v1/search`](/docs/search/run) при опущенном `provider` платформа сначала проверяет USER/PORTAL-дефолт по любому провайдеру и только потом уходит в движок по умолчанию инстанса. В research всё иначе: если поле `provider` опущено, сервер **сразу подставляет research-движок по умолчанию, настроенный на инстансе**, не проверяя USER/PORTAL-дефолты по другим провайдерам. Если для этого движка нет ни одного ключа, возвращается `404 CREDENTIAL_NOT_FOUND` — даже если у пользователя есть дефолтный ключ для `exa` или другого research-провайдера. Каскад USER → PORTAL → PLATFORM применяется уже **внутри** выбранного провайдера. Чтобы пойти через другой research-провайдер, передавайте `provider` явно. **Списание происходит только после успешного завершения потока.** Перед запуском проверяется баланс: при нехватке возвращается `402 INSUFFICIENT_BALANCE` без обращения к провайдеру. При обрыве потока с ошибкой провайдера баланс не меняется — оплачивать нечего. ## Смотрите также - [Web Search для AI](/docs/search) - [Поиск (POST /v1/search)](/docs/search/run) - [Провайдеры](/docs/search/providers) - [Свои ключи (BYOK)](/docs/search/credentials) - [Ключи и авторизация](/docs/keys-auth) - [Ошибки](/docs/errors) --- # Search: Run ## Поиск `POST /v1/search` Выполняет поиск в интернете и возвращает синтезированный ответ со ссылками на источники. Поддерживает синхронный режим и потоковую передачу через Server-Sent Events (`stream: true`). Глубокое исследование с многошаговым агентным циклом — отдельный эндпоинт [`POST /v1/research`](/docs/search/research). ## Поля запроса (body) | Поле | Тип | Обяз. | По умолч. | Описание | |------|-----|:-----:|-----------|---------| | `query` | string | да | — | Текст запроса. От 1 до 400 символов | | `search_depth` | string | нет | `basic` | Глубина поиска: `basic` или `advanced`. Цена режима — в [`GET /v1/search/providers`](/docs/search/providers) | | `provider` | string | нет | каскад USER → PORTAL → движок по умолчанию инстанса | Принудительный выбор движка: один из `bitrix-search`, `tavily`, `brave`, `exa`, `you-com`, `linkup`, `perplexity`, `z-ai`. `jina` доступен только в [`POST /v1/research`](/docs/search/research) | | `topic` | string | нет | `general` | Тематика поиска: `general` или `news`. Режим `news` поддерживают не все движки — у поддерживающих он наполняет `publishedDate` для новостных результатов, у остальных игнорируется | | `max_results` | number | нет | 5 | Количество результатов в ответе. От 1 до 20 | | `max_steps` | number | нет | 3 | Максимум шагов агентного режима. От 1 до 5. Учитывает только `bitrix-search` | | `lang` | string | нет | `ru` | Язык поиска: `ru`, `en` или `auto` | | `include_answer` | boolean | нет | `true` | Включить синтезированный ответ в поле `answer` | | `include_raw_content` | boolean | нет | `false` | Запросить полный текст найденных страниц. У поддерживающих движков текст приходит в `results[].rawContent` | | `include_images` | boolean | нет | `false` | Запросить изображения по запросу. У поддерживающих движков ссылки приходят в верхнеуровневом массиве `images` | | `include_domains` | string[] | нет | `[]` | Поиск только по доменам из списка. До 10 имён хоста | | `exclude_domains` | string[] | нет | `[]` | Исключить домены. До 10 имён хоста | | `time_range` | string \| null | нет | `null` | Окно времени публикации: `day`, `week`, `month`, `year` | | `stream` | boolean | нет | `false` | `true` — потоковая передача через SSE вместо JSON-ответа | Часть фильтров поддерживается не всеми провайдерами — см. таблицу в [Web Search для AI](/docs/search#поддерживаемые-возможности-провайдеров). Неподдерживаемый фильтр игнорируется, в ответе появляется заголовок `X-Search-Filters-Ignored` со списком пропущенных полей. ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/search \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "query": "что нового в Cursor IDE", "search_depth": "advanced", "max_results": 5, "lang": "ru" }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/search \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "query": "что нового в Cursor IDE", "search_depth": "advanced", "max_results": 5, "lang": "ru" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ query: 'что нового в Cursor IDE', search_depth: 'advanced', max_results: 5, lang: 'ru', }), }) const data = await res.json() console.log(data.answer) data.results.forEach((r) => console.log(`[${r.id}] ${r.title} — ${r.url}`)) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ query: 'что нового в Cursor IDE', search_depth: 'advanced', max_results: 5, lang: 'ru', }), }) const data = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `query` | string | Текст исходного запроса | | `provider` | string | Идентификатор провайдера, который обработал запрос (например, `bitrix-search`, `tavily`) | | `search_depth` | string | Применённая глубина поиска: `basic` или `advanced` | | `answer` | string \| null | Синтезированный ответ с маркерами `[N]`. `null` для `brave` или при `include_answer: false` | | `results` | array | Массив найденных источников | | `results[].id` | number | Порядковый номер. Совпадает с маркером `[N]` в `answer` | | `results[].url` | string | Адрес страницы | | `results[].title` | string | Заголовок страницы | | `results[].content` | string | Всегда краткое описание или сниппет страницы. Полный текст приходит отдельным полем `rawContent`, а не здесь | | `results[].rawContent` | string \| null | Полный текст страницы при `include_raw_content: true` у поддерживающих движков. Размер ограничен примерно 40 КБ на результат. `null`, если полный текст не запрашивался или движок его не отдаёт | | `results[].score` | number \| null | Оценка релевантности от провайдера. Для `tavily` — число от 0 до 1, чем выше — тем релевантнее. `null` для `bitrix-search` и `brave` | | `results[].publishedDate` | string \| null | Дата публикации в формате ISO 8601. `null` для `bitrix-search`. У `tavily` заполняется в основном при `topic: "news"` | | `images` | array | Верхнеуровневый массив изображений при `include_images: true` у поддерживающих движков. Каждый элемент — объект с полем `url`. Пустой массив, если изображения не запрашивались или движок их не отдаёт | | `ignored_filters` | string[] | Переданные фильтры и параметры, которые движок не смог применить. Дублирует заголовок `X-Search-Filters-Ignored` в теле ответа. Может содержать `topic`, `include_images`, `include_domains`, `time_range` и другие — состав зависит от движка | | `search_id` | string | Идентификатор запроса в формате `ws_<14 цифр>_<8 hex>` | | `upstream_search_id` | string \| null | Идентификатор у внешнего провайдера. Полезен для разбора инцидентов | | `cost_vibes` | number | Сколько Ꝟ списано фактически | | `duration_ms` | number | Длительность обработки запроса в миллисекундах | | `partial_charge` | boolean | Присутствует, когда параллельные запросы исчерпали остаток баланса до конца текущего списания. Запрос завершился успешно, фактически списано меньше номинальной стоимости — итог в `cost_vibes` | | `charge_log_failed` | boolean | Присутствует, когда не удалось записать журнал использования. Результат отдан, средства не списаны (`cost_vibes: 0`) | ## Пример ответа ```json { "query": "что нового в Cursor IDE", "provider": "bitrix-search", "search_depth": "advanced", "answer": "Cursor 3 — переработка интерфейса IDE [1]. Появилось окно агентов [2].", "results": [ { "id": 1, "url": "https://cursor.com/blog/cursor-3", "title": "Meet the new Cursor", "content": "Cursor 3 brings a new agent-first interface...", "rawContent": null, "score": null, "publishedDate": null }, { "id": 2, "url": "https://cursor.com/changelog", "title": "Changelog", "content": "Latest features in Cursor IDE...", "rawContent": null, "score": null, "publishedDate": null } ], "images": [], "ignored_filters": [], "search_id": "ws_20260430113025_a1b2c3d4", "upstream_search_id": "AG_xyz", "cost_vibes": 5, "duration_ms": 8523 } ``` Значение `provider` в примере (`bitrix-search`) и `cost_vibes` зависят от инстанса: без явного `provider` запрос обрабатывает движок по умолчанию, настроенный на инстансе (его показывает поле `defaultProvider` в [`GET /v1/me`](/docs/keys-auth)), а сумма списания — его тариф из [`GET /v1/search/providers`](/docs/search/providers). При `include_raw_content: true` у поддерживающего движка поле `rawContent` заполняется полным текстом страницы, при `include_images: true` верхнеуровневый массив `images` — ссылками на изображения. Если движок не поддерживает `topic` или `include_images`, эти параметры попадают в `ignored_filters`. **Безопасность вывода.** `rawContent` — это неочищенный текст из открытого интернета, а `images[]` — сторонние URL. Перед показом в браузере очищайте текст и проксируйте или проверяйте ссылки изображений — не вставляйте их в DOM как есть. ## Потоковая передача (SSE) При `stream: true` ответ приходит как поток событий `text/event-stream`. Каждое событие — это пара `event: ` + `data: `, разделённая пустой строкой. Возможные события: | Событие | Когда возникает | Поля `data` | |---------|-----------------|-------------| | `start` | В начале запроса | `search_id`, `provider`, `search_depth` | | `thinking` | Промежуточные размышления агента | `content` — текстовый фрагмент | | `tool_call` | Агент вызвал внутренний инструмент | `tool` (`web_search` / `content_extraction` / `external_tool`), `description` | | `tool_result` | Инструмент вернул результат | `description`, `items_count` | | `answer_delta` | Очередной фрагмент финального ответа | `content` — кусок текста | | `done` | Финальный блок | те же поля, что в синхронном ответе | | `error` | Сбой во время обработки | `error.code`, `error.message` | Пример потока: ``` event: start data: {"search_id":"ws_20260430113025_a1b2c3d4","provider":"bitrix-search","search_depth":"advanced"} event: thinking data: {"content":"Сейчас посмотрим в источниках"} event: tool_call data: {"tool":"web_search","description":"web search query"} event: tool_result data: {"description":"got 5 sources","items_count":5} event: answer_delta data: {"content":"Cursor 3 — "} event: answer_delta data: {"content":"переработка интерфейса IDE [1]."} event: done data: {"query":"что нового в Cursor IDE","provider":"bitrix-search","search_depth":"advanced","answer":"Cursor 3 — переработка интерфейса IDE [1].","results":[{"id":1,"url":"https://cursor.com/blog/cursor-3","title":"Meet the new Cursor","content":"...","rawContent":null,"score":null,"publishedDate":null}],"images":[],"ignored_filters":[],"search_id":"ws_20260430113025_a1b2c3d4","upstream_search_id":"AG_xyz","cost_vibes":5,"duration_ms":8523} ``` Реальный поток событий с промежуточными `thinking` / `tool_call` / `answer_delta` отправляет только `bitrix-search`. Для остальных провайдеров поток буферизованный — приходит только `start` и `done`. Признак прогрессивного потока — поле `capabilities.modes.streaming` в [`GET /v1/search/providers`](/docs/search/providers). ## Пример ответа при ошибке 402 — недостаточно средств: ```json { "error": { "code": "INSUFFICIENT_BALANCE", "message": "Insufficient vibes for this search.", "userMessage": "Недостаточно vibes — пополните баланс или добавьте свой BYOK-ключ (см. GET /v1/search/providers).", "hint": "Add a BYOK key to search for free — see GET /v1/search/providers", "required": 5 } } ``` Поле `required` — сумма в Ꝟ, необходимая для запроса. Остальные ситуации перечислены в таблице ошибок ниже. ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_REQUEST` | Пустой `query`, `query` длиннее 400 символов, `max_results` вне диапазона 1..20, `max_steps` вне диапазона 1..5, `provider` не из списка поддерживаемых провайдеров, неизвестное значение `search_depth`, `topic`, `lang` или `time_range`, `include_domains` / `exclude_domains` длиннее 10 элементов | | 402 | `INSUFFICIENT_BALANCE` | На балансе портала недостаточно Ꝟ для выбранного режима | | 402 | `BILLING_FROZEN` | Биллинг-аккаунт заморожен | | 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `vibe:search` | | 404 | `PROVIDER_NOT_FOUND` | Передан `provider`, которого нет в системе или он отключён | | 404 | `CREDENTIAL_NOT_FOUND` | Для провайдера нет ни USER, ни PORTAL, ни PLATFORM-ключа | | 404 | `PROVIDER_DOES_NOT_SUPPORT_SEARCH` | Запрошен `provider: "jina"` — Jina работает только в [`POST /v1/research`](/docs/search/research). Поле `search_id` присутствует в ответе | | 429 | `RATE_LIMITED` | Превышен лимит 60 запросов в минуту на портал — общий для всех его API-ключей | | 500 | `INTERNAL_ERROR` | Внутренняя ошибка сервера. В ответе присутствует `search_id` | | 401/403/429/502 | `UPSTREAM_ERROR` | Провайдер вернул ошибку, списания нет; поле `upstream_status` в ответе несёт исходный статус провайдера. Для BYOK-ключа ответы провайдера `401` и `403` приходят с тем же статусом — провайдер отверг ваш ключ, повтор без его замены не поможет. Ответ провайдера `429` сохраняет статус для любого ключа и несёт заголовок `Retry-After` — повторите позже. Остальные ошибки провайдера, включая отказ ключа платформенного движка, приходят как `502` — повторите запрос | | 503 | `FEATURE_NOT_ENABLED` | Web Search недоступен на этой платформе | | 503 | `UPSTREAM_TIMEOUT` | Провайдер превысил время ожидания запроса. Списания нет. Ответ содержит заголовок `Retry-After: 30` — повторите запрос через указанное в нём время | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Каскад выбора ключа.** Когда поле `provider` опущено, платформа подбирает источник в порядке: ключ пользователя (USER BYOK) → ключ портала (PORTAL BYOK) → движок по умолчанию, настроенный на инстансе (его показывает поле `defaultProvider` в [`GET /v1/me`](/docs/keys-auth)). Свой BYOK-ключ с `isDefault: true` начинает срабатывать автоматически — `provider` указывать необязательно. **Списание происходит только после успешного ответа.** Перед запросом проверяется баланс: при нехватке возвращается `402 INSUFFICIENT_BALANCE` без обращения к провайдеру. При `UPSTREAM_ERROR` или `UPSTREAM_TIMEOUT` баланс не меняется — провайдер не вернул результат, оплачивать нечего. **`lang: "auto"` для `bitrix-search` приводится к `ru`.** Значения `ru` и `en` передаются движку как есть — для англоязычной выдачи передайте `lang: "en"`. Поле не отбрасывается и в `X-Search-Filters-Ignored` не попадает. **Пустая выдача оплачивается полностью.** Когда провайдер не нашёл ни одного источника и вернул `results: []`, `cost_vibes` всё равно списывается в полном размере. Это поведение по дизайну — оплачивается обработка запроса провайдером, а не количество результатов. **Поле `charge_log_failed` сигнализирует о потерянной аудит-записи.** При успешном ответе провайдера, но сбое записи журнала использования, ответ всё равно отдаётся клиенту с `cost_vibes: 0` и флагом `charge_log_failed: true`. Списание Вайбов не произошло — аудит-журнал по этому запросу также отсутствует. Сценарий редкий, виден в разделе «AI-Поиск» (`/search`). **`provider: "jina"` доступен только в `/v1/research`.** Запрос с `provider: "jina"` в текущем эндпоинте возвращает `404 PROVIDER_DOES_NOT_SUPPORT_SEARCH`. Список провайдеров, поддерживающих `/v1/search`, проверяется по полю `capabilities.modes.search.basic` или `capabilities.modes.search.advanced` в [`GET /v1/search/providers`](/docs/search/providers). ## Смотрите также - [Web Search для AI](/docs/search) - [Глубокий поиск (POST /v1/research)](/docs/search/research) - [Провайдеры](/docs/search/providers) - [Свои ключи (BYOK)](/docs/search/credentials) - [Веб-поиск + LLM (RAG)](/docs/recipes/web-search-with-llm) - [Ключи и авторизация](/docs/keys-auth) - [Ошибки](/docs/errors) - [Лимиты и оптимизация](/docs/optimization) --- # AI: Audio # Распознавание речи Преобразование аудио в текст через Whisper Large v3 Turbo на инфраструктуре Битрикс24 — без подключения BYOK. Расшифровка учитывается в AI-квоте портала по длительности аудио: в рамках квоты тарифа деньги с баланса не списываются, сверх квоты расход списывается с денежного баланса портала по базовой цене модели. Скоуп: `vibe:ai` ## Операции - [Расшифровать аудио](./audio/transcriptions.md) — `POST /v1/audio/transcriptions` ## Типовой сценарий 1. Получите аудиозапись (звонок, голосовое сообщение, аудио-вложение). 2. Передайте файл в [`POST /v1/audio/transcriptions`](./audio/transcriptions.md) — получите распознанный текст. 3. Передайте текст в [чат-комплишен](/docs/ai/chat/completions) для классификации, суммаризации или извлечения сущностей. ## Смотрите также - [AI Router](/docs/ai) - [Чат-комплишены](/docs/ai/chat) --- # AI Audio: Transcriptions ## Расшифровать аудио `POST /v1/audio/transcriptions` Преобразует аудиофайл в текст через Whisper Large v3 Turbo — без подключения BYOK. Расшифровка учитывается в AI-квоте портала по длительности аудио: в рамках квоты тарифа деньги с баланса не списываются, сверх квоты расход списывается с денежного баланса портала по базовой цене модели. Принимает файл через `multipart/form-data`. Формат запроса и ответа совместим с `POST /v1/audio/transcriptions` из OpenAI API. > **Ответ приходит в сыром OpenAI-формате.** > > Обёртки `{success, data}`, которая используется в остальных эндпоинтах Вайбкод — `/v1/deals`, `/v1/tasks` и других, — здесь нет. > > Так сделано для совместимости с OpenAI SDK. Если у вас единый клиент с проверкой `if (!response.success)`, добавьте для AI Router исключение. ## Поля запроса (form-data) | Поле | Тип | Обяз. | По умолч. | Описание | |------|-----|:-----:|-----------|----------| | `file` | file | да | — | Аудиофайл. Поддерживаются `mp3`, `mp4`, `mpeg`, `mpga`, `m4a`, `wav`, `webm`, `flac`, `ogg`. Максимальный размер — 25 МБ | | `model` | string | нет | `deepdml/faster-whisper-large-v3-turbo-ct2` | ID Whisper-модели. Префикс `bitrix/` опционален и автоматически удаляется | | `language` | string | нет | автоопределение | Код языка по `ISO 639` (2-3 буквы): `ru`, `en`, `de`, `fr`, `zh` и т. п. Указание языка ускоряет распознавание | | `prompt` | string | нет | — | Контекстная подсказка: тема разговора, стиль, правильное написание терминов. До 2000 символов, модель учитывает последние ~224 токена | | `hotwords` | string | нет | — | Спец-слова и термины через запятую — повышают точность распознавания редких названий и брендов. До 500 символов | | `temperature` | number | нет | `0` | Температура декодера от `0` до `1`. `0` — детерминированный результат, выше — больше вариативности. Значения вне диапазона отклоняются | | `vad_filter` | boolean | нет | — | `true` включает VAD-фильтр: модель вырезает тишину перед распознаванием — меньше галлюцинаций на записях с паузами | | `timestamp_granularities[]` | string | нет | `segment` | Детализация таймстампов: `word` или `segment` (поле можно повторять). Только с `response_format=verbose_json`. С `word` каждый сегмент дополняется массивом `words` с таймингом и вероятностью каждого слова | | `response_format` | string | нет | `json` | Формат результата: `json`, `text`, `srt`, `vtt`, `verbose_json` | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/audio/transcriptions \ -H "X-Api-Key: YOUR_API_KEY" \ -F "file=@call-recording.mp3" \ -F "language=ru" \ -F "response_format=json" ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/audio/transcriptions \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -F "file=@call-recording.mp3" \ -F "language=ru" \ -F "response_format=json" ``` ### JavaScript — личный ключ ```javascript const formData = new FormData() formData.append('file', audioFile) // объект File или Blob formData.append('language', 'ru') formData.append('response_format', 'json') const res = await fetch('https://vibecode.bitrix24.tech/v1/audio/transcriptions', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, body: formData, }) const result = await res.json() console.log('Распознанный текст:', result.text) ``` ### JavaScript — OAuth-приложение ```javascript const formData = new FormData() formData.append('file', audioFile) formData.append('language', 'ru') const res = await fetch('https://vibecode.bitrix24.tech/v1/audio/transcriptions', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, body: formData, }) const result = await res.json() console.log('Текст:', result.text) ``` ## Поля ответа Структура ответа зависит от `response_format`. Формат `json` (по умолчанию) — самый компактный, `verbose_json` — с таймингами. ### `response_format: json` | Поле | Тип | Описание | |------|-----|----------| | `text` | string | Распознанный текст целиком | ### `response_format: text` Ответ — обычная строка с распознанным текстом, без `JSON`-обёртки. ### `response_format: verbose_json` | Поле | Тип | Описание | |------|-----|----------| | `task` | string | Тип задачи: `transcribe` | | `language` | string | Код определённого или указанного языка | | `duration` | number | Длительность аудио в секундах | | `text` | string | Распознанный текст целиком | | `usage` | object \| null | Метаданные использования модели. `null`, если модель их не возвращает | | `words` | array | Пословные тайминги на уровне всего ответа. Пустой массив, если пословные тайминги не запрошены | | `segments` | array | Сегменты с таймингами и метаданными распознавания | | `segments[].id` | number | Порядковый номер сегмента | | `segments[].seek` | number | Внутренний сдвиг окна распознавания Whisper | | `segments[].start` | number | Начало сегмента в секундах | | `segments[].end` | number | Конец сегмента в секундах | | `segments[].text` | string | Текст сегмента | | `segments[].tokens` | array | Токены модели для текста сегмента (целые числа) | | `segments[].temperature` | number | Температура декодирования, применённая моделью | | `segments[].avg_logprob` | number | Средняя логарифмическая вероятность токенов сегмента — метрика уверенности | | `segments[].compression_ratio` | number | Коэффициент сжатия текста сегмента | | `segments[].no_speech_prob` | number | Вероятность того, что в сегменте нет речи | | `segments[].words` | array | Пословные тайминги внутри сегмента. Пустой массив, если не запрошены | | `segments[].emotion` | string \| null | Определённая эмоция сегмента. `null`, если не определена | ### `response_format: srt` / `vtt` Ответ — субтитры в формате `SubRip Text` или `WebVTT`. ## Пример ответа `response_format: json`: ```json { "text": "Здравствуйте, ООО Вектор. Хотим CRM на 50 пользователей, бюджет до 500 тысяч в месяц." } ``` `response_format: verbose_json`: ```json { "task": "transcribe", "language": "ru", "duration": 8.42, "text": "Здравствуйте, ООО Вектор. Хотим CRM на 50 пользователей, бюджет до 500 тысяч в месяц.", "usage": null, "words": [], "segments": [ { "id": 0, "seek": 0, "start": 0.0, "end": 3.2, "text": "Здравствуйте, ООО Вектор.", "tokens": [50365, 2425, 11, 341, 307], "temperature": 0.0, "avg_logprob": -0.38, "compression_ratio": 1.12, "no_speech_prob": 0.02, "words": [], "emotion": null }, { "id": 1, "seek": 320, "start": 3.2, "end": 8.42, "text": "Хотим CRM на 50 пользователей, бюджет до 500 тысяч в месяц.", "tokens": [50414, 1003, 13767, 295, 1500], "temperature": 0.0, "avg_logprob": -0.41, "compression_ratio": 1.20, "no_speech_prob": 0.01, "words": [], "emotion": null } ] } ``` ## Пример ответа при ошибке `400 no_file` — поле `file` не передано: ```json { "error": { "message": "Audio file is required. Send as multipart/form-data with field \"file\".", "type": "invalid_request_error", "code": "no_file" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `no_file` | Поле `file` не передано в `multipart/form-data` | | 400 | `empty_file` | Поле `file` передано, но файл пустой (0 байт). Частая причина: `curl -F "file=path"` без префикса `@` — curl отправляет строку пути вместо содержимого файла | | 400 | `invalid_prompt` | Поле `prompt` длиннее 2000 символов | | 400 | `invalid_hotwords` | Поле `hotwords` длиннее 500 символов | | 400 | `invalid_temperature` | Поле `temperature` не число или вне диапазона 0..1 | | 400 | `invalid_vad_filter` | Поле `vad_filter` не `true` и не `false` | | 400 | `invalid_timestamp_granularities` | Значение не `word`/`segment`, либо формат ответа не `verbose_json` | | 400 | `invalid_language` | Код языка не соответствует формату `ISO 639` (2-3 буквы) | | 402 | `ai_credentials_not_configured` | На платформе не настроен Bitrix-провайдер | | 402 | `insufficient_balance` | PREPAY-счёт ушёл за овердрафт — проверяется ДО вызова распознавания (только PLATFORM/PORTAL-ключи, BYOK бесплатен и не проверяется). Полностью замороженный счёт отклоняется раньше кодом `ACCOUNT_FROZEN` | | 402 | `ai_quota_exhausted` | Месячная AI-квота портала исчерпана — см. «Известные особенности» ниже | | 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` | | 502 | `ai_provider_unavailable` | Whisper-сервис вернул ошибку или недоступен | | 503 | `ai_provider_timeout` | Whisper не ответил в течение 15 минут — файл слишком длинный или сервис перегружен. Для записей длиннее ~30 минут разбивайте на части | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 429 | `ai_provider_cooldown` | Кластер распознавания временно недоступен, и платформа держит паузу, чтобы повторы его не добивали. Запрос не выполнялся, списания нет — повторите его через число секунд из `Retry-After`. Заголовков `X-RateLimit-Scope` и `X-AI-Admission` у этого ответа нет | | 429 | `ai_congested` | Пул AI-кластера перегружен. Запрос не выполнялся, списания нет, повторите его по заголовку `Retry-After`. Ответ несёт заголовок `X-AI-Admission: shed`, а не `X-RateLimit-Scope` | | 429 | `ai_pacing_limited` | Превышено суточное или недельное окно равномерного расходования квоты. Это не исчерпание квоты — повторите запрос по заголовку `Retry-After`. Подробнее — [«Равномерное расходование»](/docs/ai/consumption/quota#равномерное-расходование-pacing) | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Подсказки повышают точность на редких терминах.** Поле `prompt` задаёт контекст — тему разговора, стиль, правильное написание терминов. Поле `hotwords` перечисляет через запятую спец-слова, на которые декодер получает повышенный приоритет. Разница на фразе «обсуждаем интеграцию NeuralDeep с Kimi и подход RAG»: | Запрос | Результат | |---|---| | Без подсказок | «…интеграцию нейролдипскими и подход рак для поиска…» | | С `hotwords` | «…интеграцию NeuralDeep с Kimi и подход RAG для поиска…» | **В рамках квоты — без списаний, сверх квоты — по базовой цене модели.** Whisper работает на инфраструктуре Битрикс24. Расшифровка тарифицируется по длительности аудио и учитывается в месячной AI-квоте портала. Пока расход укладывается в квоту тарифа, деньги с баланса портала не списываются. Сверх квоты расход списывается с денежного баланса портала по базовой цене модели из каталога. На порталах с включённым контролем квоты запрос может вернуть `402 ai_quota_exhausted`, когда месячный лимит исчерпан. Поле `reason` различает три случая: `breaker` — сработал часовой предохранитель расходов сверх квоты, `wallet_empty` — квота исчерпана и на балансе портала нет средств, `wallet_off` — расход сверх квоты для портала недоступен. Поле `resetAt` — момент, когда запросы снова начнут проходить, для `wallet_off` оно может отсутствовать. В ветке `wallet_empty` ответ может дополнительно нести строку `hint` с подсказкой и ссылку `topupUrl` на пополнение баланса — оба поля появляются, когда на платформе включены принудительный контроль квоты и подсказка о пополнении, поэтому читайте их как необязательные. Поле `hint` в этом ответе — строка. **Лимит размера — 25 МБ.** Для длинных записей разбивайте файл на части до 25 МБ и склеивайте результаты на стороне клиента. Один час `mp3` 128 кбит/с примерно 60 МБ — придётся резать. **Тайм-аут запроса — 15 минут.** Расшифровка длится примерно 5-15 % от длины аудио. Файл на 5 минут (5-7 МБ `mp3`) расшифровывается за 15-45 секунд. При превышении тайм-аута возвращается `503 ai_provider_timeout`. ## Смотрите также - [Распознавание речи](/docs/ai/audio) - [Создать чат-комплишен](/docs/ai/chat/completions) - [AI Router](/docs/ai) --- # AI: Chat # Чат-комплишены Генерация ответа модели через единый OpenAI-совместимый эндпоинт. Поддерживает синхронный режим, потоковую передачу через `Server-Sent Events`, вызов функций, гарантированный `JSON`-ответ и работу с изображениями. Скоуп: `vibe:ai` ## Операции - [Создать чат-комплишен](./chat/completions.md) — `POST /v1/chat/completions` ## Возможности - [Потоковая передача](./chat/streaming.md) — ответ событиями `Server-Sent Events` по мере генерации - [Гарантированный JSON-ответ](./chat/json.md) — режимы `json_object` и `json_schema` - [Вызов функций](./chat/tools.md) — модель просит вызвать вашу функцию и получает результат - [Анализ изображений](./chat/vision.md) — передача графики в сообщении - [Лимиты запросов](./chat/rate-limits.md) — две корзины, коды `429` и `503`, рецепт повторов ## Типовой сценарий 1. Получите данные из CRM: [`GET /v1/deals/:id`](/docs/entities/deals/get). 2. Сгенерируйте ответ модели: [`POST /v1/chat/completions`](./chat/completions.md). 3. Запишите результат в таймлайн сделки: [`POST /v1/timeline-logs`](/docs/timeline-logs). ## Смотрите также - [AI Router](/docs/ai) - [Модели](/docs/ai/models) - [Жизненный цикл моделей](/docs/ai/models/lifecycle) --- # AI Chat: Completions ## Создать чат-комплишен > **Ответ приходит в сыром OpenAI-формате.** > > Обёртки `{success, data}`, которая используется в остальных эндпоинтах Вайбкод — `/v1/deals`, `/v1/tasks` и других, — здесь нет. > > Так сделано для совместимости с OpenAI SDK. Если у вас единый клиент с проверкой `if (!response.success)`, добавьте для AI Router исключение. `POST /v1/chat/completions` Генерирует ответ AI-модели на массив сообщений. Формат запроса и ответа совместим с `POST /v1/chat/completions` из OpenAI API. Возможности эндпоинта вынесены на отдельные страницы: [потоковая передача](./streaming.md), [гарантированный JSON-ответ](./json.md), [вызов функций](./tools.md), [анализ изображений](./vision.md) и [лимиты запросов](./rate-limits.md). ## Поля запроса (body) | Поле | Тип | Обяз. | По умолч. | Описание | |------|-----|:-----:|-----------|----------| | `model` | string | нет | `auto` | ID модели или алиас. См. секцию «Алиасы» ниже. Если поле не передано или равно `auto` — запрос выполняется на модели портала по умолчанию. Список доступных моделей — [`GET /v1/models`](/docs/ai/models/list) | | `messages` | array | да | — | Массив сообщений диалога. Минимум 1, максимум 256 | | `messages[].role` | string | да | — | Роль: `system`, `user`, `assistant`, `tool` | | `messages[].content` | string \| array \| null | да | — | Текст сообщения. Максимум 500 000 символов в одном сообщении или 64 элемента в массиве `content`. Для запросов с [изображениями](./vision.md) — массив с `type: "text"` и `type: "image_url"`. У `assistant` с `tool_calls` может быть `null` | | `messages[].name` | string | нет | — | Имя отправителя (мультиагентные сценарии) | | `messages[].tool_calls` | array | нет | — | Вызовы функций от ассистента — присутствуют в ответе модели при `finish_reason: "tool_calls"` | | `messages[].tool_call_id` | string | нет | — | ID вызова функции — обязателен в сообщении с `role: "tool"` | | `temperature` | number | нет | по модели | Температура генерации, диапазон `0..2`. Меньше — точнее и детерминированнее, больше — креативнее | | `max_tokens` | number | нет | по модели | Максимум токенов в ответе | | `top_p` | number | нет | — | Nucleus sampling, диапазон `0..1` | | `stop` | string \| array | нет | — | Стоп-последовательности (до 4 штук, каждая до 64 символов) | | `stream` | boolean | нет | `false` | Если `true` — ответ приходит [потоком](./streaming.md) `Server-Sent Events` | | `response_format` | object | нет | — | Управление [форматом ответа](./json.md): `{"type": "text"}` — значение по умолчанию, `{"type": "json_object"}` — корректный JSON, `{"type": "json_schema", "json_schema": {...}}` — строгая JSON Schema, требует поддержки моделью | | `tools` | array | нет | — | Определения [функций](./tools.md), которые модель может вызвать | | `tool_choice` | string \| object | нет | — | `auto` (модель решает сама), `none` (запретить вызовы) или `{"type": "function", "function": {"name": "..."}}` (форсировать конкретную) | ## Алиасы моделей Поле `model` принимает три значения, которые разрешаются в модель портала по умолчанию — сейчас это `bitrix/bitrixgpt-5.5`: `auto`, `bitrix/free` или пустая строка. Модели `bitrix/bitrixgpt-5` и `bitrix/bitrixgpt-5-vl` помечены как устаревшие и работают до 31 июля 2026 года. После этой даты запросы к ним прозрачно перенаправляются на `bitrix/bitrixgpt-5.5` с заголовком `X-Model-Replacement` — подробнее в [жизненном цикле моделей](/docs/ai/models/lifecycle). Кроме того, частичный `modelId` сопоставляется с каталогом по подстроке: если передан `gpt-4o-mini`, будет найдена доступная вашему ключу модель, в идентификаторе которой эта подстрока встречается. ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/chat/completions \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "bitrix/bitrixgpt-5.5", "messages": [ {"role": "system", "content": "Ты эксперт по продажам. Классифицируй лидов по качеству."}, {"role": "user", "content": "ООО Вектор, 50 пользователей, бюджет 500 тысяч в месяц."} ], "temperature": 0.3, "max_tokens": 300 }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/chat/completions \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "model": "bitrix/bitrixgpt-5.5", "messages": [ {"role": "system", "content": "Ты эксперт по продажам. Классифицируй лидов по качеству."}, {"role": "user", "content": "ООО Вектор, 50 пользователей, бюджет 500 тысяч в месяц."} ], "temperature": 0.3, "max_tokens": 300 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/chat/completions', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'bitrix/bitrixgpt-5.5', messages: [ { role: 'system', content: 'Ты эксперт по продажам. Классифицируй лидов по качеству.' }, { role: 'user', content: 'ООО Вектор, 50 пользователей, бюджет 500 тысяч в месяц.' }, ], temperature: 0.3, max_tokens: 300, }), }) const data = await res.json() console.log(data.choices[0].message.content) console.log('Токены:', data.usage.total_tokens) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/chat/completions', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'bitrix/bitrixgpt-5.5', messages: [ { role: 'system', content: 'Ты эксперт по продажам. Классифицируй лидов по качеству.' }, { role: 'user', content: 'ООО Вектор, 50 пользователей, бюджет 500 тысяч в месяц.' }, ], temperature: 0.3, max_tokens: 300, }), }) const data = await res.json() console.log(data.choices[0].message.content) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `id` | string | Уникальный ID комплишена для отслеживания | | `object` | string | Всегда `chat.completion` для синхронного ответа | | `created` | number | Unix-timestamp создания комплишена | | `model` | string | Фактически использованная модель (может отличаться от `model` запроса при автоматическом переключении на резервную модель или DISABLED-перенаправлении) | | `choices` | array | Варианты ответа модели. Без параметра `n` в массиве один элемент | | `choices[].index` | number | Порядковый номер варианта | | `choices[].finish_reason` | string | Причина завершения: `stop`, `length`, `tool_calls`, `content_filter` | | `choices[].message` | object | Сгенерированное сообщение | | `choices[].message.role` | string | Всегда `assistant` | | `choices[].message.content` | string \| null | Текст ответа. `null` при `finish_reason: "tool_calls"` — содержимое в `tool_calls` | | `choices[].message.tool_calls` | array | Список вызовов функций (если модель решила их вызвать) | | `warnings` | array | Предупреждения о том, что платформа изменила в запросе или что стоит учесть в ответе. У каждого элемента есть минимум `code` и `message`, у отдельных предупреждений — дополнительные поля. Известные коды: `MAX_TOKENS_RAISED`, `COWORK_QUOTA_FALLBACK` (несёт также `tier`, `nextTier`, `resetAt`), `THINKING_TRUNCATED`. Поле отсутствует, когда предупреждений нет | | `usage.prompt_tokens` | number | Токены входа | | `usage.completion_tokens` | number | Токены ответа | | `usage.total_tokens` | number | Сумма токенов в запросе и ответе | ## Пример ответа ```json { "id": "chatcmpl-a1a73c6eb3f180fd", "object": "chat.completion", "created": 1777289339, "model": "bitrix/bitrixgpt-5.5", "choices": [ { "index": 0, "finish_reason": "stop", "message": { "role": "assistant", "content": "Качество: ВЫСОКОЕ\n\nОбоснование:\n- Юридическое лицо (ООО) — B2B-клиент\n- Бюджет 500 тысяч в месяц — выше среднего\n- Конкретный объём (50 пользователей) — осознанная потребность\n\nРекомендация: назначить звонок в течение 24 часов." } } ], "usage": { "prompt_tokens": 42, "completion_tokens": 85, "total_tokens": 127 } } ``` ## Пример ответа при ошибке `404 ai_model_not_found` — модель не найдена или у ключа нет доступа к ней: ```json { "error": { "message": "Model \"anthropic/claude-imaginary-x\" not found or disabled.", "type": "invalid_request_error", "code": "ai_model_not_found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `invalid_request` | Пустой массив `messages`, неверная роль, нарушение схемы | | 400 | `invalid_image_payload` | Некорректный `image_url` — сообщение содержит номер элемента `content` и причину. См. [анализ изображений](./vision.md) | | 400 | `no_default_model` | У портала нет ни одной доступной для вызова модели | | 402 | `ai_credentials_not_configured` | Для модели нет учётных данных провайдера — подключите [BYOK](/docs/ai/credentials/create) | | 402 | `insufficient_balance` | Недостаточно средств для платной модели | | 402 | `ai_quota_exhausted` | Месячная [AI-квота портала](/docs/ai/consumption/quota) исчерпана. Поле `reason` уточняет причину | | 402 | `cowork_quota_exhausted` | Исчерпано одно из окон квоты подписки Cowork/Code. Тело несёт `window` (`5h`/`week`/`month`), `resetAt` и `nextTier`, заголовок `Retry-After` — число секунд до сброса окна | | 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` | | 404 | `ai_model_not_found` | Модель не найдена или отключена | | 422 | `structured_output_truncated` | Запрос с `response_format` не дал полного JSON: генерация оборвана по `finish_reason: "length"` либо поле `content` пустое при любой причине завершения и без `tool_calls`. В режиме `json_object` есть исключение — готовый JSON, попавший в служебный канал `reasoning_content`, восстанавливается, и ответ остаётся `200`. Подробнее — [гарантированный JSON-ответ](./json.md) | | 429 | `rate_limit_exceeded` | Превышен [лимит запросов](./rate-limits.md). Заголовок `X-RateLimit-Scope` указывает уровень — `per-key` или `per-user` | | 429 | `ai_congested` | Пул AI-кластера перегружен. Запрос не выполнялся, списания нет, повторите его по заголовку `Retry-After`. Ответ несёт заголовок `X-AI-Admission: shed`, а не `X-RateLimit-Scope` | | 429 | `ai_pacing_limited` | Превышено суточное или недельное окно равномерного расходования квоты. Это не исчерпание квоты — повторите запрос по заголовку `Retry-After`. Подробнее — [«Равномерное расходование»](/docs/ai/consumption/quota#равномерное-расходование-pacing) | | 429 | `ai_provider_cooldown` | Кластер моделей временно недоступен, и платформа держит паузу, чтобы повторы его не добивали. Запрос не выполнялся, списания нет — повторите его через число секунд из `Retry-After`. Заголовков `X-RateLimit-Scope` и `X-AI-Admission` у этого ответа нет | | 400 | `ai_provider_rejected` | Модель отклонила сам запрос (например неподдерживаемый параметр). Повторять его без изменений бесполезно. Возвращается, когда провайдер ответил `400` или `422` | | 502 | `ai_provider_unavailable` | Внешний провайдер вернул ошибку (`401`/`403`/`5xx`) или недоступен | | 503 | `model_unavailable` | Модель отключена, и преемник для неё не назначен. См. [жизненный цикл моделей](/docs/ai/models/lifecycle) | | 503 | `pool_exhausted` | Платформа временно перегружена. Повторите запрос через число секунд из `Retry-After` — это 3-7 секунд со случайным разбросом | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Автоматическое переключение на резервную модель при сбое провайдера.** Если у платной модели произошла ошибка `5xx` или таймаут, синхронный запрос повторяется с моделью по умолчанию. В ответе появляется заголовок `X-Model-Fallback: <исходный modelId>`. В потоковом режиме такого переключения нет — клиент получает ошибку в последнем событии перед `data: [DONE]`. **Исчерпанная квота Cowork/Code: ответ объявляет лимит, а не выполняет запрос.** Это отдельное состояние, не имеющее отношения к `X-Model-Fallback` выше: тот заголовок отмечает подмену модели, здесь же квота подписки исчерпана. Когда окно квоты исчерпано, а на платформе настроена резервная модель, запрос отвечает кодом `200`, но работа по нему не делается: поля `tools`, `tool_choice` и `response_format` снимаются, системные сообщения запроса не действуют, и модель сообщает, что лимит достигнут и когда он сбросится. Признаки состояния — заголовок `X-Cowork-Fallback: true` и предупреждение `COWORK_QUOTA_FALLBACK` в массиве `warnings`. В потоковом режиме предупреждения в теле нет, состояние видно по заголовку. Списания за такой ответ нет, квота не расходуется. Не ждите здесь `tool_calls` и JSON по схеме: даже с `response_format` в запросе придёт обычный текст. Если резервная модель не настроена — или настроенная сама не ответила, — приходит `402 cowork_quota_exhausted`. По коду ответа эти два случая не различаются, поэтому обрабатывайте `402` на этом эндпоинте всегда. **Месячная AI-квота портала.** На порталах с включённым контролем квоты запрос может вернуть `402 ai_quota_exhausted`. Поле `reason` различает три случая: `breaker` — сработал часовой предохранитель расходов сверх квоты, `wallet_empty` — квота исчерпана и на балансе портала нет средств, `wallet_off` — расход сверх квоты для портала недоступен. Поле `resetAt` содержит момент, когда запросы снова начнут проходить, для `wallet_off` оно может отсутствовать. В ветке `wallet_empty` ответ может дополнительно нести строку `hint` с подсказкой и ссылку `topupUrl` на пополнение баланса — оба поля появляются, когда на платформе включены принудительный контроль квоты и подсказка о пополнении, поэтому читайте их как необязательные. Поле `hint` в этом ответе — строка. Пока расход укладывается в квоту, поведение эндпоинта не меняется. Сверх квоты, если такой расход для портала разрешён, запросы списываются с денежного баланса портала по базовой цене модели из каталога. **Бюджет обработки синхронного запроса — около 850 секунд.** По исчерпании бюджета приходит `503 ai_provider_timeout`. Заголовка `Retry-After` в этом ответе нет намеренно: повтор того же запроса упрётся в тот же бюджет. Сократите объём запроса или перейдите на [потоковую передачу](./streaming.md) — там действует тайм-аут простоя между событиями, а не общий бюджет на весь вызов. **Лимит размера тела запроса — 30 MiB.** Этого хватает, чтобы передать одно изображение размером до 20 MiB: после кодирования base64 оно занимает около 27 MiB. **Передача `content` массивом.** Для текстовых моделей передавайте `content` строкой. Массив с одним элементом `text` тоже работает, но избыточен. Массив обязателен только для запросов с изображениями. ## Смотрите также - [Потоковая передача](./streaming.md) - [Гарантированный JSON-ответ](./json.md) - [Вызов функций](./tools.md) - [Анализ изображений](./vision.md) - [Лимиты запросов](./rate-limits.md) - [Жизненный цикл моделей](/docs/ai/models/lifecycle) - [Список моделей](/docs/ai/models/list) - [AI Router](/docs/ai) --- # AI Chat: Json ## Гарантированный JSON-ответ Параметр `response_format` заставляет модель вернуть машиночитаемый ответ вместо свободного текста. Есть два уровня строгости: `json_object` гарантирует корректный JSON произвольной формы, `json_schema` — соответствие заданной схеме. ## Режим `json_object` При `response_format: {"type": "json_object"}` модель возвращает корректный JSON в поле `content`. Вайбкод автоматически добавляет в системное сообщение инструкцию вернуть только JSON. Структуру результата опишите явно в системном сообщении: ```bash curl -X POST https://vibecode.bitrix24.tech/v1/chat/completions \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "bitrix/bitrixgpt-5.5", "messages": [ {"role": "system", "content": "Классифицируй лид. Верни JSON: {\"quality\": \"high|medium|low\", \"score\": 0-100}"}, {"role": "user", "content": "ООО Вектор, бюджет 2 миллиона в месяц"} ], "response_format": {"type": "json_object"} }' ``` Ответ: ```json { "id": "chatcmpl-acdb112cf9cdf9f9", "object": "chat.completion", "model": "bitrix/bitrixgpt-5.5", "choices": [ { "index": 0, "finish_reason": "stop", "message": { "role": "assistant", "content": "{\"quality\":\"high\",\"score\":92}" } } ], "usage": {"prompt_tokens": 56, "completion_tokens": 14, "total_tokens": 70} } ``` ## Режим `json_schema` `response_format: {"type": "json_schema", "json_schema": {...}}` гарантирует, что ответ модели **строго соответствует** заданной JSON Schema — модель не может вернуть лишние поля, пропустить обязательные или перепутать типы. Это строже, чем `json_object`, который гарантирует только корректный JSON. Режим доступен не на всех моделях. Актуальный список — в ответе [`GET /v1/me`](/docs/keys-auth), поле `ai.structuredOutputs.models`. ## Поля `json_schema` | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `name` | string | да | Имя схемы. До 64 символов, допустимы `a-zA-Z0-9_-` | | `schema` | object | да | Сама JSON Schema | | `strict` | boolean | нет | `true` — строгая проверка соответствия схеме. Рекомендуемое значение | | `description` | string | нет | Описание схемы для модели, помогает ей верно истолковать поля | ## Пример со схемой ```bash curl -X POST https://vibecode.bitrix24.tech/v1/chat/completions \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "bitrix/openai/gpt-oss-120b", "messages": [ {"role": "system", "content": "Верни строгий JSON по схеме."}, {"role": "user", "content": "Привет"} ], "response_format": { "type": "json_schema", "json_schema": { "name": "hello_response", "strict": true, "schema": { "type": "object", "properties": {"message": {"type": "string"}}, "required": ["message"], "additionalProperties": false } } } }' ``` Поле `choices[0].message.content` содержит строку, которая разбирается в объект, точно соответствующий схеме — например `{"message":"Привет"}`. ## Пример ответа при ошибке `400 model_does_not_support_structured_outputs` — модель не поддерживает `json_schema`. В поле `structuredOutputsModels` приходит список подходящих моделей: ```json { "error": { "message": "Model 'openai/o3' does not support response_format=json_schema. Use one of: bitrix/bitrixgpt-5.5, bitrix/bitrixgpt-5.5-thinking, openai/gpt-4o, bitrix/openai/gpt-oss-120b, openai/gpt-4o-mini.", "type": "invalid_request_error", "code": "model_does_not_support_structured_outputs", "param": "response_format.type", "structuredOutputsModels": ["bitrix/bitrixgpt-5.5", "bitrix/bitrixgpt-5.5-thinking", "openai/gpt-4o", "bitrix/openai/gpt-oss-120b", "openai/gpt-4o-mini", "openai/o3-mini"] } } ``` `422 structured_output_truncated` — генерация оборвана по лимиту токенов до полного JSON: ```json { "error": { "message": "The model's response was cut off (finish_reason=length) before a complete JSON document was produced, so it does not satisfy the requested response_format. Raise max_tokens, or reduce the schema/prompt size.", "type": "invalid_request_error", "code": "structured_output_truncated", "hint": "For reasoning models, max_tokens must cover the reasoning phase plus the JSON answer.", "param": "max_tokens", "finishReason": "length", "suggestedMaxTokens": 2048 } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `model_does_not_support_structured_outputs` | Модель не поддерживает `json_schema`. Список подходящих — в поле `structuredOutputsModels` | | 422 | `structured_output_truncated` | Модель оборвала генерацию до полного JSON или вернула пустой ответ | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Обрезанный ответ даёт `422 structured_output_truncated`.** Если модель оборвала генерацию до полного JSON (`finish_reason: "length"`), запрос с `response_format` возвращает `422` с полями `finishReason` и `suggestedMaxTokens`. Так ведут себя модели с рассуждением: фаза рассуждения расходует бюджет `max_tokens` до того, как модель напишет JSON. Обрабатывайте эту ошибку и повторяйте запрос с увеличенным `max_tokens` — можно взять значение из `suggestedMaxTokens`. Для строгого JSON задавайте `max_tokens` с запасом либо используйте модель без рассуждения. Поля `suggestedMaxTokens` и `param: "max_tokens"` присутствуют **только** при `finish_reason: "length"` — они указывают, что помогает увеличение бюджета токенов. Если причина завершения любая другая, а корректного JSON так и нет, ответ тоже `422`, но уже без этих двух полей — увеличение `max_tokens` не поможет, возьмите модель без рассуждения. Строка `hint` и поле `finishReason` есть в обеих ветках, `finishReason` может быть `null`. Если же модель с рассуждением на `json_object` завершилась сама и положила готовый корректный JSON в служебный канал `reasoning_content`, платформа восстанавливает этот JSON и возвращает `200` с ним в `content` — отдельной обработки не требуется. **Обрезанная попытка тарифицируется.** Ответ `422` приходит после того, как модель отработала, поэтому токены попытки учитываются в статистике расхода [`GET /v1/ai/usage`](/docs/ai/consumption/usage) и в месячной AI-квоте портала. Повтор с увеличенным `max_tokens` — это ещё один оплачиваемый вызов. **Заниженный `max_tokens` на бесплатной модели с рассуждением поднимается автоматически.** Если у бесплатной модели с рассуждением запрошен структурированный ответ, а `max_tokens` задан явно и ниже нижней границы, платформа поднимает его до этой границы и сообщает об этом на успешном ответе `200`: в теле появляется массив `warnings` с элементом `{"code": "MAX_TOKENS_RAISED", "message": "..."}`. Это не ошибка — читайте `warnings` как необязательное поле. Если `max_tokens` в запросе не задан, правка не применяется. **В потоковом режиме ошибка (и восстановленный ответ) приходят внутри потока.** Служебное событие `{"error":{"code":"structured_output_truncated"}}` идёт перед `data: [DONE]`. Восстановленный из `reasoning_content` JSON приходит событием потока с полем `content` перед терминальным событием с `finish_reason` — читайте поток до конца. **`json_object` не проверяет структуру.** Он гарантирует только то, что ответ разберётся как JSON. Набор полей и их типы остаются на усмотрение модели — если структура важна, используйте `json_schema` со `strict: true`. ## Смотрите также - [Создать чат-комплишен](./completions.md) - [Потоковая передача](./streaming.md) - [Вызов функций](./tools.md) - [Список моделей](/docs/ai/models/list) --- # AI Chat: Rate Limits ## Лимиты запросов и повторы Обращения к моделям ограничены двухуровневой корзиной, а при пиковой нагрузке платформа может ненадолго отказывать в обслуживании. Оба сигнала — `429` и `503` — означают «повтори позже», а не «запрос неверен». Ни один из них не списывает квоту. ## Два уровня корзины - **На ключ** — по умолчанию `600` запросов в минуту. Корзина привязана к ключу, а не к IP-адресу: клиент за NAT не делит её с другими ключами, а один и тот же ключ с разных адресов имеет общий счётчик. - **На пользователя** — по умолчанию `1500` запросов в минуту суммарно по всем ключам одного пользователя. Это защищает платформу, когда один аккаунт раздаёт десяток ключей агентам и каждый выбирает свой лимит. Запрос проверяется сначала по ключу, затем по пользователю. Первый исчерпанный счётчик выдаёт `429`. Для отдельных ключей — партнёрских интеграций, пакетных обработчиков — администратор платформы может поднять лимит на ключ. Лимит на пользователя при этом продолжает действовать. ## Ответ `429` ```json { "error": { "type": "rate_limit_exceeded", "code": "rate_limit_exceeded", "message": "Rate limit exceeded (per-key). Limit: 600 per minute. Retry after 12 seconds.", "scope": "per-key", "limit": 600, "retryAfter": 12 } } ``` Поле `scope` принимает одно из двух значений: - `per-key` — исчерпан лимит конкретного ключа. Снизьте число одновременных запросов этого ключа. - `per-user` — исчерпан общий лимит аккаунта. Снизьте суммарную нагрузку по всем ключам или попросите администратора платформы поднять лимит. Вместе с `429` приходят заголовки: - `Retry-After: <секунды>` — сколько ждать перед следующей попыткой. - `X-RateLimit-Scope: per-key | per-user` — уровень, в который упёрлись. Полезно для логов и метрик клиента. Лимит проверяется после проверки ключа, поэтому запросы с некорректным ключом (`401`) квоту не расходуют. ## Транзитные `503`: `pool_exhausted` и `db_transient` Помимо `429`, который означает превышение клиентской квоты, платформа может отдать `503` с одним из двух кодов. `pool_exhausted` — внутренний пул соединений с базой временно исчерпан, например при одновременном пике у нескольких клиентов. `db_transient` — транзакция в базе закрылась или истекла до того, как операция завершилась, и платформа откатила её целиком. Причины разные, реакция одна: это сигнал «попробуй ещё раз через несколько секунд», а не «инфраструктура сломана». Ответ всегда содержит заголовок `Retry-After` — целое число секунд от 3 до 7, со случайным разбросом на стороне сервера, чтобы массовое восстановление не било повторно в пул. В обычном (не потоковом) режиме обрабатывайте оба кода одинаково — по статусу `503` вместе с `Retry-After`, а не списком известных вам строк: так клиент переживёт появление третьего транзитного кода. ```json { "error": { "code": "pool_exhausted", "type": "server_error", "retryAfter": 5 } } ``` В потоковом режиме (`stream: true`) статус `200` уже отправлен до того, как платформа узнаёт о перегрузке, поэтому сигнал приходит последним событием потока: `data: { "error": { "code": "pool_exhausted", "retryAfter": <число> } }`, после чего идёт обычный `data: [DONE]`. Распознайте `code === "pool_exhausted"` и повторите запрос через `retryAfter` секунд. Есть и третий сигнал перегрузки — `429 ai_congested`. Он приходит, когда перегружен пул AI-кластера. Запрос при этом не выполнялся и списания нет. Отличить его от превышения квоты можно по заголовку `X-AI-Admission: shed`, которого нет у ответа `429 rate_limit_exceeded`. ## Ответ `429 ai_pacing_limited` Четвёртый ответ со статусом `429` не связан с нагрузкой на платформу. Он приходит, когда администратор портала включил равномерное расходование AI-квоты и вызов пробил суточное или недельное окно. Тело такого ответа приходит в конверте `{ "success": false, "error": { ... } }`, а не в сыром формате остальных ошибок этой страницы, и несёт поля `reason`, `overageDenied` и `resetAt`. Разбор полей и режимов — на странице [AI-квота компании](/docs/ai/consumption/quota). ## Ответ `429 ai_provider_cooldown` Пятый ответ со статусом `429` приходит, когда кластер моделей отвечает ошибками подряд и платформа перестаёт обращаться к нему, чтобы повторы не мешали ему восстановиться. Пауза снимается сама; заголовок `Retry-After` несёт её остаток в секундах. Запрос не выполнялся, списания нет. Длительность паузы не фиксирована: первая — около минуты, но если по её истечении кластер всё ещё отвечает ошибками, следующая пауза становится длиннее (до четырёх минут). Поэтому берите время ожидания из заголовка `Retry-After`, а не из фиксированной константы в своём коде. Отличить его от остальных `429` можно по коду и по отсутствию заголовков: у него нет ни `X-RateLimit-Scope` (он есть у `rate_limit_exceeded`), ни `X-AI-Admission` (он есть у `ai_congested`). В потоковом режиме статус `200` уже отправлен, поэтому сигнал приходит последним событием потока — тем же способом, что и `pool_exhausted`, с полем `retryAfter` внутри кадра ошибки. ## Ответ `429 ai_deadline_exceeded` Шестой ответ со статусом `429` приходит, когда запрос не уложился в **срок обслуживания** — предельное время, которое платформа готова держать вызов, прежде чем честно отказать. Раньше такой вызов просто обрывался по таймауту без тела; теперь у него есть объявленная граница и понятный отказ. Тело несёт код `ai_deadline_exceeded`, тип `rate_limit_exceeded` и поле `retryAfter`. Вместе с ним приходят два заголовка: `Retry-After` — пауза перед повтором в секундах, и `X-AI-Deadline-Ms` — бюджет, который реально был у этого запроса, в миллисекундах. Свой, более короткий бюджет можно назвать заголовком запроса `X-AI-Deadline-Ms` (миллисекунды). Он **только сокращает** срок: значение больше платформенного не выдаётся, а там, где срок отключён администратором, заголовок его не включает. Нечисловое или неположительное значение считается неуказанным и вызов не отклоняет. Срок отсчитывается от прихода запроса и покрывает всю его обработку целиком, включая автоматический повтор на резервной модели. В потоковом режиме статус `200` уже отправлен, поэтому отказ приходит последним событием потока — как у `pool_exhausted` и `stream_idle_timeout`, с полем `retryAfter` внутри кадра ошибки. Отличить его от `stream_idle_timeout` просто: тот означает «кластер замолчал посреди ответа», а этот — «времени на весь запрос больше нет», и он срабатывает даже когда фрагменты продолжают идти. ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 429 | `rate_limit_exceeded` | Превышен лимит запросов. Уровень — в поле `scope` и заголовке `X-RateLimit-Scope` | | 429 | `ai_congested` | Пул AI-кластера перегружен. Запрос не выполнялся, списания нет. Ответ несёт заголовок `X-AI-Admission: shed` | | 429 | `ai_pacing_limited` | Пробито суточное или недельное окно равномерного расходования квоты. Повторите запрос по заголовку `Retry-After` | | 429 | `ai_provider_cooldown` | Кластер моделей временно недоступен, платформа держит короткую паузу. Запрос не выполнялся, списания нет. Повторите его через число секунд из `Retry-After` | | 429 | `ai_deadline_exceeded` | Запрос не уложился в срок обслуживания. Повторите его через число секунд из `Retry-After`; фактический бюджет — в заголовке `X-AI-Deadline-Ms` | | 503 | `pool_exhausted` | Платформа временно перегружена. Повторите запрос через число секунд из `Retry-After` | | 503 | `db_transient` | Транзакция в базе закрылась до завершения операции, изменение откатилось целиком. Повторите запрос через число секунд из `Retry-After` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Готовый рецепт повторов ```javascript async function callWithBackoff(makeRequest, { maxAttempts = 5 } = {}) { for (let attempt = 0; attempt < maxAttempts; attempt++) { const res = await makeRequest() if (res.status === 429 || res.status === 503) { const retryAfterSec = Number(res.headers.get('retry-after')) || 0 // Соблюдаем Retry-After и добавляем небольшой случайный разброс, // чтобы параллельные обработчики не возвращались синхронно. const baseMs = retryAfterSec * 1000 || Math.min(1000 * 2 ** attempt, 30000) const jitterMs = Math.floor(Math.random() * 1000) await new Promise(r => setTimeout(r, baseMs + jitterMs)) continue } return res } throw new Error('Повторы исчерпаны') } ``` Что важно: - **Всегда соблюдайте `Retry-After`.** Он соответствует ожидаемому времени восстановления, меньший интервал ничего не ускоряет, а только нагружает платформу. - **Добавляйте собственный случайный разброс** поверх серверного — задержка в 100-1000 мс разрывает синхронные циклы обработчиков. - **Ограничивайте количество попыток.** Пяти достаточно для большинства сценариев, дальше возвращайте ошибку наружу. - **При `5xx` без `Retry-After`**, например при сбое на стороне провайдера, увеличивайте паузу по экспоненте: `min(2^attempt × 1s, 30s)` со случайным разбросом. - **Не запускайте `Promise.all` поверх тысяч записей.** Без пауз пакетная обработка упрётся в один из уровней корзины. ## Смотрите также - [Создать чат-комплишен](./completions.md) - [Потоковая передача](./streaming.md) - [Лимиты и оптимизация](/docs/optimization) - [Ошибки](/docs/errors) --- # AI Chat: Streaming ## Потоковая передача (Server-Sent Events) При `stream: true` ответ модели приходит потоком событий по мере генерации токенов, а не одним куском в конце. Первый байт доходит до клиента за секунды независимо от полной длины ответа. Заголовки ответа: `Content-Type: text/event-stream`, `Cache-Control: no-cache`, `Connection: keep-alive`. Каждое событие — строка `data: {JSON}\n\n`, завершающее событие — `data: [DONE]\n\n`. ## Формат событий ``` data: {"id":"chatcmpl-a9f6128818355f17","object":"chat.completion.chunk","model":"bitrix/bitrixgpt-5.5","choices":[{"index":0,"delta":{"role":"assistant","content":"CRM"}}]} data: {"id":"chatcmpl-a9f6128818355f17","object":"chat.completion.chunk","model":"bitrix/bitrixgpt-5.5","choices":[{"index":0,"delta":{"content":" — это"}}]} data: {"id":"chatcmpl-a9f6128818355f17","object":"chat.completion.chunk","model":"bitrix/bitrixgpt-5.5","choices":[{"index":0,"finish_reason":"stop","delta":{}}],"usage":{"prompt_tokens":10,"completion_tokens":15,"total_tokens":25}} data: [DONE] ``` `usage` приходит в последнем событии перед `[DONE]`. Накапливайте `delta.content` из всех событий для получения полного текста ответа. ## Пример обработки потока ```javascript const response = await fetch('https://vibecode.bitrix24.tech/v1/chat/completions', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'bitrix/bitrixgpt-5.5', messages: [{ role: 'user', content: 'Расскажи про CRM' }], stream: true, }), }) const reader = response.body.getReader() const decoder = new TextDecoder() let buffer = '' while (true) { const { done, value } = await reader.read() if (done) break buffer += decoder.decode(value, { stream: true }) const lines = buffer.split('\n') buffer = lines.pop() ?? '' for (const line of lines) { if (!line.startsWith('data: ')) continue const payload = line.slice(6) if (payload === '[DONE]') return const chunk = JSON.parse(payload) const delta = chunk.choices?.[0]?.delta?.content if (delta) process.stdout.write(delta) } } ``` ## Выбор режима под нагрузкой В синхронном режиме (`stream: false`) полный ответ модели собирается на сервере и уходит клиенту одним ответом — первый байт приходит вместе с последним. Для модели с длинной фазой рассуждения `bitrix/bitrixgpt-5.5-thinking` на длинном контексте и с развёрнутым ответом генерация занимает десятки секунд. Если клиентский таймаут короче полного времени генерации, соединение закрывается без единого полученного байта — например, `cURL error 28: Operation timed out, 0 bytes received`. На коротких запросах генерация укладывается в таймаут, и эффект не проявляется. В потоковом режиме (`stream: true`) сервер отправляет статус `200` и заголовки сразу после начала обработки, а события идут по мере генерации токенов, включая фазу рассуждения. Для объёмных запросов и моделей с рассуждением используйте `stream: true` — клиентский таймаут по приёму первого байта тогда не срабатывает. Ориентиры по клиентскому таймауту: - **Потоковый режим (`stream: true`)** — задавайте таймаут на приём первого события с запасом на обдумывание модели. Модель с рассуждением тратит несколько секунд до первого токена, значение от 30 секунд покрывает эту фазу с запасом. - **Синхронный режим (`stream: false`)** — таймаут по всему запросу должен покрывать полное время генерации, а не только сетевой обмен. Для объёмного запроса к модели с рассуждением это десятки секунд. Кроме того, при ошибке или таймауте провайдера синхронный запрос повторяется автоматически, и тогда финальный ответ или ошибка приходят через несколько минут. Поэтому значений 9-15 секунд недостаточно: задавайте таймаут по всему запросу с запасом на такие повторы — несколько минут — либо переходите на потоковый режим, где таймаут по приёму первого байта снимает проблему. ## Известные особенности **Резервной модели в потоке нет.** При сбое провайдера синхронный запрос повторяется с моделью по умолчанию, а в потоковом режиме клиент получает ошибку в последнем событии перед `data: [DONE]`. **Ошибки приходят внутри потока.** Статус `200` уже отправлен, когда платформа узнаёт о перегрузке или обрыве генерации, поэтому служебное событие вида `data: { "error": { "code": "pool_exhausted", "retryAfter": 5 } }` приходит перед `data: [DONE]`. Читайте поток до конца и проверяйте поле `error`. **Незавершённый структурированный ответ тоже приходит событием ошибки.** Если в запросе был `response_format`, а полного JSON модель не выдала, перед `data: [DONE]` приходит `data: { "error": { "code": "structured_output_truncated", "message": "...", "type": "invalid_request_error" } }`. В этом событии только три поля — `code`, `message` и `type`. Полей `finishReason`, `param` и `suggestedMaxTokens`, которые несёт синхронный ответ `422`, здесь нет. Текст `message` различается по причине завершения: генерация оборвана по `finish_reason: "length"` — предлагается повторить запрос с увеличенным `max_tokens`, поток закончился без причины завершения — ответ может быть неполным, модель завершилась сама с другой причиной — разбираемого JSON нет, рекомендуется модель без рассуждения. Подробнее — [гарантированный JSON-ответ](./json.md). **У потока есть общий срок обслуживания.** Кроме тайм-аута простоя у вызова теперь есть предельное время целиком: не уложился — поток завершается событием `data: { "error": { "code": "ai_deadline_exceeded", "type": "rate_limit_exceeded", "retryable": true, "retryAfter": <секунды> } }` перед `data: [DONE]`. Отличие от тайм-аута простоя в том, что этот срок срабатывает даже при непрерывно идущих токенах — он про длительность всего ответа, а не про паузу в нём. Свой, более короткий бюджет можно назвать заголовком запроса `X-AI-Deadline-Ms`; разбор — на странице [Лимиты и перегрузка](/docs/ai/chat/rate-limits). **Зависший ответ обрывается по тайм-ауту простоя.** Если модель отдала заголовки, но затем замолчала в середине ответа и не присылает новых данных дольше окна ожидания, платформа прерывает вызов и присылает `data: { "error": { "code": "stream_idle_timeout", "type": "server_error", "retryable": true, "retryAfter": <секунды> } }` перед `data: [DONE]`. Ошибка повторяемая — повторите запрос с учётом `retryAfter`. Непрерывный поток токенов (в том числе токенов рассуждений у «думающих» моделей) сбрасывает таймер простоя и под тайм-аут не попадает. ## Смотрите также - [Создать чат-комплишен](./completions.md) - [Лимиты запросов](./rate-limits.md) - [Гарантированный JSON-ответ](./json.md) - [AI Router](/docs/ai) --- # AI Chat: Tools ## Вызов функций (tools) Опишите функции, которые модель может вызвать, и она сама решит, когда это нужно. Модель не выполняет функцию — она возвращает её имя и аргументы, а вызов делает ваш код. Результат вы отправляете обратно в диалог, и модель формулирует финальный ответ. Когда модель решает вызвать функцию, `finish_reason` равен `tool_calls`, а `content` — `null`. Аргументы приходят в `tool_calls[].function.arguments` строкой с JSON. ## Описание функции ```bash curl -X POST https://vibecode.bitrix24.tech/v1/chat/completions \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "bitrix/bitrixgpt-5.5", "messages": [ {"role": "user", "content": "Какая погода в Москве?"} ], "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "Получить текущую погоду в указанном городе", "parameters": { "type": "object", "properties": { "city": {"type": "string", "description": "Название города"} }, "required": ["city"] } } } ], "tool_choice": "auto" }' ``` ## Пример ответа ```json { "id": "chatcmpl-9aaee7576d8057ab", "object": "chat.completion", "model": "bitrix/bitrixgpt-5.5", "choices": [ { "index": 0, "finish_reason": "tool_calls", "message": { "role": "assistant", "content": null, "tool_calls": [ { "id": "chatcmpl-tool-a423212c4e614cab", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\": \"Москва\"}" } } ] } } ], "usage": {"prompt_tokens": 275, "completion_tokens": 26, "total_tokens": 301} } ``` ## Возврат результата в диалог Выполните функцию у себя и добавьте в `messages` сообщение с ролью `tool` и тем же `tool_call_id`: ```json { "messages": [ {"role": "user", "content": "Какая погода в Москве?"}, {"role": "assistant", "content": null, "tool_calls": [{"id": "chatcmpl-tool-a423212c4e614cab", "type": "function", "function": {"name": "get_weather", "arguments": "{\"city\": \"Москва\"}"}}]}, {"role": "tool", "tool_call_id": "chatcmpl-tool-a423212c4e614cab", "content": "+5°C, облачно"} ] } ``` Следующим ответом модель сформулирует человеческий текст на основе полученного результата. ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `unsupported_tool_type` | В массиве `tools` есть элемент с `type`, отличным от `function`. Для поиска в интернете используйте [`POST /v1/search`](/docs/search/run) | | 400 | `tool_choice_without_tools` | Передан `tool_choice`, но массив `tools` отсутствует | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Поддерживается только `type: "function"`.** Встроенных инструментов вроде поиска в интернете у эндпоинта нет. Запрос с другим значением `type` отклоняется с `400`, а не выполняется молча без инструментов. **Имена в ответе сверяются с вашим списком.** Если модель придумала имя функции, которого нет в `tools`, такой вызов удаляется из ответа. Когда придуманными оказываются все вызовы, `finish_reason` меняется на `stop`, а в `content` приходит текстовое объяснение — диалог не зацикливается на несуществующей функции. **Аргументы приходят строкой.** Поле `arguments` — это JSON в виде строки, его нужно разобрать перед использованием. Модель может вернуть синтаксически корректный JSON, не соответствующий вашей схеме параметров, поэтому проверяйте значения перед вызовом. ## Смотрите также - [Создать чат-комплишен](./completions.md) - [Гарантированный JSON-ответ](./json.md) - [Веб-поиск](/docs/search/run) - [Список моделей](/docs/ai/models/list) --- # AI Chat: Vision ## Анализ изображений Модели с поддержкой изображений принимают графику через массив `content` с элементом `type: "image_url"`. Адрес изображения — либо `data:`-URI с данными в base64, либо ссылка `https`. В каталоге [`GET /v1/models`](/docs/ai/models/list) такие модели имеют флаг `capabilities.vision: true`. Бесплатно изображения обрабатывают `bitrix/bitrixgpt-5.5` и `bitrix/bitrixgpt-5.5-thinking`. Через свой ключ провайдера (BYOK) доступны модели Anthropic Claude: `anthropic/claude-opus-4-6`, `anthropic/claude-sonnet-4-6`, `anthropic/claude-haiku-4-5-20251001`. Для них платформа сама приводит элемент `image_url` к формату Anthropic — на стороне клиента менять ничего не нужно. ## Пример запроса ```bash curl -X POST https://vibecode.bitrix24.tech/v1/chat/completions \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "bitrix/bitrixgpt-5.5", "messages": [ { "role": "user", "content": [ {"type": "text", "text": "Опиши, что на изображении"}, {"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,/9j/4AAQSkZJRg..."}} ] } ], "max_tokens": 500 }' ``` ## Ограничения | Параметр | Значение | |----------|----------| | MIME-типы | `image/png`, `image/jpeg`, `image/gif`, `image/webp` | | Максимум на изображение, декодированный размер | 20 MiB | | Максимум `image_url.url` в запросе | 30 MiB, с запасом на кодирование base64 это 22 MiB полезных данных | | Формат `url` | `data:[;параметр=значение]*;base64,<данные>` или `https:///`. Параметры между типом и `;base64` (например `data:image/jpeg;name=photo.jpg;base64,…`) допускаются и отбрасываются | | Ссылки `http://` | не принимаются, только `https` или `data:` | | Максимум элементов `content` на сообщение | 64 | | Максимум тела запроса на эндпоинт | 30 MiB | **MiB** — мебибайт, двоичная единица по стандарту IEC 80000-13: `1 MiB = 2²⁰ = 1 048 576 байт ≈ 1,05 МБ`. Лимиты проверяются как `N × 1024 × 1024`, поэтому и в сообщении об ошибке размер указан в `MiB` — например, `decoded size 21.3 MiB exceeds limit 20 MiB`. ## Проверка содержимого Перед отправкой модели содержимое каждого элемента `image_url`, переданного как `data:`-URI, проверяется по фактическим байтам, а не по заявленному MIME-типу. Если содержимое не является изображением — например HTML-страница или ответ с ошибкой, закодированные в base64 и объявленные как `image/png`, — элемент не отбрасывается, а **заменяется на своей позиции** текстовой заглушкой `[image unavailable: <причина>]`. Остальные изображения обрабатываются как обычно, запрос завершается успешно. Проверка по содержимому применяется только к `data:`-URI. Кандидат по ссылке `https://` платформа передаёт модели как есть, без загрузки и проверки байтов, — такие ссылки валидируйте на своей стороне. Позиции элементов сохраняются: длина массива `content` не меняется, поэтому нумерация кандидатов на вашей стороне остаётся верной. Факт замены виден в ответе: - заголовок `X-Image-Parts-Rejected` несёт число заменённых элементов — это единый сигнал для всех режимов ответа; для потоковых ответов он приходит вместе с началом потока; - в обычном (не потоковом) ответе поле `warnings` дополнительно содержит запись с кодом `IMAGE_CONTENT_REJECTED` и деталями замен. В потоковом ответе поля `warnings` нет — ориентируйтесь на заголовок. ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `invalid_image_payload` | Структурная ошибка запроса: отсутствует поле `url`, строка не является ни URL, ни data-URI, бесформенный data-URI (без `;base64,`), неподдерживаемая схема или `http://` в production. Сообщение содержит номер элемента `content` и конкретную причину | Ошибки содержимого (не изображение, повреждённый base64, неподдерживаемый MIME-тип, превышение 20 MiB) **больше не завершают запрос ошибкой** — такой элемент заменяется заглушкой (см. «Проверка содержимого»). Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Массив `content` нужен только для изображений.** Для текстовых запросов передавайте `content` строкой. Массив с единственным элементом `text` тоже работает, но избыточен. **Размер проверяется после декодирования.** Ограничение в 20 MiB относится к самому изображению, а не к строке base64. Строка длиннее примерно на треть, поэтому тело запроса ограничено 30 MiB. ## Смотрите также - [Создать чат-комплишен](./completions.md) - [Список моделей](/docs/ai/models/list) - [Свои ключи (BYOK)](/docs/ai/credentials) --- # AI: Consumption # Расход и лимиты Сколько AI-ресурсов израсходовано, какая часть месячной квоты компании уже потрачена и в какие часы квота расходуется медленнее. Статистика считается **по API-ключу**: токены, стоимость и разбивка по моделям за выбранный период. Квота — **по порталу**: общий месячный лимит компании, единый для всех её ключей. Выгодные часы — расписание скидок, которое замедляет расход этой квоты в определённые часы недели. Скоуп: `vibe:ai` ## Операции - [Статистика использования](./consumption/usage.md) — `GET /v1/ai/usage` - [AI-квота компании](./consumption/quota.md) — `GET /v1/ai/quota` - [Расписание выгодных часов](./consumption/off-peak.md) — `GET /v1/off-peak` ## Типовой сценарий 1. Проверьте остаток квоты перед массовой обработкой: [`GET /v1/ai/quota`](./consumption/quota.md). Поля `pctUsed` и `exhausted` позволяют предупредить пользователя до отказа `402`. 2. Узнайте, когда квота расходуется медленнее: [`GET /v1/off-peak`](./consumption/off-peak.md), и перенесите задачи, которые терпят отсрочку, в дешёвые окна. 3. После обработки сверьте расход по ключу: [`GET /v1/ai/usage`](./consumption/usage.md). ## Смотрите также - [AI Router](/docs/ai) - [Список моделей](/docs/ai/models/list) - [Лимиты запросов](/docs/ai/chat/rate-limits) --- # AI Consumption: Off Peak ## Расписание выгодных часов `GET /v1/off-peak` Возвращает расписание выгодных часов: насколько медленнее расходуется AI-квота компании в каждый час недели и когда наступит ближайшее окно со скидкой. Скидка применяется к расходу квоты — в выгодные часы один и тот же вызов забирает меньшую долю месячного лимита. Оплата за токены по кошельку скидку не получает. Эндпоинт предназначен для планирования: агент читает расписание и переносит массовые задачи, которые терпят отсрочку, в дешёвые окна. ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|---------| | `model` (query) | string | нет | — | Идентификатор модели из [`GET /v1/models`](/docs/ai/models/list). Возвращает расписание этой модели. Без параметра возвращается расписание, отмеченное платформой как основное | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/off-peak?model=bitrix/bitrixgpt-5.5" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/off-peak?model=bitrix/bitrixgpt-5.5" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const url = 'https://vibecode.bitrix24.tech/v1/off-peak?model=bitrix/bitrixgpt-5.5' const res = await fetch(url, { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const schedule = await res.json() if (schedule.enabled && schedule.currentMultiplier < 1) { const discount = Math.round((1 - schedule.currentMultiplier) * 100) console.log(`Сейчас выгодный час: квота расходуется на ${discount}% медленнее`) } else if (schedule.nextWindow) { console.log(`Дешевле станет через ${schedule.nextWindow.inHours} ч`) } ``` ### JavaScript — OAuth-приложение ```javascript const url = 'https://vibecode.bitrix24.tech/v1/off-peak?model=bitrix/bitrixgpt-5.5' const res = await fetch(url, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const schedule = await res.json() ``` ## Поля ответа Успешный ответ — сам объект расписания, без обёртки `success` и `data`. | Поле | Тип | Описание | |------|-----|---------| | `enabled` | boolean | Действует ли расписание для запрошенной модели. При `false` все часы идут по полной цене, остальные поля пустые | | `timezone` | string \| null | Часовой пояс расписания — идентификатор из базы часовых поясов IANA, например `Europe/Moscow`. По нему считаются день недели и час | | `currentMultiplier` | number | Множитель расхода квоты в текущий час, больше `0` и не больше `1`. Значение `0.5` означает, что квота расходуется вдвое медленнее, значение `1` — без скидки | | `nextWindow` | object \| null | Ближайший час, который строго дешевле текущего, в пределах недели вперёд. `null`, когда такого часа нет | | `nextWindow.inHours` | number | Через сколько часов наступит этот час | | `nextWindow.multiplier` | number | Множитель расхода квоты в этом часе | | `currentWindowEndsInHours` | number \| null | Через сколько часов расход перестанет быть таким же выгодным. `null`, если в пределах недели вперёд дороже не станет — в том числе когда текущий час идёт по полной цене | | `grid` | array \| null | Сетка множителей `grid[день][час]`. Семь строк по 24 значения. День `0` — воскресенье, день `6` — суббота. Час — от `0` до `23` в часовом поясе `timezone` | | `nowCell` | object \| null | Ячейка сетки, которой соответствует текущий момент. Считается на сервере, поэтому совпадает с `currentMultiplier` | | `nowCell.dow` | number | День недели, от `0` (воскресенье) до `6` (суббота) | | `nowCell.hour` | number | Час, от `0` до `23` | ## Пример ответа Расписание действует: ```json { "enabled": true, "timezone": "Europe/Moscow", "currentMultiplier": 1, "nextWindow": { "inHours": 4, "multiplier": 0.87 }, "currentWindowEndsInHours": null, "grid": [ [0.75, 0.87, 0.87, 0.87, 0.87, 0.87, 0.87, 0.87, 0.75, 0.75, 0.75, 0.75, 0.62, 0.5, 0.75, 0.87, 1, 1, 0.87, 0.87, 0.87, 0.75, 0.75, 0.75], [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.62, 0.62, 0.62, 0.62, 0.75, 0.75, 0.87, 0.87, 0.75, 0.75, 0.75, 0.75, 0.62, 0.5, 0.5], [0.5, 0.5, 0.62, 0.62, 0.75, 0.62, 0.62, 0.62, 0.75, 0.75, 0.87, 1, 1, 0.87, 0.75, 0.87, 0.87, 0.75, 0.75, 0.62, 0.62, 0.62, 0.62, 0.62], [0.75, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.62, 0.62, 0.62, 0.75, 0.75, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.87], [1, 1, 1, 1, 1, 0.87, 0.87, 0.87, 0.87, 1, 1, 1, 1, 1, 1, 0.87, 0.75, 0.75, 0.75, 0.87, 1, 1, 1, 1], [1, 1, 1, 1, 1, 0.87, 0.87, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.87, 0.87, 0.75, 0.87], [0.75, 0.62, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.62, 0.75, 0.75, 0.62, 0.62, 0.75, 0.75, 0.87, 0.87, 1, 1, 1, 1, 0.87] ], "nowCell": { "dow": 4, "hour": 11 } } ``` Расписание не действует — у модели его нет, либо выгодные часы отключены на платформе: ```json { "enabled": false, "timezone": null, "currentMultiplier": 1, "nextWindow": null, "currentWindowEndsInHours": null, "grid": null, "nowCell": null } ``` ## Пример ответа при ошибке `401 MISSING_API_KEY` — не передан заголовок `X-Api-Key`: ```json { "success": false, "error": { "code": "MISSING_API_KEY", "message": "API key required. Pass via X-Api-Key header." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Ключ не найден или отозван | | 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` | | 429 | `rate_limit_exceeded` | Превышен лимит запросов к AI-эндпоинтам. Время до сброса — в заголовке `Retry-After` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Множитель — коэффициент расхода, а не размер скидки.** Значение `0.62` означает, что вызов забирает 62% от той доли квоты, которую он забрал бы без скидки, то есть расход снижен на 38%. Размер скидки считается как `1 - currentMultiplier`. **Указывайте модель.** Без параметра `model` эндпоинт отдаёт расписание, отмеченное платформой как основное. Пока основное расписание не назначено, такой вызов возвращает `enabled: false`, даже если у отдельных моделей скидки действуют. **Неизвестная модель не даёт ошибки.** Если у модели нет расписания или идентификатор не существует, приходит `200` с `enabled: false` и пустыми полями. Признак наличия скидок — поле `enabled`, а не код ответа. **Расписание меняется.** Платформа пересчитывает сетку по фактической нагрузке, поэтому перечитывайте расписание перед планированием, а не сохраняйте его надолго. **`nextWindow` ищет строго более дешёвый час.** Если текущий час уже самый дешёвый в пределах недели вперёд, поле равно `null`. Это не означает отсутствия скидки — смотрите `currentMultiplier`. **Скидка замедляет заполнение окон равномерного расходования.** Суточное и недельное окна растут на ту же величину расхода, что и месячная квота, то есть уже со скидкой. Перенос отложенных задач в выгодные часы отдаляет и `429 ai_pacing_limited`, и исчерпание месячной квоты. ## Смотрите также - [AI-квота компании](/docs/ai/consumption/quota) - [Список моделей](/docs/ai/models/list) - [Чат-комплишены](/docs/ai/chat/completions) - [AI Router](/docs/ai) --- # AI Consumption: Quota ## AI-квота компании `GET /v1/ai/quota` Возвращает состояние месячной AI-квоты портала, к которому привязан API-ключ: процент израсходованного лимита, дату сброса и разбивку по моделям — сколько запросов пришлось на каждую модель и какую долю месячного лимита она израсходовала. Квота — портальная: лимит общий для всей компании, а не per-ключ. Абсолютные значения лимита (в Вайбах) API не раскрывает — только проценты. ## Параметры Без параметров. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/ai/quota" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/ai/quota" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/ai/quota', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() console.log(`Квота использована на ${data.pctUsed}%, сброс ${data.resetAt}`) data.byModel.forEach((m) => { console.log(` ${m.modelId}: ${m.calls} запросов, ${m.pctOfLimit ?? 0}% лимита`) }) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/ai/quota', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() console.log(`Квота использована на ${data.pctUsed}%, сброс ${data.resetAt}`) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data.pctUsed` | number | Процент израсходованной месячной квоты. Честное значение — не обрезается на 100: перерасход показывается как есть (например, `150`) | | `data.exhausted` | boolean | `true`, когда квота исчерпана | | `data.resetAt` | string \| null | Дата сброса квоты в `ISO 8601` (скользящее 30-дневное окно). `null`, пока по порталу не было ни одного тарифицируемого AI-вызова | | `data.pacing` | object \| null | Состояние равномерного расходования квоты (пейсинг). `null`, если пейсинг выключен для портала — не включён ни платформой, ни администратором (см. «Равномерное расходование (pacing)» ниже) | | `data.pacing.mode` | string | Режим реакции на превышение окна: `wallet`, `block` или `ignore` | | `data.pacing.active` | boolean | `true`, только если превышение окна прямо сейчас приведёт к `429`: энфорсмент включён на платформе и режим не `ignore`. `false` — режим наблюдения или `ignore`: окна только информируют, блокировок и списаний нет | | `data.pacing.day.pctUsed` | number | Расход суточного окна в процентах от его собственного лимита (не от месячной квоты) | | `data.pacing.day.resetAt` | string | Момент сброса суточного окна в `ISO 8601` | | `data.pacing.week.pctUsed` | number | Расход недельного окна в процентах от его собственного лимита | | `data.pacing.week.resetAt` | string | Момент сброса недельного окна в `ISO 8601` | | `data.period.start` | string | Начало текущего окна квоты в `ISO 8601` | | `data.byModel` | array | Разбивка по моделям за текущее окно, сортировка по убыванию количества вызовов | | `data.byModel[].modelId` | string | ID модели | | `data.byModel[].calls` | number | Количество успешных вызовов | | `data.byModel[].pctOfLimit` | number \| null | Доля месячного лимита, израсходованная этой моделью, в процентах (один знак после запятой). `null`, когда у портала нет положительного лимита | ## Пример ответа ```json { "success": true, "data": { "pctUsed": 12, "exhausted": false, "resetAt": "2026-07-31T18:50:39.633Z", "pacing": { "mode": "wallet", "active": false, "day": { "pctUsed": 42, "resetAt": "2026-07-10T21:00:00.000Z" }, "week": { "pctUsed": 18, "resetAt": "2026-07-13T21:00:00.000Z" } }, "period": { "start": "2026-07-01T18:50:39.633Z" }, "byModel": [ { "modelId": "bitrix/openai/gpt-oss-120b", "calls": 63017, "pctOfLimit": 10.9 }, { "modelId": "bitrix/bitrixgpt-5.5", "calls": 1240, "pctOfLimit": 1.2 } ] } } ``` ## Равномерное расходование (pacing) Пейсинг — дополнительные суточный и недельный лимиты расхода AI-квоты, каждый в процентах от общего месячного лимита. Платформа может включать пейсинг для портала по умолчанию (без действий администратора); раскатка поэтапная, поэтому не каждый портал уже покрыт. Администратор портала может включить пейсинг сам в кабинете `/ai`; если портал под платформенным default-on — только ужесточить лимиты: ослабить их или выключить пейсинг нельзя, пока портал управляется платформенными настройками по умолчанию. Пейсинг не меняет саму месячную квоту — он сглаживает пики, не позволяя потратить весь месячный лимит за один день или час. Режим реакции на превышение окна настраивается администратором и приходит в поле `pacing.mode`: | Режим | Поведение при превышении окна | |-------|-------------------------------| | `wallet` | Вызов проходит как оплачиваемое превышение лимита — списывается с денежного баланса портала, при наличии средств и свободного часового лимита превышений | | `block` | Вызов отклоняется `429` до сброса окна — оплачиваемое превышение недоступно | | `ignore` | Окно считается для мониторинга, вызовы не блокируются | ### Поле `pacing` в ответе Текущее состояние пейсинга отдаётся в `data.pacing` (см. «Поля ответа» выше) — `null`, если пейсинг выключен для портала (не включён ни платформой, ни администратором): ```json { "mode": "wallet", "active": false, "day": { "pctUsed": 42, "resetAt": "2026-07-10T21:00:00.000Z" }, "week": { "pctUsed": 18, "resetAt": "2026-07-13T21:00:00.000Z" } } ``` `active: false` означает, что превышение окна не приводит к `429` — это информационный режим: лимиты окон показываются в ответе, но не отклоняют запросы (`429` в этом состоянии невозможен). Так бывает и в демо-режиме платформенного энфорсмента, и при `mode: "ignore"` — режиме, который платформа применяет к порталам под default-on. `active: true` — превышение окна прямо сейчас приведёт к отказу в вызове. Как и весь ответ `GET /v1/ai/quota`, состояние пейсинга кэшируется — статус запаздывает до 30 секунд. ### Ошибка при превышении окна Когда пейсинг активен и суточный или недельный лимит пробит, запросы к [чат-комплишенам](/docs/ai/chat/completions), [эмбеддингам](/docs/ai/embeddings) и [расшифровке аудио](/docs/ai/audio/transcriptions) отвечают `429`: ```json { "success": false, "error": { "code": "ai_pacing_limited", "type": "rate_limit_exceeded", "message": "AI pacing window exceeded for this portal. Wait for the window reset or adjust pacing settings in the cabinet.", "reason": "day_window", "overageDenied": "wallet_empty", "resetAt": "2026-07-11T00:00:00.000Z", "retryAfter": 3600 } } ``` | Поле | Тип | Описание | |------|-----|----------| | `reason` | string | Какое окно пробито: `day_window` или `week_window` | | `overageDenied` | string \| null | Причина отказа в оплачиваемом превышении лимита. Присутствует в ответе всегда: `wallet_empty` — не хватает средств на балансе портала, `breaker` — сработал часовой предохранитель расхода сверх квоты, `wallet_off` — портал не может расходовать сверх лимита. `null` — в режиме `block`, где оплачиваемое превышение недоступно в принципе | | `resetAt` | string | Момент, когда окно сбросится и вызовы снова начнут проходить, в `ISO 8601` | | `retryAfter` | number | То же время в секундах — совпадает со значением заголовка ответа `Retry-After` | ### Как реагировать - **Соблюдайте `Retry-After` и `resetAt`.** Повторный вызов раньше указанного времени ничего не ускорит — квота не станет доступнее. - **В режиме `wallet` смотрите `overageDenied`.** `429` в этом режиме означает не «пейсинг запрещает вызовы вообще», а «отказано именно в оплачиваемом превышении лимита» — например, `wallet_empty` сигнализирует, что стоит пополнить баланс портала. - **Это не то же самое, что `402 ai_quota_exhausted`.** Пейсинг ограничивает скорость расхода в рамках ещё не исчерпанной месячной квоты. Ошибка `402` — сигнал о полном исчерпании самой квоты. Подробнее про `402` — в [описании ошибок чата](/docs/ai/chat/completions). ## Пример ответа при ошибке `403 scope_missing` — у API-ключа нет скоупа `vibe:ai`: ```json { "error": { "message": "API key does not have the vibe:ai scope required for AI endpoints. Add vibe:ai scope to your API key in portal settings.", "type": "invalid_request_error", "code": "scope_missing" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Ключ не найден или отозван | | 429 | `rate_limit_exceeded` | Превышен лимит запросов к AI-эндпоинтам. Время до сброса — в заголовке `Retry-After` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`pctOfLimit` считается по моделям программы квоты.** Модель, не входящая в программу квоты (для неё не настроена тарифная политика), присутствует в `byModel` со счётчиком вызовов, но её `pctOfLimit` равен `0` — она не расходует квоту. **Разбивка не включает Cowork-трафик.** Вызовы, тарифицируемые персональной подпиской Cowork/Code, не расходуют квоту компании и в разбивку не входят. **Сумма `pctOfLimit` может отличаться от `pctUsed`.** `pctUsed` читается из леджера квоты и отражает условия тарификации на момент вызова (включая скидку «выгодных часов», если она активна), а `pctOfLimit` — пиковая оценка: пересчёт по текущим тарифным политикам за окно, без учёта скидок. При смене политик в середине окна значения могут расходиться. **Ответ кэшируется на 30 секунд.** Счётчики обновляются с задержкой до 30 секунд — для мониторинга квоты этого достаточно, опрашивать чаще нет смысла. **При исчерпании квоты вызовы моделей отвечают `402 ai_quota_exhausted`.** Подробнее — в описании ошибок [чата](/docs/ai/chat). Чтобы предупредить пользователя заранее, опрашивайте `pctUsed` и `exhausted` до вызова модели, а не дожидайтесь отказа. **При срабатывании пейсинга вызовы моделей отвечают `429 ai_pacing_limited`.** Отдельно от `402 ai_quota_exhausted` — пейсинг ограничивает скорость расхода ещё не исчерпанной квоты. Подробнее — в разделе «Равномерное расходование (pacing)» выше. ## Смотрите также - [Расписание выгодных часов](/docs/ai/consumption/off-peak) - [Статистика использования](/docs/ai/consumption/usage) - [Список моделей](/docs/ai/models/list) - [AI Router](/docs/ai) --- # AI Consumption: Usage ## Статистика использования `GET /v1/ai/usage` Возвращает агрегированную статистику использования AI для текущего API-ключа: общие показатели за период, разбивку по моделям, последние 10 вызовов и группировку по типу учётных данных (`PLATFORM`, `PORTAL`, `USER`). ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|----------| | `days` (query) | number | нет | `30` | Период в днях. Допустимый диапазон: `1..90`. Значения вне диапазона автоматически приводятся к границам | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/ai/usage?days=7" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/ai/usage?days=7" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/ai/usage?days=7', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() console.log(`За ${data.period.days} дней: ${data.totals.calls} вызовов, ${data.totals.totalTokens} токенов`) data.byModel.forEach((m) => console.log(` ${m.modelId}: ${m.calls} запросов, ${m.cost} Вайбов`)) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/ai/usage?days=30', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() console.log('Стоимость за 30 дней:', data.totals.cost, 'Вайбов') ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data.period.days` | number | Фактический период в днях (после ограничения 1..90) | | `data.period.since` | string | Начало периода в `ISO 8601` | | `data.totals.calls` | number | Общее количество вызовов за период (все статусы) | | `data.totals.promptTokens` | number | Сумма токенов входа | | `data.totals.completionTokens` | number | Сумма токенов ответа | | `data.totals.totalTokens` | number | Сумма всех токенов | | `data.totals.cost` | number | Общая стоимость в Вайбах | | `data.byModel` | array | Разбивка успешных вызовов по моделям, сортировка по убыванию количества | | `data.byModel[].modelId` | string | ID модели | | `data.byModel[].calls` | number | Количество вызовов | | `data.byModel[].promptTokens` | number | Токены входа | | `data.byModel[].completionTokens` | number | Токены ответа | | `data.byModel[].totalTokens` | number | Сумма токенов | | `data.byModel[].cost` | number | Стоимость в Вайбах | | `data.byModel[].audioSeconds` | number | Секунды расшифрованного аудио (Whisper). Для текстовых моделей — `0` | | `data.recentCalls` | array | Последние 10 вызовов любого статуса | | `data.recentCalls[].modelId` | string | ID модели | | `data.recentCalls[].promptTokens` | number | Токены входа | | `data.recentCalls[].completionTokens` | number | Токены ответа | | `data.recentCalls[].cost` | number | Стоимость вызова в Вайбах | | `data.recentCalls[].status` | string | Статус: `SUCCESS`, `ERROR`, `INCOMPLETE`, `FALLBACK_ORIGIN`, `DISABLED_REDIRECT` | | `data.recentCalls[].createdAt` | string | Время вызова в `ISO 8601` | | `data.byScope` | object | Разбивка по типу учётных данных провайдера, ключи: `PLATFORM`, `PORTAL`, `USER` | | `data.byScope..calls` | number | Количество вызовов через этот тип учётных данных | | `data.byScope..promptTokens` | number | Токены входа | | `data.byScope..completionTokens` | number | Токены ответа | ## Пример ответа ```json { "success": true, "data": { "period": { "days": 7, "since": "2026-04-20T11:30:00.000Z" }, "totals": { "calls": 142, "promptTokens": 45200, "completionTokens": 18300, "totalTokens": 63500, "cost": 12.5 }, "byModel": [ { "modelId": "bitrix/bitrixgpt-5.5", "calls": 98, "promptTokens": 28000, "completionTokens": 11000, "totalTokens": 39000, "cost": 0, "audioSeconds": 0 }, { "modelId": "openai/gpt-4o", "calls": 44, "promptTokens": 17200, "completionTokens": 7300, "totalTokens": 24500, "cost": 12.5, "audioSeconds": 0 } ], "recentCalls": [ { "modelId": "bitrix/bitrixgpt-5.5", "promptTokens": 120, "completionTokens": 85, "cost": 0, "status": "SUCCESS", "createdAt": "2026-04-27T11:30:00.000Z" }, { "modelId": "openai/gpt-4o", "promptTokens": 350, "completionTokens": 200, "cost": 0.28, "status": "SUCCESS", "createdAt": "2026-04-27T09:45:00.000Z" } ], "byScope": { "PLATFORM": { "calls": 98, "promptTokens": 28000, "completionTokens": 11000 }, "USER": { "calls": 44, "promptTokens": 17200, "completionTokens": 7300 } } } } ``` ## Пример ответа при ошибке `403 scope_missing` — у API-ключа нет скоупа `vibe:ai`: ```json { "error": { "message": "API key does not have the vibe:ai scope required for AI endpoints. Add vibe:ai scope to your API key in portal settings.", "type": "invalid_request_error", "code": "scope_missing" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `no_api_key` | Запрос пришёл без идентификатора API-ключа | | 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`recentCalls` всегда содержит до 10 записей.** Они не зависят от параметра `days` — это просто последние 10 вызовов независимо от того, попадают ли они в выбранный период. **`byModel` учитывает только `SUCCESS`.** Разбивка по моделям не включает ошибочные вызовы. Общие счётчики `totals` — все вызовы (включая `ERROR`, `INCOMPLETE`). **Стоимость в Вайбах.** Поле `cost` — это стоимость в Вайбах (внутренняя валюта платформы), не в рублях и не в долларах. Модели с нулевой ценой в каталоге (большинство `bitrix/*`) и BYOK дают `cost: 0`. Часть платформенных моделей платная — цена берётся из тарифной таблицы `AiModel.inputPriceVibes` / `AiModel.outputPriceVibes`, посмотреть её можно в [`GET /v1/models`](/docs/ai/models/list). **`byScope.USER` — это вызовы через ваш BYOK.** Если вы используете подключённый BYOK-ключ — статистика попадает в `byScope.USER`. Платформенные модели — в `byScope.PLATFORM`. Если у портала настроены PORTAL-credentials — в `byScope.PORTAL`. Когда вызовов с каким-то scope не было — ключ просто отсутствует в объекте. ## Смотрите также - [Статистика по ключу](/docs/ai/credentials/usage) - [Список моделей](/docs/ai/models/list) - [AI Router](/docs/ai) --- # AI: Credentials # Свои ключи (BYOK) Подключение собственных ключей провайдеров (`Bring Your Own Key`). Все запросы через ваш ключ идут напрямую к провайдеру и **не списываются** с баланса Вайбкод — вы платите провайдеру по его тарифам. Поддерживаемые провайдеры: OpenAI, Anthropic, OpenRouter, Google Gemini, Mistral AI, Groq, Together AI, DeepSeek, Fireworks AI, Cerebras, Cohere, Minimax, Qwen, Yi, а также **Custom OpenAI-Compatible** для подключения любого совместимого по API сервиса (требует указать `baseUrl`). Скоуп: `vibe:ai` ## Что нужно знать перед работой 1. **Один ключ на провайдера.** Повторное подключение того же провайдера через `POST /v1/ai/credentials` вернёт `409 already_exists`. Чтобы заменить ключ — обновите существующий через `PATCH`. 2. **Верификация при сохранении.** При создании и при обновлении поля `credentials` ключ проверяется у провайдера (`POST` к `/chat/completions` или `GET /v1/models`). Некорректный ключ — `422 credential_invalid` с сообщением от провайдера. 3. **`Custom OpenAI-Compatible`.** Требует `baseUrl` в формате `https://...` или `http://...`. Приватные сети (loopback, RFC 1918, link-local) запрещены, защита от `SSRF` (Server-Side Request Forgery — подделка серверных запросов). 4. **Таблица моделей зависит от провайдера.** Для большинства провайдеров каталог фиксирован. Для Custom-сервиса каталог либо загружается с эндпоинта провайдера через `fetch-models`, либо собирается вручную через `models-add`. 5. **Приоритет ключей.** Ваш USER-ключ имеет приоритет над ключом, который администратор портала подключил для всех. Если оба настроены — будет использован ваш. 6. **V1 управляет только USER-ключами.** Ключи на уровне портала (PORTAL-scope, доступные всем участникам) подключаются администратором в кабинете Вайбкод, не через V1. ## Лимиты | Лимит | Значение | |-------|----------| | Создание ключа | 10 запросов в минуту | | Проверка ключа | 10 запросов в минуту | | Изменение ключа (с проверкой) | 10 запросов в минуту | | Загрузка каталога моделей | 10 запросов в минуту | | Регистрация / удаление модели вручную | 30 запросов в минуту | Лимиты считаются **на портал**: все API-ключи одного портала делят единый бакет. При превышении возвращается `429` с заголовком `Retry-After`. ## Ключ не подключается из РФ {#geo-block-faq} OpenAI, Anthropic и некоторые другие провайдеры блокируют запросы по IP сервера. Если при сохранении ключа вы видите ошибку `PROVIDER_GEOBLOCKED`, выберите один из двух путей: 1. **Использовать OpenRouter** — у них POP в Сингапуре, блокировок нет. Заведите свой ключ на [openrouter.ai](https://openrouter.ai/) и подключите как BYOK-провайдер «openrouter». Через него работают модели OpenAI, Anthropic, Google, Meta и десятки других. 2. **Указать свой прокси** — если у вас уже есть HTTP/HTTPS-прокси в неблокируемой юрисдикции, разверните «Расширенные настройки» в форме подключения ключа и укажите URL в формате `https://user:pass@host:port`. Все запросы по этому ключу будут идти через ваш прокси (включая первичную проверку ключа). ### Куда платформа смотрит на geo-block Признаки, которые срабатывают как «провайдер блокирует по региону»: - HTTP 403 + текст ответа содержит `country` / `region` / `territory` / `unsupported location` - HTTP 451 (Unavailable For Legal Reasons) - Структурированный код ошибки OpenAI `unsupported_country_region_territory` - Сетевой обрыв на `api.openai.com` / `api.anthropic.com` (`ECONNREFUSED` / `EHOSTUNREACH` / `ETIMEDOUT`) Если ключ прошёл первичную проверку, но потом сломался на реальных вызовах `/v1/chat/completions`, на карточке ключа в `/ai` появится бейдж «Заблокирован по IP». Это означает, что провайдер начал блокировать запросы после момента сохранения ключа — действия те же: добавить прокси или мигрировать на OpenRouter. > ⚠️ **Юридическая заметка.** Использование прокси для обхода географических > ограничений может нарушать Terms of Service провайдера. Ответственность за > соответствие условиям использования ключа лежит на вас. ## Операции - [Список провайдеров](./credentials/providers.md) — `GET /v1/ai/providers` - [Список ключей](./credentials/list.md) — `GET /v1/ai/credentials` - [Подключить ключ](./credentials/create.md) — `POST /v1/ai/credentials` - [Обновить ключ](./credentials/update.md) — `PATCH /v1/ai/credentials/:id` - [Удалить ключ](./credentials/delete.md) — `DELETE /v1/ai/credentials/:id` - [Проверить ключ](./credentials/test.md) — `POST /v1/ai/credentials/:id/test` - [Статистика по ключу](./credentials/usage.md) — `GET /v1/ai/credentials/:id/usage` - [Загрузить каталог моделей](./credentials/fetch-models.md) — `POST /v1/ai/credentials/:id/fetch-models` (Custom) - [Список моделей ключа](./credentials/models-list.md) — `GET /v1/ai/credentials/:id/models` - [Добавить модель вручную](./credentials/models-add.md) — `POST /v1/ai/credentials/:id/models` (Custom) - [Удалить модель ключа](./credentials/models-delete.md) — `DELETE /v1/ai/credentials/:credId/models/:modelRowId` ## Типовой сценарий ### Подключение стандартного провайдера 1. Получите ID провайдера: [`GET /v1/ai/providers`](/docs/ai/credentials/providers). 2. Подключите ключ: [`POST /v1/ai/credentials`](./credentials/create.md). Ключ автоматически проверяется у провайдера до сохранения — если ключ некорректен, возвращается `422`. 3. После подключения модели провайдера появятся в [`GET /v1/models`](/docs/ai/models/list). ### Подключение Custom-сервиса (OpenAI-совместимого) 1. Подключите ключ с указанием `baseUrl`: [`POST /v1/ai/credentials`](./credentials/create.md) c `providerId: cprv_custom_seed`. 2. Загрузите каталог моделей: [`POST /v1/ai/credentials/:id/fetch-models`](./credentials/fetch-models.md). Если сервис не поддерживает `GET /v1/models` — добавьте модели вручную: [`POST /v1/ai/credentials/:id/models`](./credentials/models-add.md). 3. Используйте `modelId` в [чат-комплишене](/docs/ai/chat/completions). ## Смотрите также - [AI Router](/docs/ai) - [Список провайдеров](/docs/ai/credentials/providers) - [Модели](/docs/ai/models) --- # AI Credentials: Create ## Подключить ключ провайдера `POST /v1/ai/credentials` Подключает новый ключ провайдера к вашему пользователю (USER scope). Ключ автоматически проверяется у провайдера до сохранения: непрошедший проверку ключ не сохраняется. Один пользователь может подключить только один ключ на каждого провайдера. ## Поля запроса (body) | Поле | Тип | Обяз. | По умолч. | Описание | |------|-----|:-----:|-----------|----------| | `providerId` | string | да | — | ID провайдера. Список: [`GET /v1/ai/providers`](/docs/ai/credentials/providers) | | `name` | string | да | — | Произвольное имя ключа для отображения в списке | | `credentials.apiKey` | string | да | — | Ключ от провайдера (например, `sk-...` для OpenAI) | | `credentials.baseUrl` | string | условно | — | Обязательно для `custom-openai-compat`. Формат: `https://api.example.com/v1`. Только `http`/`https`, приватные сети запрещены | | `isDefault` | boolean | нет | `false` | Использовать этот ключ по умолчанию для провайдера | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/ai/credentials \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "providerId": "openai", "name": "Мой личный OpenAI", "credentials": { "apiKey": "sk-proj-..." }, "isDefault": true }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/ai/credentials \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "providerId": "openai", "name": "Мой личный OpenAI", "credentials": { "apiKey": "sk-proj-..." }, "isDefault": true }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/ai/credentials', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ providerId: 'openai', name: 'Мой личный OpenAI', credentials: { apiKey: 'sk-proj-...' }, isDefault: true, }), }) const { success, data } = await res.json() if (success) console.log('Ключ подключён, ID:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/ai/credentials', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ providerId: 'openai', name: 'Мой личный OpenAI', credentials: { apiKey: 'sk-proj-...' }, }), }) const { data } = await res.json() console.log('ID:', data.id) ``` ## Подключение Custom OpenAI-Compatible сервиса Для произвольного OpenAI-совместимого сервиса (Minimax, Cerebras, Cohere, корпоративный `vLLM`/`Ollama` и т. п.) используйте `providerId: cprv_custom_seed` и обязательно укажите `baseUrl`: ```bash curl -X POST https://vibecode.bitrix24.tech/v1/ai/credentials \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "providerId": "cprv_custom_seed", "name": "Корпоративный сервис", "credentials": { "apiKey": "sk-corp-...", "baseUrl": "https://llm.example.com/v1" } }' ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | string | Уникальный ID созданного ключа | | `data.providerId` | string | ID провайдера | | `data.provider.slug` | string | Системное имя провайдера | | `data.provider.name` | string | Название провайдера | | `data.name` | string | Имя ключа из запроса | | `data.isDefault` | boolean | Флаг ключа по умолчанию | | `data.createdAt` | string | Время создания в `ISO 8601` | | `data.updatedAt` | string | Время последнего обновления в `ISO 8601` | ## Пример ответа HTTP-статус `201 Created`: ```json { "success": true, "data": { "id": "cred_abc123def456", "providerId": "openai", "provider": { "slug": "openai", "name": "OpenAI" }, "name": "Мой личный OpenAI", "isDefault": true, "createdAt": "2026-04-27T11:30:00.000Z", "updatedAt": "2026-04-27T11:30:00.000Z" } } ``` ## Пример ответа при ошибке `422 credential_invalid` — ключ не прошёл верификацию у провайдера: ```json { "success": false, "error": { "code": "credential_invalid", "message": "OpenAI API 401: Incorrect API key provided" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `invalid_request` | Нарушена схема `body` (нет обязательных полей) | | 400 | `no_key` | В `credentials` нет поля `apiKey` | | 400 | `base_url_invalid` | `baseUrl` использует не `http`/`https` или некорректен | | 400 | `base_url_private` | `baseUrl` указывает на приватную сеть или не разрешается в IP-адрес через `DNS` | | 404 | `provider_not_found` | Провайдер с таким `providerId` не существует или отключён | | 409 | `already_exists` | Ключ для этого провайдера уже подключён — используйте [`PATCH /v1/ai/credentials/:id`](./update.md) | | 422 | `credential_invalid` | Ключ не прошёл верификацию у провайдера. Сообщение содержит детали от провайдера | | 422 | `provider_geoblocked` | Провайдер отклонил проверку ключа по региону нашего сервера. Подключите свой прокси или перейдите на OpenRouter. Ответ несёт поле `suggestions` | | 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` | Полный список общих ошибок API — [Ошибки](/docs/errors). Лимит создания ключей: 10 запросов в минуту (единый бакет на портал — все ключи портала делят его). ## Известные особенности **Верификация перед сохранением.** Ключ проверяется у провайдера через `verify()` — это HTTP-запрос к `GET /v1/models` или (если провайдер не поддерживает `models`) к `POST /v1/chat/completions` с минимальным телом. Тайм-аут проверки — 10 секунд. При некорректном ключе ничего не сохраняется в базе. **SSRF-защита для Custom-провайдера.** `baseUrl` для `custom-openai-compat` обязательно проходит проверку: запрещены приватные сети (`127.0.0.0/8`, `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `169.254.0.0/16`), `IPv6` link-local и ULA, `IPv4`-mapped `IPv6`. Принимаются только `http://`/`https://` схемы. **Сообщение об ошибке очищено.** Текст ошибки от провайдера обрезается до 200 символов, URL заменяются на плейсхолдер `[URL]` — это защищает от случайной утечки внутренних адресов в логах клиента. ## Смотрите также - [Список провайдеров](/docs/ai/credentials/providers) - [Обновить ключ](./update.md) - [Проверить ключ](./test.md) - [Свои ключи (BYOK)](/docs/ai/credentials) --- # AI Credentials: Delete ## Удалить ключ провайдера `DELETE /v1/ai/credentials/:id` Удаляет подключённый ключ провайдера. Связанные модели Custom-провайдера, привязанные к этому ключу, удаляются каскадно. История использования (`AiUsageLog`) сохраняется — записи статистики не пропадают. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|----------| | `id` (path) | string | да | ID ключа из [`GET /v1/ai/credentials`](./list.md) | ## Примеры ### curl — личный ключ ```bash curl -X DELETE https://vibecode.bitrix24.tech/v1/ai/credentials/cred_abc123def456 \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE https://vibecode.bitrix24.tech/v1/ai/credentials/cred_abc123def456 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const id = 'cred_abc123def456' const res = await fetch(`https://vibecode.bitrix24.tech/v1/ai/credentials/${id}`, { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { success } = await res.json() if (success) console.log('Ключ удалён') ``` ### JavaScript — OAuth-приложение ```javascript const id = 'cred_abc123def456' const res = await fetch(`https://vibecode.bitrix24.tech/v1/ai/credentials/${id}`, { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) if ((await res.json()).success) console.log('OK') ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | ## Пример ответа HTTP-статус `200 OK`: ```json { "success": true } ``` ## Пример ответа при ошибке `404 not_found` — ключ не найден или принадлежит другому пользователю: ```json { "success": false, "error": { "code": "not_found", "message": "Credential not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 404 | `not_found` | Ключ с таким `id` не найден или не принадлежит вам | | 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Каскадное удаление моделей.** Для Custom-провайдера, к ключу которого привязаны модели через [`POST /v1/ai/credentials/:id/models`](./models-add.md) или [`POST /v1/ai/credentials/:id/fetch-models`](./fetch-models.md), все привязанные модели удаляются вместе с ключом. **История использования сохраняется.** Записи `AiUsageLog` не удаляются — статистика по этому провайдеру за прошлые периоды останется в [`GET /v1/ai/usage`](/docs/ai/consumption/usage). Поля `modelId` и `providerId` хранятся как строки, без `FK`-связи с таблицей ключей. **Только USER-ключи.** Эндпоинт работает только с ключами текущего пользователя. PORTAL-ключи, подключённые администратором для всех — здесь недоступны. ## Смотрите также - [Список ключей](./list.md) - [Обновить ключ](./update.md) - [Свои ключи (BYOK)](/docs/ai/credentials) --- # AI Credentials: Fetch Models ## Загрузить каталог моделей `POST /v1/ai/credentials/:id/fetch-models` Загружает список моделей у Custom-провайдера через его эндпоинт `GET /v1/models` и сохраняет каждую как `AiModel`, привязанную к этому ключу. Если провайдер не поддерживает `/v1/models` — операция возвращает успешный ответ с подсказкой добавить модели вручную. Эндпоинт работает только с провайдером `custom-openai-compat` — для остальных провайдеров каталог моделей фиксирован и управляется платформой. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|----------| | `id` (path) | string | да | ID Custom-ключа из [`GET /v1/ai/credentials`](./list.md) | Тело запроса не передаётся. ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/ai/credentials/cred_custom_xyz/fetch-models \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/ai/credentials/cred_custom_xyz/fetch-models \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const id = 'cred_custom_xyz' const res = await fetch(`https://vibecode.bitrix24.tech/v1/ai/credentials/${id}/fetch-models`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() console.log(`Добавлено: ${data.added}, обновлено: ${data.updated}, помечено устаревшими: ${data.deprecated}`) ``` ### JavaScript — OAuth-приложение ```javascript const id = 'cred_custom_xyz' const res = await fetch(`https://vibecode.bitrix24.tech/v1/ai/credentials/${id}/fetch-models`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() if (data.error === 'PROVIDER_LIST_MODELS_UNAVAILABLE') { console.log('Провайдер не поддерживает GET /v1/models — добавьте модели вручную:', data.hint) } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` | | `data.added` | number | Количество новых `AiModel`-записей | | `data.updated` | number | Количество обновлённых записей (модели, которые уже были в каталоге ключа) | | `data.deprecated` | number | Количество моделей, которые ранее были загружены, но больше не возвращаются провайдером — их статус автоматически меняется на `DEPRECATED` | | `data.error` | string | Только при ошибке провайдера: `PROVIDER_LIST_MODELS_UNAVAILABLE` | | `data.hint` | string | Подсказка по дальнейшим действиям при ошибке | | `data.message` | string | Сообщение от провайдера при ошибке | ## Пример ответа Успешная загрузка каталога: ```json { "success": true, "data": { "added": 5, "updated": 12, "deprecated": 0 } } ``` Провайдер не поддерживает `GET /v1/models` (например, Minimax): ```json { "success": true, "data": { "added": 0, "updated": 0, "deprecated": 0, "error": "PROVIDER_LIST_MODELS_UNAVAILABLE", "hint": "add models manually: POST /v1/ai/credentials/cred_custom_xyz/models", "message": "OpenAI API 404: page not found" } } ``` ## Пример ответа при ошибке `400 not_custom_provider` — ключ принадлежит не Custom-провайдеру: ```json { "success": false, "error": { "code": "not_custom_provider", "message": "fetch-models is only available for custom-openai-compat provider" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `not_custom_provider` | Эндпоинт работает только с провайдером `custom-openai-compat` | | 404 | `not_found` | Ключ с таким `id` не найден или не принадлежит вам | | 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` | Полный список общих ошибок API — [Ошибки](/docs/errors). Лимит загрузки каталога: 10 запросов в минуту (единый бакет на портал). ## Известные особенности **Идемпотентно.** Повторный запуск не создаёт дубликатов: модели с уже существующим `modelId` обновляются (поля `name`, `contextLength`, `maxOutputTokens`), новые добавляются, ушедшие из каталога провайдера получают статус `DEPRECATED` (история использования сохраняется). **Цены — нулевые.** Загруженные модели по умолчанию имеют `inputPrice = 0`, `outputPrice = 0` — BYOK означает, что вы платите провайдеру напрямую. Платформенный биллинг такие записи пропускает. **Альтернатива при `PROVIDER_LIST_MODELS_UNAVAILABLE`.** Если провайдер не отдаёт каталог моделей — добавьте каждую модель вручную через [`POST /v1/ai/credentials/:id/models`](./models-add.md). Это нужно для Minimax (`api.minimax.io`), некоторых корпоративных `vLLM`-инсталляций и других сервисов без `GET /v1/models`. **Срабатывает фильтр `OpenAiAdapter`.** Эндпоинт под капотом использует `GET /v1/models` через `OpenAiAdapter`, который фильтрует ответы по префиксу `gpt-`. Если ваш Custom-сервис возвращает модели без этого префикса (Minimax `abab6.5-chat`, Cohere и др.) — `fetch-models` вернёт `added: 0`. Используйте [ручную регистрацию](./models-add.md). ## Смотрите также - [Список моделей ключа](./models-list.md) - [Добавить модель вручную](./models-add.md) - [Удалить модель ключа](./models-delete.md) - [Подключить ключ](./create.md) --- # AI Credentials: List ## Список ключей `GET /v1/ai/credentials` Возвращает все BYOK-ключи, подключённые текущим пользователем (USER scope), вместе со статистикой использования за последние 30 дней. Ключи на уровне портала (PORTAL) не попадают в этот список — их подключает администратор в кабинете Вайбкод. ## Параметры Параметров запроса нет. ## Примеры ### curl — личный ключ ```bash curl https://vibecode.bitrix24.tech/v1/ai/credentials \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl https://vibecode.bitrix24.tech/v1/ai/credentials \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/ai/credentials', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() data.forEach((cred) => { console.log(`${cred.name} (${cred.provider.name}) — ${cred.usage.requests} запросов за 30 дней`) }) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/ai/credentials', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() console.log('Подключено провайдеров:', data.length) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив подключённых ключей | | `data[].id` | string | Уникальный ID ключа | | `data[].providerId` | string | ID провайдера. Список: [`GET /v1/ai/providers`](/docs/ai/credentials/providers) | | `data[].provider.slug` | string | Системное имя провайдера: `openai`, `anthropic`, `custom-openai-compat` и т. п. | | `data[].provider.name` | string | Отображаемое название провайдера | | `data[].name` | string | Имя ключа, заданное пользователем | | `data[].isDefault` | boolean | Флаг ключа по умолчанию для провайдера | | `data[].lastError` | string \| null | Последняя ошибка верификации (null, если ошибок не было) | | `data[].lastErrorAt` | string \| null | Время последней ошибки в `ISO 8601` | | `data[].usage.requests` | number | Количество запросов за последние 30 дней | | `data[].usage.promptTokens` | number | Токены входа за 30 дней | | `data[].usage.completionTokens` | number | Токены ответа за 30 дней | | `data[].createdAt` | string | Время создания в `ISO 8601` | | `data[].updatedAt` | string | Время последнего обновления в `ISO 8601` | ## Пример ответа ```json { "success": true, "data": [ { "id": "cred_abc123def456", "providerId": "openai", "provider": { "slug": "openai", "name": "OpenAI" }, "name": "Мой личный OpenAI", "isDefault": true, "lastError": null, "lastErrorAt": null, "usage": { "requests": 142, "promptTokens": 45200, "completionTokens": 18300 }, "createdAt": "2026-04-15T10:00:00.000Z", "updatedAt": "2026-04-20T14:30:00.000Z" } ] } ``` Если ключи не подключены — `data` будет пустым массивом: ```json { "success": true, "data": [] } ``` ## Пример ответа при ошибке `403 scope_missing` — у API-ключа нет скоупа `vibe:ai`: ```json { "success": false, "error": { "code": "scope_missing", "message": "API key does not have the vibe:ai scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Видны только USER-ключи.** Эндпоинт показывает ключи, которые подключили лично вы. Ключи на уровне портала (PORTAL scope), которые администратор настроил для всех участников — здесь не отображаются. Их подключает администратор в кабинете Вайбкод. **`lastError` показывает последнюю проблему.** Если у ключа `lastError` отличен от `null` — провайдер вернул ошибку при последней проверке (через `POST /v1/ai/credentials/:id/test` или при использовании в чат-комплишене). Поле сбрасывается при успешном `PATCH` с обновлением `credentials` или при успешной проверке. **Статистика за фиксированные 30 дней.** Поле `usage` содержит цифры за последние 30 дней без возможности задать период. Для произвольного периода — [`GET /v1/ai/credentials/:id/usage?days=N`](./usage.md). ## Смотрите также - [Подключить ключ](./create.md) - [Список провайдеров](/docs/ai/credentials/providers) - [Свои ключи (BYOK)](/docs/ai/credentials) --- # AI Credentials: Models Add ## Добавить модель вручную `POST /v1/ai/credentials/:id/models` Регистрирует одну модель, привязанную к Custom-ключу. Используется для провайдеров, которые не отдают каталог через `GET /v1/models` (Minimax, корпоративный `vLLM`/`Ollama`, Cohere). Эндпоинт работает только с провайдером `custom-openai-compat`. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|----------| | `id` (path) | string | да | ID Custom-ключа из [`GET /v1/ai/credentials`](./list.md) | ## Поля запроса (body) | Поле | Тип | Обяз. | По умолч. | Описание | |------|-----|:-----:|-----------|----------| | `modelId` | string | да | — | ID модели у провайдера. Будет использоваться в `model` запроса к [`/v1/chat/completions`](/docs/ai/chat/completions) | | `name` | string | нет | значение `modelId` | Отображаемое название модели | | `contextLength` | number | нет | `8192` | Максимальный размер контекста в токенах | | `maxOutputTokens` | number | нет | `4096` | Максимум токенов в ответе | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/ai/credentials/cred_custom_xyz/models \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "modelId": "abab6.5-chat", "name": "MiniMax abab6.5-chat", "contextLength": 32768, "maxOutputTokens": 8192 }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/ai/credentials/cred_custom_xyz/models \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "modelId": "abab6.5-chat", "name": "MiniMax abab6.5-chat", "contextLength": 32768, "maxOutputTokens": 8192 }' ``` ### JavaScript — личный ключ ```javascript const id = 'cred_custom_xyz' const res = await fetch(`https://vibecode.bitrix24.tech/v1/ai/credentials/${id}/models`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ modelId: 'abab6.5-chat', name: 'MiniMax abab6.5-chat', contextLength: 32768, maxOutputTokens: 8192, }), }) const { data } = await res.json() console.log('Зарегистрирована модель с id:', data.id) ``` ### JavaScript — OAuth-приложение ```javascript const id = 'cred_custom_xyz' const res = await fetch(`https://vibecode.bitrix24.tech/v1/ai/credentials/${id}/models`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ modelId: 'abab6.5-chat' }), }) const { data } = await res.json() console.log('Готово:', data.modelId) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | string | Уникальный ID записи `AiModel` (нужен для [удаления](./models-delete.md)) | | `data.modelId` | string | Зарегистрированный `modelId` | | `data.name` | string | Имя модели | | `data.contextLength` | number | Сохранённый размер контекста | ## Пример ответа HTTP-статус `201 Created`: ```json { "success": true, "data": { "id": "aimodel_xyz789", "modelId": "abab6.5-chat", "name": "MiniMax abab6.5-chat", "contextLength": 32768 } } ``` ## Пример ответа при ошибке `400 not_custom_provider` — ключ не относится к Custom-провайдеру: ```json { "success": false, "error": { "code": "not_custom_provider", "message": "Manual model registration is only available for custom-openai-compat provider" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `invalid_request` | Поле `modelId` не передано или нарушена схема | | 400 | `not_custom_provider` | Эндпоинт работает только с провайдером `custom-openai-compat` | | 404 | `not_found` | Ключ с таким `id` не найден или не принадлежит вам | | 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` | Полный список общих ошибок API — [Ошибки](/docs/errors). Лимит регистрации моделей: 30 запросов в минуту. ## Известные особенности **Идемпотентно.** Повторный вызов с тем же `modelId` обновит существующую запись (поля `name`, `contextLength`, `maxOutputTokens`) вместо создания дубликата. **`modelId` совпадает с провайдерским.** Передавайте именно тот идентификатор, который провайдер ожидает в `model` запроса. Например, для Minimax — `abab6.5-chat`, для корпоративного `vLLM` — то имя, под которым модель загружена. **Цена — нулевая.** Модели Custom-провайдера всегда регистрируются с нулевой ценой (`inputPrice = 0`, `outputPrice = 0`). Платформенный биллинг такие записи пропускает — вы платите провайдеру напрямую. ## Смотрите также - [Загрузить каталог моделей](./fetch-models.md) - [Список моделей ключа](./models-list.md) - [Удалить модель ключа](./models-delete.md) - [Создать чат-комплишен](/docs/ai/chat/completions) --- # AI Credentials: Models Delete ## Удалить модель ключа `DELETE /v1/ai/credentials/:credId/models/:modelRowId` Удаляет одну модель, привязанную к BYOK-ключу. После удаления модель пропадает из [`GET /v1/models`](/docs/ai/models/list), а запросы к ней через [`/v1/chat/completions`](/docs/ai/chat/completions) возвращают `404 ai_model_not_found`. История вызовов в `AiUsageLog` сохраняется. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|----------| | `credId` (path) | string | да | ID ключа из [`GET /v1/ai/credentials`](./list.md) | | `modelRowId` (path) | string | да | ID записи модели (`data[].id`) из [`GET /v1/ai/credentials/:id/models`](./models-list.md) — это **не** `modelId`, а первичный ключ записи `AiModel` | ## Примеры ### curl — личный ключ ```bash curl -X DELETE https://vibecode.bitrix24.tech/v1/ai/credentials/cred_custom_xyz/models/aimodel_xyz789 \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE https://vibecode.bitrix24.tech/v1/ai/credentials/cred_custom_xyz/models/aimodel_xyz789 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const credId = 'cred_custom_xyz' const modelRowId = 'aimodel_xyz789' const res = await fetch( `https://vibecode.bitrix24.tech/v1/ai/credentials/${credId}/models/${modelRowId}`, { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY' } }, ) const { success } = await res.json() if (success) console.log('Модель удалена из каталога ключа') ``` ### JavaScript — OAuth-приложение ```javascript const credId = 'cred_custom_xyz' const modelRowId = 'aimodel_xyz789' const res = await fetch( `https://vibecode.bitrix24.tech/v1/ai/credentials/${credId}/models/${modelRowId}`, { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }, ) if ((await res.json()).success) console.log('OK') ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | ## Пример ответа HTTP-статус `200 OK`: ```json { "success": true } ``` ## Пример ответа при ошибке `404 not_found` — ключ или модель не найдены, либо ключ принадлежит другому пользователю: ```json { "success": false, "error": { "code": "not_found", "message": "Credential not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 404 | `not_found` | Ключ с таким `credId` не найден / не принадлежит вам, либо модель с таким `modelRowId` не привязана к ключу | | 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` | Полный список общих ошибок API — [Ошибки](/docs/errors). Лимит удаления моделей: 30 запросов в минуту. ## Известные особенности **`modelRowId` — первичный ключ записи, не `modelId`.** Один и тот же `modelId` может встречаться у разных ключей (одинаковая модель `gpt-4o` у двух BYOK), поэтому удаление идёт по уникальному `id` записи `AiModel`. Получите его из [`GET /v1/ai/credentials/:id/models`](./models-list.md), поле `data[].id`. **История вызовов сохраняется.** Записи `AiUsageLog` не удаляются — статистика по этой модели за прошлые периоды останется в [`GET /v1/ai/usage`](/docs/ai/consumption/usage). Поля `modelId` и `providerId` в логах хранятся как строки, без `FK`-связи с таблицей `AiModel`. **Не путайте с `DEPRECATED`.** Модель в статусе `DEPRECATED` ещё работает — её просто не рекомендуется использовать. Удалённая модель полностью пропадает: запросы к её `modelId` возвращают `404 ai_model_not_found`. Чтобы пометить модель устаревшей вместо удаления — обратитесь к администратору портала. **Каскадное удаление с ключом.** Если удалить сам ключ через [`DELETE /v1/ai/credentials/:id`](./delete.md) — все привязанные модели удаляются вместе с ним. Этот эндпоинт нужен, чтобы убрать одну модель, оставив остальные. ## Смотрите также - [Список моделей ключа](./models-list.md) - [Удалить ключ](./delete.md) - [Загрузить каталог моделей](./fetch-models.md) --- # AI Credentials: Models List ## Список моделей ключа `GET /v1/ai/credentials/:id/models` Возвращает все модели, привязанные к указанному BYOK-ключу через [`fetch-models`](./fetch-models.md) или [`models-add`](./models-add.md). Используется для просмотра текущего каталога Custom-провайдера и поиска `id` записи перед удалением. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|----------| | `id` (path) | string | да | ID ключа из [`GET /v1/ai/credentials`](./list.md) | ## Примеры ### curl — личный ключ ```bash curl https://vibecode.bitrix24.tech/v1/ai/credentials/cred_custom_xyz/models \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl https://vibecode.bitrix24.tech/v1/ai/credentials/cred_custom_xyz/models \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const id = 'cred_custom_xyz' const res = await fetch(`https://vibecode.bitrix24.tech/v1/ai/credentials/${id}/models`, { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() data.forEach((m) => console.log(`${m.modelId} — ${m.name} (${m.status})`)) ``` ### JavaScript — OAuth-приложение ```javascript const id = 'cred_custom_xyz' const res = await fetch(`https://vibecode.bitrix24.tech/v1/ai/credentials/${id}/models`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() console.log('Моделей у ключа:', data.length) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив привязанных моделей | | `data[].id` | string | Уникальный ID записи `AiModel` (нужен для [удаления](./models-delete.md)) | | `data[].modelId` | string | ID модели для использования в `model` запроса к [`/v1/chat/completions`](/docs/ai/chat/completions) | | `data[].name` | string | Отображаемое название модели | | `data[].contextLength` | number | Максимальный размер контекста в токенах | | `data[].maxOutputTokens` | number | Максимум токенов в ответе | | `data[].status` | string | Статус: `ACTIVE`, `DEPRECATED`, `DISABLED` | | `data[].isEnabled` | boolean | Глобальный выключатель: `false` — модель скрыта из всех каталогов | | `data[].createdAt` | string | Время первой регистрации в `ISO 8601` | ## Пример ответа ```json { "success": true, "data": [ { "id": "aimodel_xyz789", "modelId": "abab6.5-chat", "name": "MiniMax abab6.5-chat", "contextLength": 32768, "maxOutputTokens": 8192, "status": "ACTIVE", "isEnabled": true, "createdAt": "2026-04-25T09:00:00.000Z" }, { "id": "aimodel_old001", "modelId": "old-model-v1", "name": "Старая модель", "contextLength": 16384, "maxOutputTokens": 4096, "status": "DEPRECATED", "isEnabled": true, "createdAt": "2026-04-15T09:00:00.000Z" } ] } ``` ## Пример ответа при ошибке `404 not_found` — ключ не найден или принадлежит другому пользователю: ```json { "success": false, "error": { "code": "not_found", "message": "Credential not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 404 | `not_found` | Ключ с таким `id` не найден или не принадлежит вам | | 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`status: DEPRECATED` после `fetch-models`.** Если модель ранее была загружена через `fetch-models`, но в последнем запуске больше не пришла от провайдера — её статус автоматически меняется на `DEPRECATED`. Запросы к ней ещё работают, но в каталоге [`GET /v1/models`](/docs/ai/models/list) она помечена как устаревшая. **Работает для всех провайдеров, не только Custom.** Эндпоинт возвращает любые модели, привязанные к ключу. Для стандартных провайдеров обычно `data` пустой — у них модели платформенные (`credentialId: null`), не привязанные к конкретному ключу. **`id` нужен для удаления.** Чтобы удалить модель — сохраните `id` записи и передайте в [`DELETE /v1/ai/credentials/:credId/models/:modelRowId`](./models-delete.md). `modelId` не подходит — он не уникален между ключами. ## Смотрите также - [Загрузить каталог моделей](./fetch-models.md) - [Добавить модель вручную](./models-add.md) - [Удалить модель ключа](./models-delete.md) - [Список моделей](/docs/ai/models/list) --- # AI Credentials: Providers ## Список провайдеров `GET /v1/ai/providers` Возвращает справочник провайдеров, доступных для подключения BYOK-ключа. Используйте перед [`POST /v1/ai/credentials`](/docs/ai/credentials/create), чтобы получить корректный `providerId` и узнать, какие поля провайдер ожидает в `credentials`. ## Параметры Параметров запроса нет. ## Примеры ### curl — личный ключ ```bash curl https://vibecode.bitrix24.tech/v1/ai/providers \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl https://vibecode.bitrix24.tech/v1/ai/providers \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/ai/providers', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() data.forEach((p) => { const fields = Object.keys(p.credentialFields).join(', ') console.log(`${p.name} (${p.slug}) — нужны поля: ${fields}`) }) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/ai/providers', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() const openai = data.find((p) => p.slug === 'openai') console.log('ID OpenAI:', openai.id) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив провайдеров, отсортирован по `name` | | `data[].id` | string | ID провайдера — используйте в `providerId` запроса к [`POST /v1/ai/credentials`](/docs/ai/credentials/create) | | `data[].name` | string | Отображаемое название | | `data[].slug` | string | Системное имя провайдера: `openai`, `anthropic`, `custom-openai-compat` и т. п. | | `data[].credentialFields` | object | Описание полей, которые нужно передать в `credentials` при создании ключа | | `data[].credentialFields..type` | string | Тип ввода: `password`, `url`, `text` | | `data[].credentialFields..label` | string | Метка поля | | `data[].credentialFields..required` | boolean | Обязательность | | `data[].credentialFields..placeholder` | string | Подсказка для пустого поля | | `data[].credentialFields..hint` | string | Подсказка для пользователя. У большинства провайдеров — домен страницы, где выпускается ключ | | `data[].credentialFields..help` | string | Поясняющий текст к полю. Приходит у провайдера `custom-openai-compat` для поля `baseUrl` | ## Пример ответа ```json { "success": true, "data": [ { "id": "anthropic", "name": "Anthropic", "slug": "anthropic", "credentialFields": { "apiKey": { "type": "password", "label": "API Key", "required": true } } }, { "id": "cprv_custom_seed", "name": "Custom OpenAI-Compatible", "slug": "custom-openai-compat", "credentialFields": { "apiKey": { "type": "password", "label": "API Key", "required": true }, "baseUrl": { "type": "url", "label": "Base URL", "required": true, "placeholder": "https://api.example.com/v1", "help": "OpenAI-compatible endpoint." } } }, { "id": "openai", "name": "OpenAI", "slug": "openai", "credentialFields": { "apiKey": { "type": "password", "label": "API Key", "required": true } } } ] } ``` ## Пример ответа при ошибке `403 scope_missing` — у API-ключа нет скоупа `vibe:ai`: ```json { "success": false, "error": { "code": "scope_missing", "message": "API key does not have the vibe:ai scope" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Провайдер `bitrix` исключён.** Список не содержит платформенного провайдера `bitrix` — его модели (BitrixGPT 5.5, GPT-OSS, Whisper и др.) доступны всем без подключения BYOK. **Большинство провайдеров требует только `apiKey`.** Поле `baseUrl` обязательно только для `custom-openai-compat`. Для всех остальных провайдеров `baseUrl` фиксирован платформой и в `credentials` не передаётся. **Системное имя `custom-openai-compat` — для произвольных сервисов.** Используйте, чтобы подключить любой OpenAI-совместимый сервис: Minimax, Cerebras, Cohere, корпоративный `vLLM`/`Ollama`, локальный inference-сервер. После подключения модели либо загружаются автоматически через [`fetch-models`](/docs/ai/credentials/fetch-models), либо регистрируются вручную через [`models-add`](/docs/ai/credentials/models-add). **Подсказки `hint`.** У части провайдеров поле `hint` содержит домен страницы получения ключа: `platform.deepseek.com`, `console.groq.com`, `aistudio.google.com`. Показывайте его пользователю рядом с полем ввода ключа. ## Смотрите также - [Подключить ключ](/docs/ai/credentials/create) - [Свои ключи (BYOK)](/docs/ai/credentials) - [AI Router](/docs/ai) --- # AI Credentials: Test ## Проверить ключ провайдера `POST /v1/ai/credentials/:id/test` Перепроверяет сохранённый ключ у провайдера. Ничего не изменяет в самих учётных данных, но обновляет поля `lastError` и `lastErrorAt` ключа в зависимости от результата. Используйте, когда подозреваете, что ключ просрочен или у провайдера сменился API. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|----------| | `id` (path) | string | да | ID ключа из [`GET /v1/ai/credentials`](./list.md) | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/ai/credentials/cred_abc123def456/test \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/ai/credentials/cred_abc123def456/test \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const id = 'cred_abc123def456' const res = await fetch(`https://vibecode.bitrix24.tech/v1/ai/credentials/${id}/test`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() console.log(data.valid ? 'Ключ корректен' : `Ошибка: ${data.error}`) ``` ### JavaScript — OAuth-приложение ```javascript const id = 'cred_abc123def456' const res = await fetch(`https://vibecode.bitrix24.tech/v1/ai/credentials/${id}/test`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() if (!data.valid) alert(`Ключ некорректен: ${data.error}`) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` (даже при некорректном ключе — это не ошибка эндпоинта) | | `data.valid` | boolean | `true` — ключ принят провайдером; `false` — отвергнут | | `data.error` | string | Сообщение об ошибке от провайдера, если `valid: false`. URL заменены на `[URL]`, длина обрезана до 200 символов | ## Пример ответа Ключ корректен: ```json { "success": true, "data": { "valid": true } } ``` Ключ отвергнут провайдером: ```json { "success": true, "data": { "valid": false, "error": "OpenAI API 401: Incorrect API key provided" } } ``` ## Пример ответа при ошибке `404 not_found` — ключ не найден или принадлежит другому пользователю: ```json { "success": false, "error": { "code": "not_found", "message": "Credential not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 404 | `not_found` | Ключ с таким `id` не найден или не принадлежит вам | | 400 | `no_key` | В сохранённых учётных данных нет поля `apiKey` (битый старый ключ) | | 500 | `decryption_error` | Не удалось расшифровать сохранённые учётные данные | | 422 | `provider_geoblocked` | Провайдер отклонил проверку ключа по региону нашего сервера. Подключите свой прокси или перейдите на OpenRouter. Ответ несёт поле `suggestions` | | 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` | Полный список общих ошибок API — [Ошибки](/docs/errors). Лимит проверок: 10 запросов в минуту (единый бакет на портал). ## Известные особенности **Некорректный ключ — не ошибка эндпоинта.** Если провайдер отверг ключ — эндпоинт вернёт `200 OK` с `success: true` и `data.valid: false`. HTTP-ошибки (`4xx`/`5xx`) возвращаются только при проблемах с самим запросом (нет ключа, нет доступа, нечего расшифровать). Единственное исключение — региональная блокировка: провайдер отклонил проверку по региону нашего сервера, и эндпоинт отвечает `422 provider_geoblocked`. **Запись результата в `lastError`.** Эндпоинт обновляет поля `lastError` и `lastErrorAt` ключа в базе. При успехе — обнуляет, при неудаче — записывает текст ошибки от провайдера. Эти поля видны в [`GET /v1/ai/credentials`](./list.md). **Тайм-аут проверки — 10 секунд.** Если провайдер не отвечает за 10 секунд — `valid: false` с сообщением о тайм-ауте. **Custom-провайдер проверяется по `baseUrl` ключа.** Для `custom-openai-compat` верификация идёт по тому `baseUrl`, который сохранён в учётных данных. Если у провайдера нет `GET /v1/models` — выполняется проверка через `POST /v1/chat/completions`. ## Смотрите также - [Список ключей](./list.md) - [Обновить ключ](./update.md) - [Подключить ключ](./create.md) --- # AI Credentials: Update ## Обновить ключ провайдера `PATCH /v1/ai/credentials/:id` Обновляет имя, флаг `isDefault` и/или сам ключ. Если в запросе передано поле `credentials` — новый ключ перепроверяется у провайдера до сохранения. Непрошедший проверку ключ не сохраняется, в базе ничего не меняется. Поля `name` и `isDefault` обновляются без верификации. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|----------| | `id` (path) | string | да | ID ключа из [`GET /v1/ai/credentials`](./list.md) | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|----------| | `name` | string | нет | Новое имя ключа | | `isDefault` | boolean | нет | Сделать ключ ключом по умолчанию для провайдера | | `credentials.apiKey` | string | нет | Новый ключ от провайдера | | `credentials.baseUrl` | string | нет | Новый `baseUrl` (только для `custom-openai-compat`) | В `body` нужно передать хотя бы одно поле. Если передано `credentials` — оно проверяется у провайдера; при успехе обнуляются `lastError` и `lastErrorAt`. ## Примеры ### curl — личный ключ ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/ai/credentials/cred_abc123def456 \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "OpenAI (новое имя)", "credentials": { "apiKey": "sk-proj-new-key-..." } }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/ai/credentials/cred_abc123def456 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "OpenAI (новое имя)" }' ``` ### JavaScript — личный ключ ```javascript const id = 'cred_abc123def456' const res = await fetch(`https://vibecode.bitrix24.tech/v1/ai/credentials/${id}`, { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ credentials: { apiKey: 'sk-proj-new-key-...' }, }), }) const { success, data } = await res.json() if (success) console.log('Ключ обновлён в', data.updatedAt) ``` ### JavaScript — OAuth-приложение ```javascript const id = 'cred_abc123def456' const res = await fetch(`https://vibecode.bitrix24.tech/v1/ai/credentials/${id}`, { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'OpenAI (production)' }), }) const { data } = await res.json() console.log('Новое имя:', data.name) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | string | ID ключа | | `data.providerId` | string | ID провайдера | | `data.provider.slug` | string | Системное имя провайдера | | `data.provider.name` | string | Название провайдера | | `data.name` | string | Текущее имя ключа | | `data.isDefault` | boolean | Флаг ключа по умолчанию | | `data.lastError` | string \| null | Сбрасывается в `null` при успешном обновлении ключа | | `data.lastErrorAt` | string \| null | Сбрасывается в `null` при успешном обновлении ключа | | `data.createdAt` | string | Время создания в `ISO 8601` | | `data.updatedAt` | string | Время последнего обновления в `ISO 8601` | ## Пример ответа ```json { "success": true, "data": { "id": "cred_abc123def456", "providerId": "openai", "provider": { "slug": "openai", "name": "OpenAI" }, "name": "OpenAI (новое имя)", "isDefault": true, "lastError": null, "lastErrorAt": null, "createdAt": "2026-04-15T10:00:00.000Z", "updatedAt": "2026-04-27T11:35:00.000Z" } } ``` ## Пример ответа при ошибке `422 credential_invalid` — новый ключ не прошёл верификацию у провайдера: ```json { "success": false, "error": { "code": "credential_invalid", "message": "OpenAI API 401: Incorrect API key provided" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `invalid_request` | Нарушена схема `body` | | 400 | `no_key` | В `credentials` нет поля `apiKey` | | 400 | `base_url_invalid` | Новый `baseUrl` использует не `http`/`https` | | 400 | `base_url_private` | Новый `baseUrl` указывает на приватную сеть | | 404 | `not_found` | Ключ с таким `id` не найден или не принадлежит вам | | 404 | `provider_not_found` | Провайдер ключа удалён | | 422 | `credential_invalid` | Новый ключ не прошёл верификацию у провайдера | | 422 | `provider_geoblocked` | Провайдер отклонил проверку ключа по региону нашего сервера. Подключите свой прокси или перейдите на OpenRouter. Ответ несёт поле `suggestions` | | 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Верификация только при изменении `credentials`.** Если в запросе нет поля `credentials` (обновляются только `name` или `isDefault`) — провайдер не вызывается, поля `lastError`/`lastErrorAt` не сбрасываются. **Пустое тело запроса допустимо.** `PATCH` с пустым `body` (`{}`) вернёт текущее состояние ключа без изменений — поведение, унаследованное от Zod-схемы. Используйте для проверки доступности ключа без затрагивания данных. **Доступ только к своим ключам.** Эндпоинт работает только с USER-ключами текущего пользователя. Попытка обновить чужой ключ или PORTAL-ключ вернёт `404`. ## Смотрите также - [Список ключей](./list.md) - [Подключить ключ](./create.md) - [Удалить ключ](./delete.md) - [Проверить ключ](./test.md) --- # AI Credentials: Usage ## Статистика по ключу `GET /v1/ai/credentials/:id/usage` Возвращает агрегированную статистику использования конкретного BYOK-ключа: общее количество запросов, расход токенов и разбивку по моделям. Период настраивается через query-параметр. ## Параметры | Параметр | Тип | Обяз. | По умолч. | Описание | |----------|-----|:-----:|-----------|----------| | `id` (path) | string | да | — | ID ключа из [`GET /v1/ai/credentials`](./list.md) | | `days` (query) | number | нет | `30` | Период в днях. Допустимый диапазон: `1..90`. Значения вне диапазона автоматически приводятся к границам | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/ai/credentials/cred_abc123def456/usage?days=7" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/ai/credentials/cred_abc123def456/usage?days=7" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const id = 'cred_abc123def456' const res = await fetch(`https://vibecode.bitrix24.tech/v1/ai/credentials/${id}/usage?days=7`, { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() console.log(`За ${data.period.days} дней: ${data.requests} запросов, ${data.totalTokens} токенов`) data.byModel.forEach((m) => console.log(` ${m.modelId}: ${m.calls} запросов`)) ``` ### JavaScript — OAuth-приложение ```javascript const id = 'cred_abc123def456' const res = await fetch(`https://vibecode.bitrix24.tech/v1/ai/credentials/${id}/usage?days=30`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() console.log('Токены ответа:', data.completionTokens) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data.period.days` | number | Фактический период в днях (после ограничения 1..90) | | `data.period.since` | string | Начало периода в `ISO 8601` | | `data.requests` | number | Общее количество запросов через этот ключ за период | | `data.promptTokens` | number | Сумма токенов входа | | `data.completionTokens` | number | Сумма токенов ответа | | `data.totalTokens` | number | Сумма всех токенов | | `data.byModel` | array | Разбивка успешных запросов по моделям, отсортирована по убыванию количества вызовов | | `data.byModel[].modelId` | string | ID модели | | `data.byModel[].calls` | number | Количество запросов к этой модели | | `data.byModel[].promptTokens` | number | Токены входа по модели | | `data.byModel[].completionTokens` | number | Токены ответа по модели | ## Пример ответа ```json { "success": true, "data": { "period": { "days": 7, "since": "2026-04-20T11:30:00.000Z" }, "requests": 142, "promptTokens": 45200, "completionTokens": 18300, "totalTokens": 63500, "byModel": [ { "modelId": "openai/gpt-4o-mini", "calls": 98, "promptTokens": 28000, "completionTokens": 11000 }, { "modelId": "openai/gpt-4o", "calls": 44, "promptTokens": 17200, "completionTokens": 7300 } ] } } ``` ## Пример ответа при ошибке `404 not_found` — ключ не найден или принадлежит другому пользователю: ```json { "success": false, "error": { "code": "not_found", "message": "Credential not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 404 | `not_found` | Ключ с таким `id` не найден или не принадлежит вам | | 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Только успешные вызовы в `byModel`.** Разбивка по моделям учитывает только записи со статусом `SUCCESS`. Общие счётчики (`requests`, `promptTokens` и др.) включают все статусы — успешные, ошибочные, частично успешные. **Группировка по `(userId, providerId)`.** Статистика на уровне ключа выводится из логов, отфильтрованных по комбинации «ваш `userId`» + «`providerId` ключа» + `credentialScope: USER`. Если вы переподключали ключ того же провайдера — старые записи попадут в новую статистику, потому что они соотносятся не по `id` ключа, а по провайдеру. **Разница с [`GET /v1/ai/usage`](/docs/ai/consumption/usage).** Этот эндпоинт показывает статистику только по одному BYOK-ключу. Общий [`/v1/ai/usage`](/docs/ai/consumption/usage) показывает все вызовы текущего API-ключа, включая платформенные модели и PORTAL-credentials, не только USER-BYOK. ## Смотрите также - [Статистика использования](/docs/ai/consumption/usage) - [Список ключей](./list.md) - [Свои ключи (BYOK)](/docs/ai/credentials) --- # AI: Embeddings ## Создать эмбеддинги `POST /v1/embeddings` Преобразует текст в векторное представление. Векторы нужны для семантического поиска, кластеризации, поиска дублей и подбора похожих карточек CRM. Формат запроса и ответа совместим с OpenAI API, потоковой передачи нет. Эмбеддинги умеют только модели, у которых в [`GET /v1/models`](/docs/ai/models/list) поле `capabilities.embeddings` равно `true`. ## Поля запроса (body) | Поле | Тип | Обяз. | По умолч. | Описание | |------|-----|:-----:|-----------|---------| | `model` | string | да | — | Идентификатор модели с поддержкой эмбеддингов. Список: [`GET /v1/models`](/docs/ai/models/list) | | `input` | string \| string[] | да | — | Текст для векторизации: одна строка или массив строк. На каждую строку возвращается один вектор. Пустая строка и пустой массив отклоняются с `400` | | `encoding_format` | string | нет | `float` | Формат значений вектора: `float` или `base64` | | `dimensions` | integer | нет | — | Желаемая размерность вектора. Применяется только к моделям, которые это поддерживают | ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/embeddings \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "bitrix/embeddings", "input": "Хотим CRM на 50 пользователей" }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/embeddings \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "model": "bitrix/embeddings", "input": "Хотим CRM на 50 пользователей" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/embeddings', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'bitrix/embeddings', input: ['Первый текст', 'Второй текст'], }), }) const result = await res.json() console.log(result.data.length) // 2 — по вектору на строку console.log(result.data[0].embedding) // [0.0203, 0.0034, ...] ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/embeddings', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'bitrix/embeddings', input: ['Первый текст', 'Второй текст'], }), }) const result = await res.json() ``` ## Поля ответа Ответ приходит в сыром OpenAI-формате, без обёртки `success` и `data`. | Поле | Тип | Описание | |------|-----|---------| | `object` | string | Всегда `list` | | `data` | array | Массив векторов, по одному на каждую строку `input` | | `data[].object` | string | Всегда `embedding` | | `data[].embedding` | number[] | Значения вектора | | `data[].index` | number | Позиция строки в исходном `input` | | `model` | string | Модель, обработавшая запрос | | `usage.prompt_tokens` | number | Токены входного текста. По ним считается расход | | `usage.completion_tokens` | number | Всегда `0` — эмбеддинги не порождают ответных токенов | | `usage.total_tokens` | number | Совпадает с `prompt_tokens` | ## Пример ответа Показаны первые три значения вектора. Полная размерность зависит от модели — у `bitrix/embeddings` это 4096 значений. ```json { "object": "list", "model": "bitrix/embeddings", "data": [ { "object": "embedding", "index": 0, "embedding": [0.0203, 0.0034, -0.0156] } ], "usage": { "prompt_tokens": 12, "completion_tokens": 0, "total_tokens": 12 } } ``` ## Пример ответа при ошибке `501 embeddings_unsupported` — у модели нет поддержки эмбеддингов: ```json { "error": { "message": "Model \"bitrix/bitrixgpt-5.5\" does not support embeddings.", "type": "server_error", "code": "embeddings_unsupported" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `invalid_request` | Некорректные параметры — пустой `input`, неверное тело запроса | | 404 | `ai_model_not_found` | Модель не найдена или отключена | | 501 | `embeddings_unsupported` | Модель или провайдер не поддерживает эмбеддинги | | 402 | `ai_credentials_not_configured` | Для модели нет учётных данных провайдера — подключите свой ключ | | 402 | `insufficient_balance` | Недостаточно средств для платной модели | | 402 | `ai_quota_exhausted` | Месячная AI-квота портала исчерпана. Поле `reason` различает случай: `breaker` — сработал часовой предохранитель расходов сверх квоты, `wallet_empty` — квота исчерпана и на балансе портала нет средств, `wallet_off` — расход сверх квоты для портала недоступен. `resetAt` — момент, когда запросы снова начнут проходить, может отсутствовать для `wallet_off`. В ветке `wallet_empty` ответ может дополнительно нести строку `hint` и ссылку `topupUrl` — см. «Известные особенности» ниже | | 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` | | 429 | `ai_congested` | Пул AI-кластера перегружен. Запрос не выполнялся, списания нет, повторите его по заголовку `Retry-After`. Ответ несёт заголовок `X-AI-Admission: shed`, а не `X-RateLimit-Scope` | | 400 | `ai_provider_rejected` | Провайдер отклонил сам запрос (ответ `400` или `422`). Повторять его без изменений бесполезно | | 429 | `ai_provider_cooldown` | Кластер моделей временно недоступен, и платформа держит паузу, чтобы повторы его не добивали. Запрос не выполнялся, списания нет — повторите его через число секунд из `Retry-After`. Заголовков `X-RateLimit-Scope` и `X-AI-Admission` у этого ответа нет | | 502 | `ai_provider_unavailable` | Внешний провайдер вернул `401`/`403`/`5xx` или сетевую ошибку | | 429 | `ai_pacing_limited` | Превышено суточное или недельное окно равномерного расходования квоты. Это не исчерпание квоты — повторите запрос по заголовку `Retry-After`. Подробнее — [«Равномерное расходование»](/docs/ai/consumption/quota#равномерное-расходование-pacing) | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Коды ошибок приходят в нижнем регистре.** Тело большинства ошибок — сырой OpenAI-формат `{ "error": { "message", "type", "code" } }`, без поля `success`. Два исключения приходят в конверте `{ "success": false, "error": { … } }`: отказы по квоте и темпу запросов (`402 ai_quota_exhausted`, `429 ai_pacing_limited`) и непредвиденная ошибка сервера `5xx`, у которой код записан в верхнем регистре. Обработчик должен принимать оба конверта. **Массив `input` сохраняет порядок.** Вектор `data[i]` соответствует строке `input[i]`, а поле `data[].index` дублирует эту позицию — по нему можно сопоставить результат после параллельной обработки. **Бюджет обработки запроса — около 850 секунд.** По исчерпании бюджета приходит `503 ai_provider_timeout`. Заголовка `Retry-After` в этом ответе нет намеренно: повтор того же запроса упрётся в тот же бюджет. Разбейте массив `input` на части меньшего размера. **Подсказка о пополнении в ответе `402 ai_quota_exhausted`.** Только в ветке `reason: "wallet_empty"` ответ может дополнительно нести строку `hint` с подсказкой и ссылку `topupUrl` на пополнение баланса. Оба поля появляются, когда на платформе включены принудительный контроль квоты и подсказка о пополнении, поэтому читайте их как необязательные. Поле `hint` в этом ответе — строка. **Расход считается только по входным токенам.** Поле `usage.completion_tokens` всегда `0`, поэтому платится только вход. Для модели `bitrix/embeddings` цена входа нулевая. ## Смотрите также - [Список моделей](/docs/ai/models/list) - [Создать чат-комплишен](/docs/ai/chat/completions) - [AI-квота компании](/docs/ai/consumption/quota) - [AI Router](/docs/ai) --- # AI: Models # Модели Каталог AI-моделей, доступных текущему API-ключу. Состав каталога зависит от настроенных учётных данных провайдера: бесплатные модели Битрикс24 видны всем, остальные — только тем ключам, у которых есть доступ к учётным данным провайдера. Скоуп: `vibe:ai` ## Операции - [Список моделей](./models/list.md) — `GET /v1/models` - [Получить модель](./models/get.md) — `GET /v1/models/:modelId` ## Возможности - [Жизненный цикл моделей](./models/lifecycle.md) — состояния `ACTIVE` / `DEPRECATED` / `DISABLED` и заголовки ответа ## Типовой сценарий 1. Запросите [список моделей](./models/list.md) для текущего ключа — увидите, какие из них доступны без подключения BYOK. 2. Если нужной модели нет — подключите [свой ключ провайдера](/docs/ai/credentials/create). 3. Используйте `id` модели в [чат-комплишене](/docs/ai/chat/completions). ## Смотрите также - [AI Router](/docs/ai) - [Чат-комплишены](/docs/ai/chat) - [Свои ключи (BYOK)](/docs/ai/credentials) --- # AI Models: Get ## Получить модель > **Ответ приходит в сыром OpenAI-формате.** > > Обёртки `{success, data}`, которая используется в остальных эндпоинтах Вайбкод — `/v1/deals`, `/v1/tasks` и других, — здесь нет. > > Так сделано для совместимости с OpenAI SDK. Если у вас единый клиент с проверкой `if (!response.success)`, добавьте для AI Router исключение. `GET /v1/models/:modelId` Возвращает детали одной модели по `modelId`. Используется, когда нужно проверить характеристики модели (контекст, цену, возможности) перед запросом к [`/v1/chat/completions`](/docs/ai/chat/completions). Формат ответа совместим с `GET /v1/models/:id` из OpenAI API. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|----------| | `modelId` (path) | string | да | ID модели из [`GET /v1/models`](./list.md). Может содержать слэши: `openai/gpt-4o`, `bitrix/bitrixgpt-5.5`, `bitrix/openai/gpt-oss-120b`. Полный путь после `/v1/models/` рассматривается как `modelId` | ## Примеры ### curl — личный ключ ```bash curl https://vibecode.bitrix24.tech/v1/models/bitrix/bitrixgpt-5.5 \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl https://vibecode.bitrix24.tech/v1/models/bitrix/bitrixgpt-5.5 \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const modelId = 'bitrix/bitrixgpt-5.5' const res = await fetch(`https://vibecode.bitrix24.tech/v1/models/${modelId}`, { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const model = await res.json() console.log(`${model.name}: контекст ${model.context_length}, цена ${model.pricing.prompt}/${model.pricing.completion} Вайбов за 1M токенов`) ``` ### JavaScript — OAuth-приложение ```javascript const modelId = 'bitrix/bitrixgpt-5.5' const res = await fetch(`https://vibecode.bitrix24.tech/v1/models/${modelId}`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const model = await res.json() console.log('Поддержка vision:', model.capabilities.vision === true) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `id` | string | ID модели | | `object` | string | Всегда `model` | | `created` | number | Unix-timestamp регистрации в каталоге Вайбкод (`0` для платформенных) | | `owned_by` | string | Системное имя провайдера: `bitrix`, `openai`, `anthropic`, `openrouter`, `google` и т. п. Для платформенных моделей, которые мы перепродаём, возвращается `vibecode`. | | `name` | string | Отображаемое название модели | | `context_length` | number | Максимальный размер контекста в токенах | | `max_output_tokens` | number | Максимум токенов в ответе | | `pricing.prompt` | number | Стоимость 1М токенов входа | | `pricing.completion` | number | Стоимость 1М токенов ответа | | `pricing.perCall` | number | Плата за вызов в Вайбах. Присутствует только когда больше `0` | | `pricing.perMinute` | number | Плата за минуту аудио в Вайбах. Присутствует только когда больше `0` | | `pricing.unit` | string | Единица измерения цен: `vibes` | | `capabilities` | object | Возможности модели: `streaming`, `vision`, `reasoning`, `audio`, `transcription`, `tools`, `structured_outputs`, `embeddings` | | `replaced_by` | string | Идентификатор модели-преемника. Присутствует только когда запрошенный id снят с публикации и его вызовы обслуживает другая модель. В этом случае `pricing` показывает цену преемника | Так выглядит ответ для снятой с публикации модели: ```json "pricing": { "prompt": 68.4, "completion": 342, "unit": "vibes" }, "replaced_by": "bitrix/bitrixgpt-5.5-agent" ``` ## Пример ответа ```json { "id": "bitrix/bitrixgpt-5.5", "object": "model", "created": 0, "owned_by": "bitrix", "name": "BitrixGPT 5.5 (бесплатная)", "context_length": 262144, "max_output_tokens": 65536, "pricing": { "prompt": 0, "completion": 0, "unit": "vibes" }, "capabilities": { "streaming": true, "vision": true, "structured_outputs": true } } ``` ## Пример ответа при ошибке `404 ai_model_not_found` — модель не найдена или у ключа нет к ней доступа: ```json { "error": { "message": "Model \"openai/gpt-4o\" not found or disabled.", "type": "invalid_request_error", "code": "ai_model_not_found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 404 | `ai_model_not_found` | Модель с таким `modelId` не существует, отключена или у ключа нет доступа | | 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Ключ не найден или отозван | | 429 | `rate_limit_exceeded` | Превышен лимит запросов к AI-эндпоинтам. Время до сброса — в заголовке `Retry-After` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`modelId` со слэшами.** Эндпоинт принимает любое количество сегментов после `/v1/models/`. Например, `GET /v1/models/bitrix/openai/gpt-oss-120b` будет прочитан как `modelId = "bitrix/openai/gpt-oss-120b"`. URL-кодировать слэши не нужно. **Видимость как у списка.** Если модель не отображается в [`GET /v1/models`](./list.md) — запрос на `GET /v1/models/:modelId` вернёт `404`, даже если модель формально есть в каталоге платформы. Это значит, что у вашего ключа нет к ней доступа. Подключите учётные данные через [BYOK](/docs/ai/credentials/create). ## Смотрите также - [Список моделей](./list.md) - [Создать чат-комплишен](/docs/ai/chat/completions) --- # AI Models: Lifecycle ## Жизненный цикл моделей Модель в каталоге Вайбкод находится в одном из трёх состояний. От состояния зависит, обслуживается ли вызов запрошенной моделью и какие сигналы приходят в заголовках ответа. Правила общие для всех вызовов модели — чата, эмбеддингов и распознавания речи. | Состояние | Что происходит при вызове | Заголовки ответа | |-----------|--------------------------|------------------| | `ACTIVE` | Стандартное обслуживание, без сигналов клиенту | — | | `DEPRECATED` | Запрос обрабатывается запрошенной моделью, в заголовках приходят сигналы об устаревании | `Deprecation: true`, `Sunset: <дата отключения>` если она назначена, `Link: >; rel="successor-version"` и `X-Model-Replacement: ` если преемник назначен | | `DISABLED` | Запрос **прозрачно** перенаправляется на модель-преемник. В `response.model` приходит фактически отработавшая модель | `X-Model-Fallback: <запрошенный modelId>`, `X-Model-Replacement: <фактический modelId>`, `X-Model-Fallback-Reason: model_disabled` | ## Что делать клиенту - **`Deprecation: true`** — пометьте использование модели в логах. Если пришёл `Link: rel=successor-version`, спланируйте переход. До даты `Sunset` модель работает, после — будет отключена. - **`X-Model-Replacement` без `X-Model-Fallback`** — это рекомендуемая модель-преемник для будущих запросов. Переключиться можно сразу. - **`X-Model-Fallback` присутствует** — модель уже отключена, и ответ пришёл от преемника. Его идентификатор лежит в `response.model`. Обновите `model` в коде на этот идентификатор либо оставьте прежний: перенаправление продолжит работать. Если для отключённой модели преемник не настроен, вызов вернёт `503 model_unavailable`. Это единственный случай, когда перенаправление для состояния `DISABLED` не срабатывает. ## Сигнал в каталоге моделей В [`GET /v1/models`](./list.md) модели в состоянии `DEPRECATED` остаются — клиент видит, что они ещё работают. Модели в состоянии `DISABLED` из каталога скрыты, но прямой запрос по их `modelId` всё равно проходит через перенаправление на преемника. Проверить состояние конкретной модели можно через [`GET /v1/models/:modelId`](./get.md): у снятой с публикации модели в ответе появляется поле `replaced_by` с идентификатором преемника, а `pricing` показывает цену преемника — ту, по которой вызов фактически тарифицируется. ## Известные особенности **Заголовки соответствуют стандартам.** `Deprecation`, `Sunset` и `Link` следуют [`RFC 8594`](https://datatracker.ietf.org/doc/html/rfc8594) и [`RFC 8288`](https://datatracker.ietf.org/doc/html/rfc8288), поэтому распознаются стандартными HTTP-клиентами без дополнительного кода. **Перенаправление не меняет цену запроса.** Вызов тарифицируется по цене модели, которая фактически его обслужила. Для отключённой модели это цена преемника, а не её собственная. ## Смотрите также - [Список моделей](./list.md) - [Получить модель](./get.md) - [Создать чат-комплишен](/docs/ai/chat/completions) - [AI Router](/docs/ai) --- # AI Models: List ## Список моделей > **Ответ приходит в сыром OpenAI-формате.** > > Обёртки `{success, data}`, которая используется в остальных эндпоинтах Вайбкод — `/v1/deals`, `/v1/tasks` и других, — здесь нет. > > Так сделано для совместимости с OpenAI SDK. Если у вас единый клиент с проверкой `if (!response.success)`, добавьте для AI Router исключение. `GET /v1/models` Возвращает каталог AI-моделей, доступных текущему API-ключу. Формат ответа полностью совместим с `GET /v1/models` из OpenAI API. Бесплатные модели Битрикс24 видны всем. Модели сторонних провайдеров видны только тем ключам, у которых есть доступ к учётным данным провайдера. ## Параметры Параметров запроса нет. ## Примеры ### curl — личный ключ ```bash curl https://vibecode.bitrix24.tech/v1/models \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl https://vibecode.bitrix24.tech/v1/models \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/models', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() data.forEach((m) => { console.log(`${m.id} — ${m.name}, контекст ${m.context_length}, цена ${m.pricing.prompt}/${m.pricing.completion} Вайбов за 1М токенов`) }) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/models', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() console.log('Доступно моделей:', data.length) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `object` | string | Всегда `list` | | `data` | array | Массив моделей | | `data[].id` | string | ID модели — используйте в `model` запроса к [`/v1/chat/completions`](/docs/ai/chat/completions) | | `data[].object` | string | Всегда `model` | | `data[].created` | number | Unix-timestamp регистрации модели в каталоге Вайбкод (`0` для платформенных) | | `data[].owned_by` | string | Системное имя провайдера: `bitrix`, `openai`, `anthropic`, `openrouter`, `google` и т. п. Для платформенных моделей, которые мы перепродаём, возвращается `vibecode`. | | `data[].name` | string | Отображаемое название модели | | `data[].context_length` | number | Максимальный размер контекста в токенах (вход + выход суммарно) | | `data[].max_output_tokens` | number | Максимум токенов в ответе | | `data[].pricing.prompt` | number | Стоимость 1М токенов входа | | `data[].pricing.completion` | number | Стоимость 1М токенов ответа | | `data[].pricing.perCall` | number | Плата за вызов в Вайбах. Присутствует только когда больше `0` | | `data[].pricing.perMinute` | number | Плата за минуту аудио в Вайбах. Присутствует только когда больше `0` | | `data[].pricing.unit` | string | Единица измерения цен: `vibes` — внутренняя валюта платформы | | `data[].capabilities` | object | Возможности модели: `streaming`, `vision`, `reasoning`, `audio`, `transcription`, `tools`, `structured_outputs`, `embeddings` | ## Пример ответа ```json { "object": "list", "data": [ { "id": "bitrix/bitrixgpt-5.5", "object": "model", "created": 0, "owned_by": "bitrix", "name": "BitrixGPT 5.5 (бесплатная)", "context_length": 262144, "max_output_tokens": 65536, "pricing": {"prompt": 0, "completion": 0, "unit": "vibes"}, "capabilities": {"streaming": true, "vision": true, "structured_outputs": true} }, { "id": "bitrix/bitrixgpt-5.5-thinking", "object": "model", "created": 0, "owned_by": "bitrix", "name": "BitrixGPT 5.5 Thinking (бесплатная)", "context_length": 262144, "max_output_tokens": 65536, "pricing": {"prompt": 0, "completion": 0, "unit": "vibes"}, "capabilities": {"streaming": true, "vision": true, "reasoning": true, "structured_outputs": true} }, { "id": "bitrix/bitrixgpt-5.5-agent", "object": "model", "created": 0, "owned_by": "bitrix", "name": "BitrixGPT 5.5 Agent", "context_length": 262144, "max_output_tokens": 65535, "pricing": {"prompt": 68.4, "completion": 342, "unit": "vibes"}, "capabilities": {"streaming": true} } ] } ``` ## Пример ответа при ошибке `403 scope_missing` — у API-ключа нет скоупа `vibe:ai`: ```json { "error": { "message": "API key does not have the vibe:ai scope required for AI endpoints. Add vibe:ai scope to your API key in portal settings.", "type": "invalid_request_error", "code": "scope_missing" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Ключ не найден или отозван | | 429 | `rate_limit_exceeded` | Превышен лимит запросов к AI-эндпоинтам. Время до сброса — в заголовке `Retry-After` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Видимость зависит от настроенных учётных данных.** В каталоге показаны только те модели, для которых текущий API-ключ имеет доступ к учётным данным провайдера — общим для всей платформы, общим в портале или вашим личным BYOK. Модели Битрикс24 (`bitrix/*`) доступны всем без подключения BYOK. Если нужной модели в списке нет — [подключите свой ключ](/docs/ai/credentials/create). **Модели в статусе `DEPRECATED` остаются в списке.** Они помечены как устаревшие, но запросы к ним ещё работают — будут возвращены заголовки `Deprecation` и `Sunset`. Модели в статусе `DISABLED` из списка скрыты, но при явном указании в `model` будут прозрачно перенаправлены на модель-преемник. **Цены — в Вайбах за 1 миллион токенов.** Поле `pricing.unit: "vibes"` явно маркирует валюту, чтобы внешний клиент мог программно проверить единицу измерения. Вайбы — внутренняя валюта платформы, баланс пополняется через личный кабинет. **Не все модели тарифицируются по токенам.** У модели распознавания речи `prompt` и `completion` равны `0`, а оплата идёт по полям `perMinute` за минуту аудио и `perCall` за вызов. Нулевые `prompt` и `completion` сами по себе не означают, что вызов бесплатный — проверяйте все четыре поля `pricing`. ## Смотрите также - [Получить модель](./get.md) - [Создать чат-комплишен](/docs/ai/chat/completions) - [Эмбеддинги](/docs/ai/embeddings) - [Свои ключи (BYOK)](/docs/ai/credentials) --- # Open Channels: Config # Конфигурации открытых линий Управление конфигурациями открытых линий Битрикс24: настройка входящих обращений из мессенджеров и социальных сетей, очереди операторов, рабочего времени, интеграции с CRM, приветственных сообщений и оценки качества обслуживания. Битрикс24 API: `imopenlines.config.*` Скоуп: `imopenlines` ## Операции - [Создать конфигурацию](./config/create.md) — `POST /v1/openline-configs` - [Список конфигураций](./config/list.md) — `GET /v1/openline-configs` - [Получить конфигурацию](./config/get.md) — `GET /v1/openline-configs/:id` - [Обновить конфигурацию](./config/update.md) — `PATCH /v1/openline-configs/:id` - [Удалить конфигурацию](./config/delete.md) — `DELETE /v1/openline-configs/:id` - [Поиск конфигураций](./config/search.md) — `POST /v1/openline-configs/search` - [Поля конфигурации](./config/fields.md) — `GET /v1/openline-configs/fields` - [Агрегация конфигураций](./config/aggregate.md) — `POST /v1/openline-configs/aggregate` ## Действия оператора над диалогом Помимо CRUD конфигураций есть пара действий, которые оператор выполняет над конкретным диалогом открытой линии. Оба требуют скоуп `imopenlines` и принимают `chatId` — идентификатор объекта чата открытой линии, а **не** `dialogId` с префиксом `chat`. Идентификаторы чатов сессий отдаёт [Список сессий](./sessions.md) в поле `sessions[].chatId`. Этот метод выходит в обновлении `imopenlines 26.700.0` и доступен пока не на всех порталах. ### `POST /v1/openlines/operator/answer` Принимает диалог к обработке текущим оператором. ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/openlines/operator/answer" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"chatId": 2043}' ``` Ответ при успехе: `{ "success": true, "data": { "chatId": 2043, "answered": true } }`. ### `POST /v1/openlines/operator/finish` Завершает диалог от имени текущего оператора. ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/openlines/operator/finish" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"chatId": 2043}' ``` Ответ при успехе: `{ "success": true, "data": { "chatId": 2043, "finished": true } }`. ### Ошибки операторских эндпоинтов | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_CHAT_ID` | `chatId` отсутствует, не является положительным целым или передан в неверном формате | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imopenlines` | | 403 | `BITRIX_ACCESS_DENIED` | У оператора недостаточно прав на действие с этим диалогом | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 502 | `OPENLINE_OPERATOR_FAILED` | Битрикс24 вернул `result: false` — диалог уже взят/завершён другим оператором, либо `chatId` не соответствует активному диалогу открытой линии | | 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку: `CHAT_TYPE` (чат не является открытой линией), `USER_ID` (неверный идентификатор пользователя). Детали — в `error.message` | ## Ключевые поля | Поле | Описание | |------|---------| | `id` | Идентификатор конфигурации (число) | | `name` | Название открытой линии | | `active` | Признак активности: `true` — линия принимает обращения, `false` — отключена | | `queueType` | Алгоритм распределения: `all` — всем операторам, `evenly` — равномерно, `strictly` — строго по очереди | | `queue` | Массив идентификаторов операторов очереди — приходит только в `GET /v1/openline-configs/:id`. Источник идентификаторов: `GET /v1/users` | | `welcomeBotId` | Идентификатор приветственного бота — бот, с которым начинается диалог до передачи оператору. Источник: `/docs/bots/management/list` | | `crmCreate` | Признак автоматического создания лида или контакта в CRM при входящем обращении | | `workTimeEnable` | Признак использования расписания рабочего времени | Полный список полей — [`GET /v1/openline-configs/fields`](./config/fields.md). ## Что нужно знать перед работой 1. **Единый регистр полей — camelCase.** Поля верхнего уровня в ответах `list`, `get` и `search` приходят в camelCase — `crmCreate`, `workTimeEnable`, `welcomeBotId`, `queueType`. По этим же именам работают `filter` и `sort`. В [агрегации](./config/aggregate.md) `groupBy` принимает только два поля — `active` и `queueType`. Вложенные объекты очереди операторов — `queueFull` и `queueUsersFields` из ответа `get` — внутри несут ключи в UPPER_SNAKE_CASE (`USER_ID`, `USER_NAME`, `DEPARTMENT_ID`), см. [Получить конфигурацию](./config/get.md). Полный реестр с типами и описаниями — [Поля конфигурации](./config/fields.md). 2. **Разный набор полей в `list`/`search` и в `get`.** `GET /v1/openline-configs` и `POST /v1/openline-configs/search` возвращают по 91 полю на запись. `GET /v1/openline-configs/:id` дополнительно отдаёт 4 поля очереди операторов — `queue`, `queueFull`, `queueUsersFields`, `queueOnline` — итого 95 полей. 3. **Минимум для создания — хотя бы одно распознанное записываемое поле.** Остальные поля при создании опциональны. Тело запроса передаётся в camelCase — это канонический регистр. Имена в UPPER_SNAKE_CASE также принимаются для обратной совместимости. 4. **Адресация по `id`.** Для получения, обновления и удаления используется числовой `id` из ответа. Бывшие «зарезервированные» поля `lineId` и `agentId` удалены из схемы — Битрикс24 никогда их не возвращал. ## Связанные сущности | Сущность | Эндпоинт | Назначение | |----------|----------|-----------| | Пользователи | `GET /v1/users` | Источник идентификаторов операторов для поля `queue` | | Боты | `/docs/bots/management/list` | Источник идентификатора приветственного бота для поля `welcomeBotId` | ## Типичный сценарий 1. Получить список конфигураций: [`GET /v1/openline-configs`](./config/list.md). 2. Создать конфигурацию с минимальным набором полей: [`POST /v1/openline-configs`](./config/create.md) с `name`. 3. Получить полную запись с очередью операторов: [`GET /v1/openline-configs/:id`](./config/get.md). 4. Обновить параметры: [`PATCH /v1/openline-configs/:id`](./config/update.md). 5. Удалить конфигурацию: [`DELETE /v1/openline-configs/:id`](./config/delete.md). ## Лимиты | Лимит | Значение | |-------|----------| | Максимум записей на запрос | 200 (`limit ≤ 200`). На типичном портале конфигураций — десятки, одного запроса хватает на всё | | Пагинация | через `limit` + `offset`. Используйте поле `hasMore` для проверки следующей страницы | | Batch-доступные операции | `create`, `update`, `delete` — через [`POST /v1/batch`](/docs/batch) | | Rate limit | общий для API Вайбкод — см. [Лимиты и оптимизация](/docs/optimization) | ## Смотрите также - [Открытые линии](/docs/openlines) - [Справочник сущностей](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) - [Batch](/docs/batch) - [Лимиты и оптимизация](/docs/optimization) --- # Open Channels Config: Aggregate ## Агрегация конфигураций открытых линий `POST /v1/openline-configs/aggregate` Подсчёт количества конфигураций открытых линий с опциональной группировкой по типу очереди и другим полям схемы. **Группировка.** `groupBy` принимает 2 поля: `active`, `queueType` — это `aggregatable`-поля из [`GET /v1/openline-configs/fields`](/docs/openlines/config/fields). Остальные поля (`id`, `name`, `workTimeFrom`, `workTimeTo` и прочие camelCase-поля ответа) в `groupBy` отвергаются с `400 INVALID_PARAMS` — подробности в [Известных особенностях](#известные-особенности). **Числовые агрегации (`sum`/`avg`/`min`/`max`) не применимы.** Поля openline-configs — категориальные или идентификационные. Поддерживается только функция `count` с `field: "*"`. ## Поля запроса (body) | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `aggregate` | array | нет | Массив агрегаций. Каждый элемент: `{ "field": "*", "function": "count" }`. Функция `count` требует `field: "*"`. Без параметра — только `count` | | `filter` | object | нет | Фильтрация. [Синтаксис фильтрации](/docs/filtering). Пример: `{"active": false}` | | `groupBy` | string \| string[] | нет | Поле или массив полей для группировки. Допустимые значения: `active`, `queueType` — см. [Известные особенности](#известные-особенности) | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/openline-configs/aggregate" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "groupBy": "queueType" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/openline-configs/aggregate" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "groupBy": "queueType" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openline-configs/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ groupBy: 'queueType', }), }) const { success, data } = await res.json() console.log('Всего конфигураций:', data.count) console.log('По типу очереди:', data.groups) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openline-configs/aggregate', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ groupBy: 'queueType', }), }) const { success, data } = await res.json() ``` > Для группировки по нескольким полям передайте массив: `"groupBy": ["queueType", "active"]`. Принимаются комбинации из 2 допустимых полей: `active`, `queueType`. ## Другие сценарии Блоки ниже — тела запросов. Общее количество конфигураций — самый быстрый запрос, без выгрузки записей: ```json {} ``` Явная передача `count` через `aggregate`: ```json { "aggregate": [{ "field": "*", "function": "count" }] } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.count` | number | Итоговое количество конфигураций в выборке (после применения фильтра, если он сработал). Это основной показатель для приложения | | `data.aggregates` | object | Результаты агрегаций (для openline-configs всегда `{}`) | | `data.groups` | array | Группы (только при `groupBy`). Каждый элемент: поле группировки + `count` + `aggregates` | | `data.meta.totalRecords` | number | Сколько записей обработано во входной выборке. Без `groupBy` совпадает с `data.count`, с `groupBy` равен сумме `count` по всем группам. Техническая метрика | | `data.meta.recordsProcessed` | number | Сколько записей реально обработано при группировке. `0`, если `groupBy` не передан | | `data.meta.truncated` | boolean | `true`, если под выборку попало более 5000 записей | | `data.meta.groupTotal` | number | Количество групп в результате (только при `groupBy`) | | `data.meta.groupsTruncated` | boolean | Признак усечения списка групп (только при `groupBy`) | ## Пример ответа Ответ на основной запрос (`groupBy: "queueType"`): ```json { "success": true, "data": { "count": 10, "aggregates": {}, "groups": [ { "queueType": "all", "count": 9, "aggregates": {} }, { "queueType": "evenly", "count": 1, "aggregates": {} } ], "meta": { "totalRecords": 10, "recordsProcessed": 10, "truncated": false, "groupTotal": 2, "groupsTruncated": false } } } ``` Без `groupBy` поле `data.groups` в ответе отсутствует. ## Пример ответа при ошибке 400 — функция `count` с неверным именем поля: ```json { "success": false, "error": { "code": "INVALID_PARAMS", "message": "count aggregate requires field \"*\"" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_PARAMS` | Функция `count` передана с `field` не равным `"*"`, или передан `groupBy` по полю не из схемы Вайбкод | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imopenlines` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Параметр `filter` в агрегации игнорируется.** Передача `{"filter": {"active": false}}` не влияет на результат — метод возвращает `count` по всем конфигурациям портала. Для подсчёта по подмножеству используйте `groupBy` (например, `groupBy: ["active"]` разобьёт результат по признаку активности) или обрабатывайте результат [`POST /v1/openline-configs/search`](/docs/openlines/config/search) на стороне клиента. **Функция `count` требует `field: "*"`.** При передаче `{"field": "id", "function": "count"}` возвращается `400 INVALID_PARAMS`. Единственный корректный формат: `{"field": "*", "function": "count"}`. **`groupBy` принимает только 2 поля из схемы Вайбкод:** `active`, `queueType`. Это `aggregatable`-поля из ответа [`GET /v1/openline-configs/fields`](/docs/openlines/config/fields). Остальные поля (`id`, `name`, `workTimeFrom`, `workTimeTo`, `queueTime`, `crm`, ...) в `groupBy` отвергаются с `400 INVALID_PARAMS` и сообщением «groupBy field 'X' is not aggregatable on this entity. Available: active, queueType». ## Смотрите также - [Список конфигураций](/docs/openlines/config/list) - [Синтаксис фильтрации](/docs/filtering) - [Лимиты и оптимизация](/docs/optimization) --- # Open Channels Config: Create ## Создать конфигурацию открытой линии `POST /v1/openline-configs` Создаёт новую конфигурацию открытой линии. Для создания достаточно передать хотя бы одно распознанное записываемое поле — остальные параметры устанавливаются по умолчанию. Полная запись с идентификаторами и всеми полями доступна через `GET /v1/openline-configs/:id`. ## Поля запроса (body) Минимум для создания: хотя бы одно распознанное записываемое поле (см. [Поля конфигурации](/docs/openlines/config/fields)). **Имена полей.** Все поля передавайте в camelCase — `name`, `active`, `queueType`, `crmCreate`, `workTimeFrom` и другие из [Поля конфигурации](/docs/openlines/config/fields). Это канонический регистр, в нём поля приходят и в ответе, и в `GET /v1/openline-configs/fields`. Имена в UPPER_SNAKE_CASE также принимаются для обратной совместимости. Пример ниже использует camelCase. **Булевы поля** (`active`, `crm`, `workTimeEnable`, `welcomeMessage`, …) принимают `true` / `false` — значение приводится к ожидаемому Битрикс24 `"Y"`/`"N"` автоматически. | Поле | Тип | Обяз. | Описание | |------|-----|-------|---------| | `name` | string | нет | Название открытой линии | | `active` | boolean | нет | Активна ли линия (`true` / `false`) | | `queueType` | string | нет | Распределение очереди: `all` — всем одновременно, `evenly` — равномерно, `strictly` — строго по порядку | | `queueTime` | number | нет | Время ожидания в очереди (секунды) до перевода | | `noAnswerTime` | number | нет | Время без ответа (секунды), после которого срабатывает правило `noAnswerRule` | | `crm` | boolean | нет | Включить интеграцию с CRM | | `crmCreate` | string | нет | Режим создания CRM-сущностей при новом обращении | | `workTimeEnable` | boolean | нет | Включить расписание рабочего времени | | `workTimeFrom` | string | нет | Начало рабочего дня (например `"9"` или `"9.30"`) | | `workTimeTo` | string | нет | Конец рабочего дня (например `"18"` или `"18.30"`) | | `workTimeTimezone` | string | нет | Часовой пояс расписания (например `"Europe/Moscow"`) | | `welcomeMessage` | boolean | нет | Включить приветственное сообщение | | `welcomeMessageText` | string | нет | Текст приветственного сообщения | | `languageId` | string | нет | Язык линии (например `"ru"`, `"en"`) | Полный список полей — [`GET /v1/openline-configs/fields`](/docs/openlines/config/fields). ## Примеры ### curl — личный ключ ```bash curl -X POST https://vibecode.bitrix24.tech/v1/openline-configs \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Поддержка клиентов", "active": true, "queueType": "evenly", "workTimeEnable": true, "workTimeFrom": "9", "workTimeTo": "18" }' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/openline-configs \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Поддержка клиентов", "active": true, "queueType": "evenly", "workTimeEnable": true, "workTimeFrom": "9", "workTimeTo": "18" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openline-configs', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Поддержка клиентов', active: true, queueType: 'evenly', workTimeEnable: true, workTimeFrom: '9', workTimeTo: '18', }), }) const { success, data } = await res.json() console.log('Новая конфигурация ID:', data) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openline-configs', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Поддержка клиентов', active: true, queueType: 'evenly', workTimeEnable: true, workTimeFrom: '9', workTimeTo: '18', }), }) const { success, data } = await res.json() console.log('Новая конфигурация ID:', data) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | number | Идентификатор созданной конфигурации | | `meta.warnings` | string[] | Необязательное. Присутствует, если часть переданных полей не распознана — перечисляет ключи, которые Битрикс24 проигнорировал | ## Пример ответа ```json { "success": true, "data": 29 } ``` ## Пример ответа при ошибке 400 — в теле нет ни одного распознанного поля: ```json { "success": false, "error": { "code": "VALIDATION_ERROR", "message": "No recognised openline-configs field in the body. Unrecognised: bogusField. Provide at least one known field (e.g. lineName, queueType, active) — see GET /v1/openline-configs/fields." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `VALIDATION_ERROR` | Тело запроса пустое — не передано ни одного поля | | 400 | `VALIDATION_ERROR` | В теле нет ни одного распознанного поля (все ключи неизвестны) — в сообщении перечислены нераспознанные поля | | 400 | `READONLY_FIELD` | В теле передано поле только для чтения (`id`, `queue`, `dateCreate` и другие) | | 401 | `TOKEN_MISSING` | Заголовок `X-Api-Key` не передан | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imopenlines` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности `data` в ответе — это число (идентификатор новой конфигурации), а не объект записи. Чтобы получить созданную конфигурацию со всеми полями, выполните отдельный запрос: `GET /v1/openline-configs/:id`. **Нераспознанные поля.** Незнакомые ключи в теле запроса не сохраняются. Вайбкод сверяет тело с полной схемой полей ([Поля конфигурации](/docs/openlines/config/fields)) и реагирует так: - ни одно поле не распознано (например `{ "bogusField": "x" }`) — запрос отклоняется с `400 VALIDATION_ERROR` до вызова Битрикс24, в сообщении перечислены нераспознанные поля. - распознано хотя бы одно поле, но часть ключей неизвестна — конфигурация создаётся, а в ответе возвращается `meta.warnings` со списком проигнорированных ключей. - в теле передано поле только для чтения (`id`, `queue`, `dateCreate` и другие) — запрос отклоняется с `400 READONLY_FIELD`. ## Смотрите также - [Получить конфигурацию](/docs/openlines/config/get) - [Список конфигураций](/docs/openlines/config/list) - [Поля конфигурации](/docs/openlines/config/fields) --- # Open Channels Config: Delete ## Удалить конфигурацию открытой линии `DELETE /v1/openline-configs/:id` Удаляет конфигурацию открытой линии по ID. Восстановить удалённую запись через API нельзя — создавайте новую при необходимости. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID конфигурации | ## Примеры ### curl — личный ключ ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/openline-configs/29" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X DELETE "https://vibecode.bitrix24.tech/v1/openline-configs/29" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openline-configs/29', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() if (success && data.deleted) { console.log('Конфигурация удалена, ID:', data.id) } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openline-configs/29', { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() if (success && data.deleted) { console.log('Конфигурация удалена, ID:', data.id) } ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | number | ID удалённой конфигурации | | `data.deleted` | boolean | `true` при успешном удалении | ## Пример ответа ```json { "success": true, "data": { "id": 29, "deleted": true } } ``` ## Пример ответа при ошибке 404 — конфигурация не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "openlineConfig 99999 not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_ID` | `id` не является положительным целым числом | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imopenlines` | | 404 | `ENTITY_NOT_FOUND` | Конфигурация с указанным ID не найдена | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Смотрите также - [Список конфигураций](/docs/openlines/config/list) - [Получить конфигурацию](/docs/openlines/config/get) - [Batch](/docs/batch) --- # Open Channels Config: Fields ## Поля конфигурации открытой линии `GET /v1/openline-configs/fields` Возвращает схему полей, доступных для фильтрации и сортировки, а также полный реестр полей в ответах `list`, `get` и `search`. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/openline-configs/fields" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/openline-configs/fields" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openline-configs/fields', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Поля схемы:', Object.keys(data.fields)) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openline-configs/fields', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа Эндпоинт `/fields` возвращает `data.fields` — описание **всех** полей ответов `list`, `get` и `search`: каждое поле снабжено `type`, `readonly`, названием `label` и описанием `description`. Имена полей — **в camelCase**. Полный набор в `get` — 95 полей, в `list`/`search` — 91 (без 4 полей очереди операторов). Дополнительно `data` содержит `aggregatable` и `batch`. ### Схема полей (data.fields) `/fields` возвращает полный набор полей — каждое с `type`, `readonly`, `label` и `description`. Фильтрация (`filter`), сортировка (`sort`) и группировка (`groupBy`) работают по этим camelCase-именам. Ниже — основные поля, чаще всего используемые в `sort` и `filter`: | Поле | Тип | RO | Описание | |------|-----|----|---------| | `id` | number | да | Идентификатор конфигурации | | `name` | string | | Название открытой линии | | `active` | boolean | | Активна ли линия | | `queueType` | string | | Алгоритм распределения: `all` — всем операторам одновременно, `evenly` — равномерно, `strictly` — строго по очереди | | `workTimeFrom` | string | | Начало рабочего времени (например `"8"` или `"9.30"`) | | `workTimeTo` | string | | Конец рабочего времени | Дополнительно в `data` указаны: - `aggregatable` — поля, доступные для `groupBy`: `["active", "queueType"]` - `batch` — перечень пакетных операций, объявленных для этой сущности в ответе `/fields`: пустой массив `[]` ### Полный реестр полей ответа (list / get / search) В `get` объект `data` содержит 95 полей (все в camelCase), в `list`/`search` — 91 (без 4 полей с отметкой «только `get`»: `queue`, `queueFull`, `queueUsersFields`, `queueOnline`). #### Основные | Поле | Тип | RO | Источник | Описание | |------|-----|----|---------|---------| | `id` | number | да | везде | Идентификатор конфигурации | | `name` | string | | везде | Название открытой линии | | `active` | boolean | | везде | Линия активна (`true`/`false`) | | `temporary` | string | | везде | Временная линия: `"Y"` / `"N"` | | `xmlId` | string\|null | | везде | Внешний идентификатор | | `languageId` | string\|null | | везде | Язык линии (например `"ru"`). `null`, если язык не задан | #### Очередь и операторы | Поле | Тип | RO | Источник | Описание | |------|-----|----|---------|---------| | `queueType` | string | | везде | Алгоритм распределения: `all` — всем операторам одновременно, `evenly` — равномерно, `strictly` — строго по очереди | | `queueTime` | string | | везде | Время ожидания в очереди (секунды) | | `noAnswerTime` | string | | везде | Время без ответа оператора до переключения (секунды) | | `checkAvailable` | string | | везде | Проверять доступность оператора: `"Y"` / `"N"` | | `maxChat` | string\|null | | везде | Максимальное число одновременных чатов на оператора (`"0"` — без ограничения). `null`, если не задан | | `typeMaxChat` | string\|null | | везде | Тип подсчёта лимита чатов: `answered` — только принятые, `total` — все. `null`, если не задан | | `queue` | string[] | да | только `get` | Массив ID операторов в очереди (строки) | | `queueFull` | object | да | только `get` | Объекты операторов с полями `ID`, `SORT`, `USER_ID`, `DEPARTMENT_ID`, `USER_NAME`, `USER_WORK_POSITION`, `USER_AVATAR`, `USER_AVATAR_ID` | | `queueUsersFields` | object | да | только `get` | Данные профилей операторов: `USER_NAME`, `USER_WORK_POSITION`, `USER_AVATAR`, `USER_AVATAR_ID` | | `queueOnline` | string | да | только `get` | Есть ли операторы онлайн в данный момент: `"Y"` / `"N"` | #### Интеграция с CRM | Поле | Тип | RO | Источник | Описание | |------|-----|----|---------|---------| | `crm` | string | | везде | Включить интеграцию с CRM: `"Y"` / `"N"` | | `crmCreate` | string | | везде | Тип создаваемой CRM-записи при первом обращении: `deal`, `lead`, `contact`, `company` | | `crmCreateSecond` | string | | везде | Тип записи при повторных обращениях (числовой идентификатор типа) | | `crmCreateThird` | string | | везде | Тип записи при третьем и последующих обращениях: `"Y"` / `"N"` | | `crmForward` | string | | везде | Переадресовывать обращение ответственному из CRM: `"Y"` / `"N"` | | `crmChatTracker` | string | | везде | Включить трекер чата в CRM: `"Y"` / `"N"` | | `crmTransferChange` | string | | везде | Менять ответственного при переводе чата: `"Y"` / `"N"` | | `crmSource` | string | | везде | Источник CRM-записи: `create` — создавать, другое значение — брать из истории | #### Приветственное сообщение | Поле | Тип | RO | Источник | Описание | |------|-----|----|---------|---------| | `welcomeMessage` | string | | везде | Показывать приветствие: `"Y"` / `"N"` | | `welcomeMessageText` | string | | везде | Текст приветствия (поддерживает BB-код) | | `watchTyping` | string | | везде | Показывать индикатор набора текста: `"Y"` / `"N"` | | `sendWelcomeEachSession` | string | | везде | Отправлять приветствие при каждой новой сессии: `"Y"` / `"N"` | #### Приветственный бот | Поле | Тип | RO | Источник | Описание | |------|-----|----|---------|---------| | `welcomeBotEnable` | string | | везде | Включить приветственного бота: `"Y"` / `"N"` | | `welcomeBotId` | string | | везде | ID бота. Список: `GET /v1/bots` | | `welcomeBotTime` | string | | везде | Время ожидания ответа бота (секунды) | | `welcomeBotJoin` | string | | везде | Когда бот присоединяется: `always` — всегда, другие значения по настройке | | `welcomeBotLeft` | string | | везде | Когда бот покидает чат: `queue` — после постановки в очередь, другие значения по настройке | #### Рабочее время | Поле | Тип | RO | Источник | Описание | |------|-----|----|---------|---------| | `workTimeEnable` | string | | везде | Включить расписание рабочего времени: `"Y"` / `"N"` | | `workTimeFrom` | string | | везде | Начало рабочего дня (например `"8"`, `"9.30"`) | | `workTimeTo` | string | | везде | Конец рабочего дня | | `workTimeTimezone` | string | | везде | Часовой пояс (например `"Europe/Kaliningrad"`) | | `workTimeHolidays` | string[] | | везде | Праздничные нерабочие дни в формате `"ДД.ММ"` (например `["1.01","7.01"]`) | | `workTimeDayoff` | string[] | | везде | Выходные дни недели: `"MO"`, `"TU"`, `"WE"`, `"TH"`, `"FR"`, `"SA"`, `"SU"` | #### Сценарии нерабочего времени, нет ответа, закрытие Три группы по четыре поля — сценарий, форма, бот, текст: | Поле | Тип | RO | Источник | Описание | |------|-----|----|---------|---------| | `workTimeDayoffRule` | string | | везде | Действие в выходной день: `text` — сообщение, `form` — форма, `bot` — бот, `none` — ничего | | `workTimeDayoffFormId` | string | | везде | ID формы для нерабочего времени | | `workTimeDayoffBotId` | string | | везде | ID бота для нерабочего времени. Список: `GET /v1/bots` | | `workTimeDayoffText` | string | | везде | Текст сообщения в нерабочее время (поддерживает BB-код) | | `noAnswerRule` | string | | везде | Действие при нет ответа: `text`, `form`, `bot`, `none` | | `noAnswerFormId` | string | | везде | ID формы при нет ответа | | `noAnswerBotId` | string | | везде | ID бота при нет ответа. Список: `GET /v1/bots` | | `noAnswerText` | string | | везде | Текст сообщения при нет ответа | | `closeRule` | string | | везде | Действие при закрытии чата: `text`, `form`, `bot`, `none` | | `closeFormId` | string | | везде | ID формы при закрытии | | `closeBotId` | string | | везде | ID бота при закрытии. Список: `GET /v1/bots` | | `closeText` | string | | везде | Текст сообщения при закрытии | | `fullCloseTime` | string | | везде | Время до полного закрытия чата (секунды) | | `confirmClose` | string | | везде | Запрашивать подтверждение при закрытии чата: `"Y"` / `"N"` | | `showNotificationRedirect` | string\|null | | везде | Показывать уведомление при перенаправлении: `"Y"` / `"N"` / `null` | #### Автозакрытие по неактивности | Поле | Тип | RO | Источник | Описание | |------|-----|----|---------|---------| | `autoCloseRule` | string | | везде | Действие при истечении времени неактивности: `text`, `form`, `bot`, `none` | | `autoCloseFormId` | string | | везде | ID формы при автозакрытии | | `autoCloseBotId` | string | | везде | ID бота при автозакрытии. Список: `GET /v1/bots` | | `autoCloseTime` | string | | везде | Время до автозакрытия чата (секунды) | | `autoCloseText` | string\|null | | везде | Текст при автозакрытии. Незаданное значение приходит как `null` | | `autoExpireTime` | string | | везде | Время истечения сессии по неактивности (секунды) | #### Оценка качества | Поле | Тип | RO | Источник | Описание | |------|-----|----|---------|---------| | `voteMessage` | string | | везде | Включить запрос оценки: `"Y"` / `"N"` | | `voteTimeLimit` | string | | везде | Ограничение времени на оценку (секунды, `"0"` — без ограничения) | | `voteBeforeFinish` | string | | везде | Запрашивать оценку до завершения чата: `"Y"` / `"N"` | | `voteClosingDelay` | string | | везде | Задержка закрытия после оценки: `"Y"` / `"N"` | | `voteMessage1Text` | string | | везде | Текст запроса оценки (простые сообщения с кнопками) | | `voteMessage1Like` | string | | везде | Ответ при положительной оценке | | `voteMessage1Dislike` | string | | везде | Ответ при отрицательной оценке | | `voteMessage2Text` | string | | везде | Текст запроса оценки (текстовый режим, `1`/`0`) | | `voteMessage2Like` | string | | везде | Ответ при `1` (положительная) | | `voteMessage2Dislike` | string | | везде | Ответ при `0` (отрицательная) | #### Соглашения и категории | Поле | Тип | RO | Источник | Описание | |------|-----|----|---------|---------| | `agreementMessage` | string | | везде | Запрашивать согласие с условиями: `"Y"` / `"N"` | | `agreementId` | string | | везде | ID документа с условиями | | `categoryEnable` | string | | везде | Включить категоризацию обращений: `"Y"` / `"N"` | | `categoryId` | string | | везде | ID категории по умолчанию | #### Форма ожидания | Поле | Тип | RO | Источник | Описание | |------|-----|----|---------|---------| | `useWelcomeForm` | string | | везде | Показывать форму перед постановкой в очередь: `"Y"` / `"N"` | | `welcomeFormId` | string | | везде | ID формы ожидания | | `welcomeFormDelay` | string | | везде | Задержка показа формы: `"Y"` / `"N"` | | `ignoreWelcomeFormResponsible` | string | | везде | Пропускать форму для ответственного из CRM: `"Y"` / `"N"` | #### Оператор и сессия | Поле | Тип | RO | Источник | Описание | |------|-----|----|---------|---------| | `operatorData` | string | | везде | Данные оператора в чате: `profile` — полный профиль | | `defaultOperatorData` | object | | везде | Данные оператора по умолчанию: объект с полями `NAME` и `AVATAR`. Если данные не заданы, приходит `null` — не пустой массив (раньше поле объявлялось массивом, см. [журнал изменений](/docs/changelog)) | | `sessionPriority` | string | | везде | Приоритет сессии (`"0"` — стандартный) | | `quickAnswersIblockId` | string | | везде | ID инфоблока с быстрыми ответами | #### KPI | Поле | Тип | RO | Источник | Описание | |------|-----|----|---------|---------| | `kpiFirstAnswerTime` | string | | везде | Норматив времени первого ответа (секунды) | | `kpiFirstAnswerAlert` | string | | везде | Отправлять предупреждение при нарушении KPI первого ответа: `"Y"` / `"N"` | | `kpiFirstAnswerList` | string[] | | везде | Список ID получателей предупреждения по KPI первого ответа. Пустой набор приходит как `[]` | | `kpiFirstAnswerText` | string\|null | | везде | Шаблон текста предупреждения (поддерживает `#OPERATOR#`, `#DIALOG#`). `null`, если не задан | | `kpiFurtherAnswerTime` | string | | везде | Норматив времени последующих ответов (секунды) | | `kpiFurtherAnswerAlert` | string | | везде | Отправлять предупреждение при нарушении KPI последующих ответов: `"Y"` / `"N"` | | `kpiFurtherAnswerList` | string[] | | везде | Список ID получателей предупреждения. Пустой набор приходит как `[]` | | `kpiFurtherAnswerText` | string\|null | | везде | Шаблон текста предупреждения. `null`, если не задан | | `kpiCheckOperatorActivity` | string | | везде | Контролировать активность оператора: `"Y"` / `"N"` | | `sendNotificationEmptyQueue` | string | | везде | Уведомлять при пустой очереди: `"Y"` / `"N"` | #### Служебные | Поле | Тип | RO | Источник | Описание | |------|-----|----|---------|---------| | `dateCreate` | object | да | везде | Дата создания — приходит как пустой объект `{}` | | `dateModify` | object | да | везде | Дата последнего изменения — приходит как пустой объект `{}` | | `modifyUserId` | string | да | везде | ID пользователя, внёсшего последнее изменение. Поиск: `GET /v1/users` | ## Пример ответа Показаны несколько представительных полей. Полный набор больше — 95 полей в `get`, 91 в `list`/`search`. ```json { "success": true, "data": { "fields": { "id": { "type": "number", "readonly": true, "label": "Идентификатор", "description": "Идентификатор конфигурации." }, "name": { "type": "string", "readonly": false, "label": "Название линии", "description": "Название открытой линии." }, "active": { "type": "boolean", "readonly": false, "label": "Линия активна", "description": "Линия активна (true/false)." }, "queueType": { "type": "string", "readonly": false, "label": "Алгоритм распределения", "description": "Алгоритм распределения: all — всем одновременно, evenly — равномерно, strictly — строго по очереди." }, "crmCreate": { "type": "string", "readonly": false, "label": "Создаваемая CRM-запись", "description": "Тип создаваемой CRM-записи при первом обращении: deal, lead, contact, company." }, "welcomeMessage": { "type": "string", "readonly": false, "label": "Показывать приветствие", "description": "Показывать приветствие: Y/N." }, "workTimeFrom": { "type": "string", "readonly": false, "label": "Начало рабочего дня", "description": "Начало рабочего дня (например 8, 9.30)." } }, "aggregatable": ["active", "queueType"], "batch": [] } } ``` ## Пример ответа при ошибке 403 — нет скоупа: ```json { "success": false, "error": { "code": "SCOPE_DENIED", "message": "Access denied. Required scope: imopenlines" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `TOKEN_MISSING` | API-ключ не передан | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imopenlines` | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Единый набор имён — camelCase.** Все поля ответов `list`/`get`/`search` приходят в camelCase. Эндпоинт `/fields` (`data.fields`) описывает каждое поле с `type`, `readonly`, `label` и `description`. По этим именам работают `filter`, `sort`, `groupBy`. Всего 91 поле в `list`/`search`, 95 в `get` (добавляются 4 поля очереди операторов). При **записи** (`create`/`update`) camelCase — канонический регистр. Имена в UPPER_SNAKE_CASE также принимаются для обратной совместимости. Булевы поля при записи принимают `true`/`false` (приводятся к `"Y"`/`"N"`). **Числовые поля приходят строками.** `queueTime`, `noAnswerTime`, `autoCloseTime`, `maxChat`, `kpiFirstAnswerTime` и другие — строки (`"60"`, `"180"`). Исключение — `id` (`number`) и `active` (`boolean`): эти два поля трансформирует схема API Вайбкод. **`dateCreate` и `dateModify` всегда пустые объекты `{}`.** Битрикс24 не передаёт значения дат через эти поля. ## Смотрите также - [Список конфигураций](/docs/openlines/config/list) - [Получить конфигурацию](/docs/openlines/config/get) - [Entity API](/docs/entity-api) - [Синтаксис фильтрации](/docs/filtering) --- # Open Channels Config: Get ## Получить конфигурацию открытой линии `GET /v1/openline-configs/:id` Возвращает конфигурацию открытой линии по ID со всеми полями, включая данные очереди операторов. ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | ID конфигурации | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/openline-configs/1" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/openline-configs/1" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openline-configs/1', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data } = await res.json() console.log('Линия:', data.name, '— тип очереди:', data.queueType) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openline-configs/1', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data } = await res.json() ``` ## Поля ответа Ответ содержит 95 полей, все в camelCase — `/fields` описывает каждое поле с `label` и `description`: [Поля открытой линии](/docs/openlines/config/fields). | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Объект конфигурации (все поля — см. [Поля открытой линии](/docs/openlines/config/fields)) | ## Пример ответа Показаны ключевые поля. Полный список: [Поля открытой линии](/docs/openlines/config/fields). ```json { "success": true, "data": { "id": 1, "active": true, "name": "Открытая линия", "queueType": "all", "workTimeFrom": "8", "workTimeTo": "17", "crm": "Y", "crmCreate": "deal", "queueTime": "60", "noAnswerTime": "180", "workTimeEnable": "Y", "workTimeTimezone": "Europe/Kaliningrad", "welcomeMessage": "Y", "voteMessage": "Y", "queue": ["139", "131", "99"], "queueFull": { "99": { "ID": "59", "SORT": "2", "USER_ID": "99", "DEPARTMENT_ID": "0", "USER_NAME": "Иван Петров", "USER_WORK_POSITION": "Менеджер поддержки", "USER_AVATAR": "/upload/main/avatars/99.jpg", "USER_AVATAR_ID": "12345" }, "131": { "ID": "57", "SORT": "1", "USER_ID": "131", "DEPARTMENT_ID": "0", "USER_NAME": "Мария Смирнова", "USER_WORK_POSITION": "Старший оператор", "USER_AVATAR": "/upload/main/avatars/131.jpg", "USER_AVATAR_ID": "67890" } }, "queueUsersFields": { "99": { "USER_NAME": "Иван Петров", "USER_WORK_POSITION": "Менеджер поддержки", "USER_AVATAR": "/upload/main/avatars/99.jpg" }, "131": { "USER_NAME": "Мария Смирнова", "USER_WORK_POSITION": "Старший оператор", "USER_AVATAR": "/upload/main/avatars/131.jpg" } }, "queueOnline": "N", "dateCreate": {}, "dateModify": {} } } ``` ## Пример ответа при ошибке 404 — конфигурация не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "openlineConfig 99999 not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imopenlines` | | 404 | `ENTITY_NOT_FOUND` | Конфигурация с таким ID не найдена | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Поля очереди операторов доступны только здесь.** `queue`, `queueFull`, `queueUsersFields`, `queueOnline` приходят в ответе одиночного запроса и недоступны в [Списке](/docs/openlines/config/list) и [Поиске](/docs/openlines/config/search). Полный реестр всех 95 полей (все в camelCase, с `label` и `description`) и пустые `dateCreate`/`dateModify` — [Поля конфигурации](/docs/openlines/config/fields). ## Смотрите также - [Поля открытой линии](/docs/openlines/config/fields) - [Список конфигураций](/docs/openlines/config/list) - [Обновить конфигурацию](/docs/openlines/config/update) --- # Open Channels Config: List ## Список конфигураций открытых линий `GET /v1/openline-configs` Возвращает список конфигураций открытых линий с поддержкой фильтрации, сортировки и пагинации. ## Параметры | Параметр | Тип | По умолч. | Допустимые значения | Описание | |----------|-----|-----------|---------------------|---------| | `limit` | number | `50` | `1`–`200` | Количество записей на запрос | | `offset` | number | `0` | `0` и больше | Пропустить N записей | | `sort` | string | — | `id`, `name`, `active`, `queueType`, `workTimeFrom`, `workTimeTo` | Поле сортировки | | `order` | string | `asc` | `asc`, `desc` | Направление сортировки | | `filter` | object | — | ключи — те же 6 полей, что и в `sort`, значения — по типу поля | Фильтрация по полям схемы.
[Синтаксис фильтрации](/docs/filtering). Пример: `?filter[active]=false`, `?filter[queueType]=evenly` | ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/openline-configs?limit=10&sort=id&order=asc&filter[active]=true" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/openline-configs?limit=10&sort=id&order=asc&filter[active]=true" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openline-configs?limit=10&sort=id&order=asc&filter[active]=true', { headers: { 'X-Api-Key': 'YOUR_API_KEY', }, }) const { success, data, total, hasMore } = await res.json() console.log(`Получено ${data.length} конфигураций, всего в окне: ${total}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openline-configs?limit=10&sort=id&order=asc&filter[active]=true', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { success, data, total, hasMore } = await res.json() ``` ## Поля ответа Ответ содержит поля метаданных на верхнем уровне (не вложены в `meta`): | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив конфигураций (все поля — см. [Поля конфигурации](/docs/openlines/config/fields)) | | `total` | number | Количество записей в текущем окне (не общий счётчик портала) | | `limit` | number | Размер страницы | | `offset` | number | Смещение | | `hasMore` | boolean | Есть ли ещё записи за пределами `limit` | ## Пример ответа Показаны основные поля. Полный список: [Поля конфигурации](/docs/openlines/config/fields). ```json { "success": true, "data": [ { "id": 1, "active": true, "name": "Открытая линия", "queueType": "all", "workTimeFrom": "8", "workTimeTo": "17", "crm": "Y", "crmCreate": "deal", "queueTime": "60", "noAnswerTime": "180", "welcomeMessage": "Y", "workTimeEnable": "Y", "workTimeTimezone": "Europe/Kaliningrad", "dateCreate": {}, "dateModify": {} }, { "id": 3, "active": true, "name": "Wix", "queueType": "all", "workTimeFrom": "9", "workTimeTo": "18.30", "crm": "Y", "crmCreate": "deal", "queueTime": "60", "noAnswerTime": "180", "welcomeMessage": "Y", "workTimeEnable": "N", "workTimeTimezone": "Europe/Moscow", "dateCreate": {}, "dateModify": {} } ], "total": 7, "limit": 10, "offset": 0, "hasMore": false } ``` > В примере показаны 2 записи из 7 — остальные 5 опущены для краткости. Каждый элемент содержит ещё около 75 полей помимо показанных. Страница короче `limit`, поэтому `hasMore` равен `false`. ## Пример ответа при ошибке 400 — логический оператор `$or` / `$and` в фильтре (Битрикс24 не поддерживает OR/AND для этого метода): ```json { "success": false, "error": { "code": "INVALID_FILTER_OPERATOR", "message": "'$or' is not supported. OR/AND logic cannot be expressed in a single openline-configs filter. For same-field OR use { field: { $in: [v1, v2] } }. For cross-field OR run parallel requests. AND is the default — combine conditions as sibling keys in one filter object." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_FILTER_OPERATOR` | В фильтре передан логический оператор `$or` / `$and` / `$not` / `LOGIC`. Для OR по одному полю используйте `{ поле: { $in: [...] } }` | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imopenlines` | | 422 | `BITRIX_ERROR` | Передано имя поля, которого нет в схеме конфигураций: опечатка, поле вне схемы вроде `createdAt` или поле, недоступное для фильтрации. Используйте 6 документированных camelCase-полей схемы | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **`total` — счётчик текущего окна, а не общий.** Битрикс24 не возвращает общее количество конфигураций для метода списка, поэтому `total` содержит число записей только в текущей странице. Для проверки наличия следующей страницы используйте поле `hasMore`. **`hasMore` — признак следующей страницы, и только он.** Обход страниц ведите по нему, а не по арифметике с `total`. При `limit` от 1 до 199 признак точный. При `limit=200` (потолок) он означает «страница заполнена целиком», поэтому за последней полной страницей может последовать один пустой ответ — это нормальное завершение обхода, а не ошибка. **Нецелый или слишком маленький `limit` заменяется значением по умолчанию.** Размер страницы — целое число от 1 до 200. Значение меньше единицы (`0`, `0.5`, отрицательное) и нечисловое значение отбрасываются, применяется `50`. Дробное значение больше единицы округляется вниз: `2.7` даёт страницу в 2 записи. **Фильтрация и сортировка — 6 camelCase-полей схемы.** Параметры `filter` и `sort` работают по всем 6 документированным именам: `id`, `name`, `active`, `queueType`, `workTimeFrom`, `workTimeTo` (обёртка переводит их в реальные имена Битрикс24 на стороне запроса). **Другие поля тоже принимаются.** Если нужно отфильтровать или отсортировать по полю вне этих шести — например `crmCreate`, `languageId` — передайте его camelCase-имя из [Поля конфигурации](/docs/openlines/config/fields), это канонический регистр. Имена в UPPER_SNAKE_CASE также принимаются для обратной совместимости. Неизвестное поле возвращает `422 BITRIX_ERROR`. **OR/AND в фильтре не поддерживаются.** Операторы `$or` / `$and` / `$not` / `LOGIC` отклоняются с `400 INVALID_FILTER_OPERATOR` — выразить логику OR/AND в одном фильтре нельзя. Для OR по одному полю используйте `{ "id": { "$in": [1, 3] } }`, в строке запроса — `filter[id][$in]=1,3`. **Поля `queue`, `queueFull`, `queueUsersFields`, `queueOnline` в списке не возвращаются** — они доступны только в [Получить конфигурацию](/docs/openlines/config/get). **camelCase и пустые даты.** Каждая запись содержит ~91 поле, все в camelCase. `dateCreate` и `dateModify` приходят пустыми объектами `{}`. `/fields` описывает каждое поле с `label` и `description` — полный реестр и пояснения — [Поля конфигурации](/docs/openlines/config/fields). ## Смотрите также - [Получить конфигурацию](/docs/openlines/config/get) - [Создать конфигурацию](/docs/openlines/config/create) - [Поля конфигурации](/docs/openlines/config/fields) - [Синтаксис фильтрации](/docs/filtering) - [Entity API](/docs/entity-api) - [Лимиты и оптимизация](/docs/optimization) --- # Open Channels Config: Search ## Поиск конфигураций открытых линий `POST /v1/openline-configs/search` Возвращает список конфигураций открытых линий с фильтрацией, сортировкой и пагинацией. Параметры передаются в теле запроса — удобнее для сложных условий, чем query-строка. ## Поля запроса (body) | Параметр | Тип | По умолч. | Допустимые значения | Описание | |----------|-----|-----------|---------------------|---------| | `filter` | object | — | ключи — те же 6 полей, что и в `sort`, значения — по типу поля | Фильтрация по полям схемы. Доступные поля — [`GET /v1/openline-configs/fields`](/docs/openlines/config/fields).
Пример: `{"active": false}` | | `limit` | number | `50` | `1`–`200` | Количество записей на запрос | | `offset` | number | `0` | `0` и больше | Пропустить N записей | | `sort` | string | — | `id`, `name`, `active`, `queueType`, `workTimeFrom`, `workTimeTo` | Поле для сортировки | | `order` | string | `asc` | `asc`, `desc` | Направление сортировки | Пустое тело запроса возвращает все конфигурации — эквивалент `GET /v1/openline-configs` без параметров. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/openline-configs/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "active": true }, "limit": 3, "sort": "id", "order": "desc" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/openline-configs/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "filter": { "active": true }, "limit": 3, "sort": "id", "order": "desc" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openline-configs/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { active: true }, limit: 3, sort: 'id', order: 'desc', }), }) const { success, data, total } = await res.json() console.log('Найдено:', total, 'записей, возвращено:', data.length) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openline-configs/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ filter: { active: true }, limit: 3, sort: 'id', order: 'desc', }), }) const { success, data, total } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив конфигураций (все поля — см. [Поля конфигурации](/docs/openlines/config/fields)) | | `total` | number | Количество записей в текущей странице. Общего счётчика по всем конфигурациям портала этот метод не возвращает | | `limit` | number | Применённое ограничение на количество записей | | `offset` | number | Применённое смещение | | `hasMore` | boolean | Есть ли ещё записи за пределами `limit` | ## Пример ответа ```json { "success": true, "data": [ { "id": 21, "active": true, "name": "Открытая линия 12", "queueType": "all", "workTimeFrom": "9", "workTimeTo": "18.30", "crm": "Y", "crmCreate": "lead", "queueTime": "60", "noAnswerTime": "60", "welcomeMessage": "Y", "dateCreate": {}, "dateModify": {} } ], "total": 3, "limit": 3, "offset": 0, "hasMore": true } ``` Показаны основные поля. Каждый элемент массива содержит ~91 поле, все в camelCase. `/fields` описывает каждое с `label` и `description`. Полный список — [Поля конфигурации](/docs/openlines/config/fields). ## Пример ответа при ошибке 400 — логический оператор `$or` / `$and` в фильтре (для этого метода Битрикс24 их не поддерживает): ```json { "success": false, "error": { "code": "INVALID_FILTER_OPERATOR", "message": "'$or' is not supported. OR/AND logic cannot be expressed in a single openline-configs filter. For same-field OR use { field: { $in: [v1, v2] } }. For cross-field OR run parallel requests. AND is the default — combine conditions as sibling keys in one filter object." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_FILTER_OPERATOR` | В фильтре передан логический оператор `$or` / `$and` / `$not` / `LOGIC` | | 401 | `TOKEN_MISSING` | Не передан `X-Api-Key` | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imopenlines` | | 422 | `BITRIX_ERROR` | Имя поля отсутствует в схеме конфигураций: опечатка или поле, недоступное для фильтрации | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности **Пустое тело возвращает все записи** — эквивалент `GET /v1/openline-configs` без параметров. Остальные особенности — те же, что и у списка: `total` как счётчик текущей страницы, обход строго по `hasMore` (на потолке `limit=200` за последней полной страницей возможен один пустой ответ), нецелый и меньший единицы `limit` заменяется значением по умолчанию `50`, фильтр и сортировка по 6 camelCase-полям схемы плюс прочие camelCase-имена запасным путём, OR/AND через `$or`/`$and` не поддерживаются — используйте `$in`, полей очереди операторов в ответе нет. Подробности — [Известные особенности списка](/docs/openlines/config/list). ## Смотрите также - [Список конфигураций](/docs/openlines/config/list) - [Поля конфигурации](/docs/openlines/config/fields) - [Синтаксис фильтрации](/docs/filtering) --- # Open Channels Config: Update ## Обновить конфигурацию открытой линии `PATCH /v1/openline-configs/:id` Обновляет поля существующей конфигурации открытой линии. Передайте только изменяемые поля — остальные не затрагиваются. Полный список полей — [Поля конфигурации](/docs/openlines/config/fields). ## Параметры | Параметр | Тип | Обяз. | Описание | |----------|-----|:-----:|---------| | `id` (path) | number | да | Числовой идентификатор конфигурации | ## Поля запроса (body) Тело запроса не должно быть пустым — обязательно наличие хотя бы одного поля. Передайте только изменяемые поля. **Имена полей.** Все поля передавайте в camelCase — `name`, `active`, `queueType`, `queueTime`, `workTimeFrom` и другие. Это канонический регистр. Имена в UPPER_SNAKE_CASE также принимаются для обратной совместимости. **Булевы поля** (`active`, …) принимают `true` / `false` — значение приводится к `"Y"`/`"N"` автоматически. Например, `{ "active": false }` (или `{ "ACTIVE": false }`) выключит линию. | Поле | Тип | Описание | |------|-----|---------| | `name` | string | Название открытой линии | | `active` | boolean | Включена ли линия (`true` / `false`) | | `queueTime` | number | Время ожидания ответа оператора (секунды) | | `noAnswerTime` | number | Время до сработывания правила «Нет ответа» (секунды) | | `welcomeMessageText` | string | Текст приветственного сообщения | | `workTimeFrom` | string | Начало рабочего времени, например `"9"` или `"9.30"` | | `workTimeTo` | string | Конец рабочего времени, например `"18"` или `"17.30"` | | `workTimeTimezone` | string | Часовой пояс рабочего времени | Полный список доступных полей — [Поля конфигурации](/docs/openlines/config/fields). ## Примеры ### curl — личный ключ ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/openline-configs/29" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "queueTime": 120, "welcomeMessageText": "Здравствуйте! Чем можем помочь?" }' ``` ### curl — OAuth-приложение ```bash curl -X PATCH "https://vibecode.bitrix24.tech/v1/openline-configs/29" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "queueTime": 120, "welcomeMessageText": "Здравствуйте! Чем можем помочь?" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openline-configs/29', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ queueTime: 120, welcomeMessageText: 'Здравствуйте! Чем можем помочь?', }), }) const { success, data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openline-configs/29', { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ queueTime: 120, welcomeMessageText: 'Здравствуйте! Чем можем помочь?', }), }) const { success, data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|---------| | `success` | boolean | Всегда `true` при успехе | | `data` | object | Результат операции | | `data.id` | number | Идентификатор обновлённой конфигурации | | `data.updated` | boolean | `true` — обновление применено | | `meta.warnings` | string[] | Необязательное. Присутствует, если часть переданных полей не распознана — перечисляет ключи, которые Битрикс24 проигнорировал | ## Пример ответа ```json { "success": true, "data": { "id": 29, "updated": true } } ``` ## Пример ответа при ошибке 404 — конфигурация не найдена: ```json { "success": false, "error": { "code": "ENTITY_NOT_FOUND", "message": "openlineConfig 99999 not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|---------| | 400 | `INVALID_ID` | Параметр `id` не является положительным целым числом | | 400 | `VALIDATION_ERROR` | Тело запроса пустое — необходимо передать хотя бы одно поле | | 400 | `VALIDATION_ERROR` | В теле нет ни одного распознанного поля (все ключи неизвестны) — в сообщении перечислены нераспознанные поля | | 400 | `READONLY_FIELD` | В теле передано поле только для чтения (`id`, `queue`, `dateCreate` и другие) | | 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов | | 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `imopenlines` | | 404 | `ENTITY_NOT_FOUND` | Конфигурация с указанным `id` не существует | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности Ответ содержит только `id` и `data.updated: true` — полей конфигурации в ответе нет. Чтобы получить актуальные значения всех полей после обновления, выполните `GET /v1/openline-configs/:id`. **Нераспознанные поля.** Незнакомые ключи в теле запроса не сохраняются. Вайбкод сверяет тело с полной схемой полей ([Поля конфигурации](/docs/openlines/config/fields)) и реагирует так: - ни одно поле не распознано — запрос отклоняется с `400 VALIDATION_ERROR` до вызова Битрикс24, в сообщении перечислены нераспознанные поля. - распознано хотя бы одно поле, но часть ключей неизвестна — обновление применяется, а в ответе возвращается `meta.warnings` со списком проигнорированных ключей. - в теле передано поле только для чтения (`id`, `queue`, `dateCreate` и другие) — запрос отклоняется с `400 READONLY_FIELD`. ## Смотрите также - [Получить конфигурацию](/docs/openlines/config/get) - [Поля конфигурации](/docs/openlines/config/fields) - [Список конфигураций](/docs/openlines/config/list) - [Batch](/docs/batch) --- # Open Channels: Operators ## Операторы в реальном времени > **Метод выходит в обновлении `imopenlines 26.700.0` и доступен пока не на всех порталах Битрикс24.** Если обновление на ваш портал ещё не пришло, API вернёт `422 METHOD_NOT_YET_AVAILABLE` — это признак того, что метод на портале ещё не выпущен, а не ошибка интеграции. `GET /v1/openlines/operators` Список операторов линии с текущим статусом и нагрузкой — для виджетов мониторинга контакт-центра в реальном времени. Данные приходят почти в реальном времени: статус и счётчик активных сессий читаются раздельно, без единой транзакции. Для виджета опрашивайте метод не чаще одного раза в 30 секунд. ## Поля запроса (query) | Параметр | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `configId` | number | нет | Идентификатор линии. Источник: [`GET /v1/openline-configs`](/docs/openlines/config/list) | | `configIdList` | number[] | нет | Список линий. Форма — `configIdList=3,5` или `configIdList[]=3&configIdList[]=5` | | `userId` | number | нет | Идентификатор оператора. Источник: [`GET /v1/users`](/docs/entities/users) | | `userIdList` | number[] | нет | Список операторов, те же две формы | | `status` | string | нет | Статус: `online`, `offline` или `pause` | | `hasFreeSlots` | boolean | нет | Только операторы со свободными слотами. Принимает `true`/`false` и `Y`/`N` | | `limit` | number | нет | Размер страницы, 1..200 (по умолчанию 50) | | `offset` | number | нет | Смещение для пагинации (по умолчанию 0) | Списочные параметры принимают либо строку через запятую (`configIdList=3,5`), либо повторяющуюся скобочную форму (`configIdList[]=3&configIdList[]=5`). Голое повторение параметра без скобок (`configIdList=3&configIdList=5`) не поддерживается. ## Примеры ### curl — личный ключ ```bash curl "https://vibecode.bitrix24.tech/v1/openlines/operators?configId=3&status=online" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl "https://vibecode.bitrix24.tech/v1/openlines/operators?configId=3&status=online" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openlines/operators?configId=3&status=online', { headers: { 'X-Api-Key': 'YOUR_API_KEY' }, }) const { data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openlines/operators?configId=3&status=online', { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, }) const { data } = await res.json() ``` ## Поля ответа Ответ — `{ "success": true, "data": { "operators": [...], "hasNextPage": bool } }`. | Ключ | Описание | |---|---| | `operators` | Массив операторов | | `operators[].userId` | Идентификатор пользователя-оператора | | `operators[].configId` | Идентификатор линии | | `operators[].status` | Статус: `online` / `offline` / `pause` | | `operators[].activeSessions` | Количество активных (незакрытых) сессий прямо сейчас | | `operators[].maxChat` | Лимит чатов оператора (из настроек линии) | | `operators[].freeSlots` | Свободные слоты (`maxChat − activeSessions`) | | `operators[].lastActivityDate` | Дата последней активности оператора в линии | | `hasNextPage` | Есть ли следующая страница | ## Пример ответа ```json { "success": true, "data": { "operators": [ { "userId": 42, "configId": 3, "status": "online", "activeSessions": 2, "maxChat": 5, "freeSlots": 3, "lastActivityDate": "2026-06-15T15:01:00+03:00" }, { "userId": 51, "configId": 3, "status": "pause", "activeSessions": 0, "maxChat": 5, "freeSlots": 5, "lastActivityDate": "2026-06-15T14:20:00+03:00" } ], "hasNextPage": false } } ``` ## Пример ответа при ошибке `422` — недопустимое значение `status` (значение уходит в Битрикс24, тот отклоняет фильтр): ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "Недопустимое значение фильтра", "b24Code": "INVALID_FILTER" } } ``` ## Ошибки | HTTP | Код | Когда | |---|---|---| | 403 | `B24_TARIFF_RESTRICTION` | Тариф не включает статистику Открытых линий (`report_open_lines`) | | 400 | `INVALID_PARAMS` | Нечисловое значение в `limit`/`offset` или элементе списка | | 422 | `BITRIX_ERROR` (`error.b24Code: INVALID_FILTER`) | Недопустимое значение `status` | | 422 | `BITRIX_ERROR` (`error.b24Code: OFFSET_TOO_LARGE`) | `offset` превышает максимум при фильтре `status`/`hasFreeSlots` — сузьте фильтры | | 422 | `METHOD_NOT_YET_AVAILABLE` | Обновление `imopenlines 26.700.0` ещё не приехало на портал. Ответ содержит поле `error.release` со значением `imopenlines 26.700.0` | Полный список системных кодов — [Ошибки API](/docs/errors). ## Смотрите также - [Агрегаты по линии за период](/docs/openlines/stats) - [Статистика Открытых линий](/docs/openlines) --- # Open Channels: Ratings ## Оценки (CSAT) > **Метод выходит в обновлении `imopenlines 26.700.0` и доступен пока не на всех порталах Битрикс24.** Если обновление на ваш портал ещё не пришло, API вернёт `422 METHOD_NOT_YET_AVAILABLE` — это признак того, что метод на портале ещё не выпущен, а не ошибка интеграции. `POST /v1/openlines/ratings/search` Список сессий с выставленной клиентом оценкой (лайк/дизлайк) за период — для отчётов CSAT и выгрузки отзывов. Сессии без клиентской оценки в список не попадают. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `dateVoteFrom` | string | да | Начало периода оценки, ISO 8601. Период `dateVoteFrom`..`dateVoteTo` — не больше 1 года | | `dateVoteTo` | string | да | Конец периода оценки, ISO 8601 | | `configId` | number | нет | Идентификатор линии. Источник: [`GET /v1/openline-configs`](/docs/openlines/config/list) | | `configIdList` | number[] | нет | Список линий | | `operatorId` | number | нет | Идентификатор оператора. Источник: [`GET /v1/users`](/docs/entities/users) | | `operatorIdList` | number[] | нет | Список операторов | | `source` | string | нет | Код коннектора | | `sourceList` | string[] | нет | Список кодов коннекторов | | `vote` | string | нет | Клиентская оценка: `like` / `dislike`. Без параметра возвращаются все оценённые сессии | | `hasVoteHead` | boolean | нет | Есть ли оценка руководителя. Принимает `true`/`false` и `Y`/`N` | | `limit` | number | нет | Размер страницы, 1..200 (по умолчанию 50) | | `offset` | number | нет | Смещение для пагинации (по умолчанию 0) | Период `dateVoteFrom`/`dateVoteTo` обязателен — ограничение защищает от тяжёлых выборок по таблице сессий. Если на линии отключена клиентская оценка, метод вернёт пустой список (оценённых сессий на такой линии не появляется). ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/openlines/ratings/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "configId": 3, "vote": "like", "dateVoteFrom": "2026-06-01T00:00:00+03:00", "dateVoteTo": "2026-06-30T23:59:59+03:00" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/openlines/ratings/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "configId": 3, "vote": "like", "dateVoteFrom": "2026-06-01T00:00:00+03:00", "dateVoteTo": "2026-06-30T23:59:59+03:00" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openlines/ratings/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ configId: 3, vote: 'like', dateVoteFrom: '2026-06-01T00:00:00+03:00', dateVoteTo: '2026-06-30T23:59:59+03:00', }), }) const { data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openlines/ratings/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ configId: 3, vote: 'like', dateVoteFrom: '2026-06-01T00:00:00+03:00', dateVoteTo: '2026-06-30T23:59:59+03:00', }), }) const { data } = await res.json() ``` ## Поля ответа Ответ — `{ "success": true, "data": { "ratings": [...], "hasNextPage": bool } }`. | Ключ | Описание | |---|---| | `ratings[].sessionId` | Идентификатор сессии | | `ratings[].configId` | Идентификатор линии | | `ratings[].operatorId` | Идентификатор оператора | | `ratings[].source` | Код коннектора | | `ratings[].vote` | Клиентская оценка (`like` / `dislike`) | | `ratings[].voteHead` | Оценка руководителя, число 1..5 (`null`, если нет права) | | `ratings[].commentHead` | Комментарий руководителя (`null`, если нет права) | | `ratings[].dateVote` | Дата выставления оценки клиентом | | `ratings[].dateSessionClose` | Дата закрытия сессии | | `hasNextPage` | Есть ли следующая страница (поле конверта `data`, не элемента) | ## Пример ответа ```json { "success": true, "data": { "ratings": [ { "sessionId": 1024, "configId": 3, "operatorId": 42, "source": "livechat", "vote": "like", "voteHead": 5, "commentHead": "Отличная работа", "dateVote": "2026-06-15T14:53:00+03:00", "dateSessionClose": "2026-06-15T14:52:10+03:00" } ], "hasNextPage": false } } ``` ## Пример ответа при ошибке `400` — не передан период оценки: ```json { "success": false, "error": { "code": "MISSING_PARAMS", "message": "Required: dateVoteFrom, dateVoteTo (ISO 8601 strings)" } } ``` ## Ошибки | HTTP | Код | Когда | |---|---|---| | 403 | `B24_TARIFF_RESTRICTION` | Тариф не включает статистику Открытых линий (`report_open_lines`) | | 400 | `INVALID_JSON_BODY` | Тело запроса не разобралось как JSON. Проверка идёт до валидации полей, поэтому про отсутствующие параметры ответ ничего не говорит | | 400 | `MISSING_PARAMS` | Не переданы обязательные `dateVoteFrom`/`dateVoteTo` | | 422 | `BITRIX_ERROR` (`error.b24Code: INVALID_FILTER`) | Недопустимое значение `vote` или формат даты | | 422 | `BITRIX_ERROR` (`error.b24Code: PERIOD_TOO_LARGE`) | Период превышает 1 год | | 422 | `BITRIX_ERROR` (`error.b24Code: OFFSET_TOO_LARGE`) | `offset` превышает максимум — сузьте период | | 422 | `METHOD_NOT_YET_AVAILABLE` | Обновление `imopenlines 26.700.0` ещё не приехало на портал. Ответ содержит поле `error.release` со значением `imopenlines 26.700.0` | ## Пагинация без дрейфа страниц Метод листается через `offset`/`limit`. При постраничной выгрузке фиксируйте верхнюю границу периода — `dateVoteTo` равным моменту старта выгрузки, чтобы новые оценки не сдвигали страницы. Полный список системных кодов — [Ошибки API](/docs/errors). ## Смотрите также - [Список сессий](/docs/openlines/sessions) - [Агрегаты по линии за период](/docs/openlines/stats) - [Статистика Открытых линий](/docs/openlines) --- # Open Channels: Sessions ## Список сессий > **Метод выходит в обновлении `imopenlines 26.700.0` и доступен пока не на всех порталах Битрикс24.** Если обновление на ваш портал ещё не пришло, API вернёт `422 METHOD_NOT_YET_AVAILABLE` — это признак того, что метод на портале ещё не выпущен, а не ошибка интеграции. `POST /v1/openlines/sessions/search` Список сессий Открытых линий с фильтрами и пагинацией — основной метод для детализированных отчётов и выгрузки в внешние системы аналитики. Пустое тело `{}` вернёт первую страницу всех видимых сессий. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `configId` | number | нет | Идентификатор линии. Источник: [`GET /v1/openline-configs`](/docs/openlines/config/list) | | `configIdList` | number[] | нет | Список линий | | `operatorId` | number | нет | Идентификатор оператора. Источник: [`GET /v1/users`](/docs/entities/users) | | `operatorIdList` | number[] | нет | Список операторов | | `source` | string | нет | Код коннектора | | `sourceList` | string[] | нет | Список кодов коннекторов | | `status` | string | нет | Статус сессии: `new` / `answered` / `closed` / `spam` / `paused` | | `closeReason` | string | нет | Причина закрытия: `operator` / `auto` / `spam` / `client` / `replyLimit` | | `dateCreateFrom` | string | нет | Начало периода создания, ISO 8601. Период `dateCreateFrom`..`dateCreateTo` — не больше 1 года | | `dateCreateTo` | string | нет | Конец периода создания, ISO 8601 | | `dateCloseFrom` | string | нет | Начало периода закрытия, ISO 8601 | | `dateCloseTo` | string | нет | Конец периода закрытия, ISO 8601 | | `vote` | string | нет | Клиентская оценка: `like` / `dislike` / `none` / `any` | | `hasVoteHead` | boolean | нет | Есть ли оценка руководителя. Принимает `true`/`false` и `Y`/`N` | | `kpiFirstAnswer` | boolean | нет | Уложились ли в SLA первого ответа. Требует ограниченного периода (`dateCreateFrom`+`dateCreateTo` либо `dateCloseFrom`+`dateCloseTo`) | | `hasCrm` | boolean | нет | Есть ли привязка к CRM | | `waitAnswerFrom` | number | нет | Мин. время до первого ответа, секунды | | `waitAnswerTo` | number | нет | Макс. время до первого ответа, секунды | | `waitCloseFrom` | number | нет | Мин. время до закрытия, секунды | | `waitCloseTo` | number | нет | Макс. время до закрытия, секунды | | `order` | string | нет | Поле сортировки: `dateCreate` / `dateClose` / `waitAnswer` / `waitClose` (по умолчанию `dateCreate`) | | `orderDirection` | string | нет | Направление: `asc` / `desc` (по умолчанию `desc`) | | `limit` | number | нет | Размер страницы, 1..200 (по умолчанию 50) | | `offset` | number | нет | Смещение для пагинации (по умолчанию 0) | Фильтры `status` и `closeReason` взаимоисключающи: `closeReason` уже подразумевает закрытую сессию. Фильтр `hasVoteHead` применяется только к линиям, где у пользователя есть право на оценку руководителя. Фильтра по типу CRM-сущности нет — по CRM доступен только булев `hasCrm` (есть привязка или нет). Если нужен отбор по конкретному типу, фильтруйте на своей стороне по полям `crmEntityType` / `crmEntityId` из ответа. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/openlines/sessions/search" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "configId": 3, "status": "closed", "dateCreateFrom": "2026-06-01T00:00:00+03:00", "dateCreateTo": "2026-06-30T23:59:59+03:00", "limit": 50 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/openlines/sessions/search" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "configId": 3, "status": "closed", "dateCreateFrom": "2026-06-01T00:00:00+03:00", "dateCreateTo": "2026-06-30T23:59:59+03:00", "limit": 50 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openlines/sessions/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ configId: 3, status: 'closed', dateCreateFrom: '2026-06-01T00:00:00+03:00', dateCreateTo: '2026-06-30T23:59:59+03:00', limit: 50, }), }) const { data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openlines/sessions/search', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ configId: 3, status: 'closed', dateCreateFrom: '2026-06-01T00:00:00+03:00', dateCreateTo: '2026-06-30T23:59:59+03:00', limit: 50, }), }) const { data } = await res.json() ``` ## Поля ответа Ответ — `{ "success": true, "data": { "sessions": [...], "hasNextPage": bool } }`. | Ключ | Описание | |---|---| | `sessions[].id` | Идентификатор сессии | | `sessions[].configId` | Идентификатор линии | | `sessions[].source` | Код коннектора | | `sessions[].operatorId` | Идентификатор оператора, завершившего сессию | | `sessions[].userId` / `userCode` | Клиент: внутренний id и внешний код | | `sessions[].chatId` | Идентификатор IM-чата сессии | | `sessions[].dateCreate` / `dateClose` | Создание и закрытие сессии, ISO 8601 | | `sessions[].dateFirstAnswer` / `dateOperatorAnswer` | Дата первого ответа и дата, когда оператор начал работу с сессией — это разные моменты, ISO 8601 | | `sessions[].status` / `closeReason` | Статус и причина закрытия | | `sessions[].vote` | Клиентская оценка (`like` / `dislike` / `none`) | | `sessions[].voteHead` / `commentHead` | Оценка и комментарий руководителя (`null`, если нет права) | | `sessions[].crmEntityType` / `crmEntityId` | Привязка к CRM (`null`, если нет права чтения связанной сущности) | | `sessions[].queueTransfers` | Число переназначений в очереди | | `sessions[].waitAnswer` / `waitClose` | Время до первого ответа и до закрытия, секунды. Это самостоятельные хранимые метрики — не вычисляйте их из дат выше, значения могут не совпасть | | `sessions[].kpiFirstAnswer` | Уложились ли в SLA первого ответа | | `sessions[].messageCount` | Число сообщений в сессии | | `hasNextPage` | Есть ли следующая страница (поле конверта `data`, не элемента) | ## Пример ответа ```json { "success": true, "data": { "sessions": [ { "id": 1024, "configId": 3, "source": "livechat", "operatorId": 42, "userId": 501, "userCode": "site_visitor_88a1", "chatId": 2048, "dateCreate": "2026-06-15T14:30:00+03:00", "dateClose": "2026-06-15T14:52:10+03:00", "dateFirstAnswer": "2026-06-15T14:31:05+03:00", "dateOperatorAnswer": "2026-06-15T14:50:00+03:00", "status": "closed", "closeReason": "operator", "vote": "like", "voteHead": 5, "commentHead": "Отличная работа", "crmEntityType": "deal", "crmEntityId": 771, "queueTransfers": 1, "waitAnswer": 65, "waitClose": 1330, "kpiFirstAnswer": true, "messageCount": 14 } ], "hasNextPage": false } } ``` ## Пример ответа при ошибке `422` — период превышен: ```json { "success": false, "error": { "code": "BITRIX_ERROR", "message": "The requested period exceeds the maximum of 1 year", "b24Code": "PERIOD_TOO_LARGE" } } ``` ## Ошибки | HTTP | Код | Когда | |---|---|---| | 403 | `B24_TARIFF_RESTRICTION` | Тариф не включает статистику Открытых линий (`report_open_lines`) | | 400 | `INVALID_JSON_BODY` | Тело запроса не разобралось как JSON. Проверка идёт до валидации полей, поэтому про отсутствующие параметры ответ ничего не говорит | | 400 | `INVALID_PARAMS` | Тело запроса не объект | | 422 | `BITRIX_ERROR` (`error.b24Code: PERIOD_TOO_LARGE`) | Период создания/закрытия превышает 1 год | | 422 | `BITRIX_ERROR` (`error.b24Code: OFFSET_TOO_LARGE`) | `offset` превышает максимум — сузьте период или фильтры | | 422 | `BITRIX_ERROR` (`error.b24Code: INVALID_FILTER`) | Недопустимое значение фильтра, одновременно переданы `status` и `closeReason`, либо `kpiFirstAnswer` без ограниченного периода | | 422 | `METHOD_NOT_YET_AVAILABLE` | Обновление `imopenlines 26.700.0` ещё не приехало на портал. Ответ содержит поле `error.release` со значением `imopenlines 26.700.0` | ## Пагинация без дрейфа страниц Метод листается через `offset`/`limit`. При постраничной выгрузке фиксируйте верхнюю границу периода — `dateCreateTo` равным моменту старта выгрузки. Без фиксированной границы новые сессии, пришедшие во время листания, сдвигают страницы, и записи на стыках могут повториться или пропасть. Полный список системных кодов — [Ошибки API](/docs/errors). ## Смотрите также - [Метрики по сессиям](/docs/openlines/sessions/stats) - [История переназначений](/docs/openlines/sessions/transfers) - [Статистика Открытых линий](/docs/openlines) --- # Open Channels Sessions: Stats ## Метрики по сессиям > **Метод выходит в обновлении `imopenlines 26.700.0` и доступен пока не на всех порталах Битрикс24.** Если обновление на ваш портал ещё не пришло, API вернёт `422 METHOD_NOT_YET_AVAILABLE` — это признак того, что метод на портале ещё не выпущен, а не ошибка интеграции. `POST /v1/openlines/sessions/stats` Пакетные метрики по конкретным сессиям — время ответа и закрытия, счётчики сообщений, число переводов, оценка. До 100 идентификаторов за один вызов. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `sessionId` | number[] | да | Массив идентификаторов сессий, до 100 элементов. Источник: [`POST /v1/openlines/sessions/search`](/docs/openlines/sessions). Одиночное число тоже принимается и оборачивается в массив | Дубликаты в `sessionId` схлопываются: каждый уникальный идентификатор возвращается один раз. Несуществующий, чужой или недоступный `sessionId` не приводит к ошибке — для него возвращается объект с самим `sessionId` и `null` во всех метриках. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/openlines/sessions/stats" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "sessionId": [1024, 1025, 999999] }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/openlines/sessions/stats" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "sessionId": [1024, 1025, 999999] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openlines/sessions/stats', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ sessionId: [1024, 1025, 999999] }), }) const { data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openlines/sessions/stats', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ sessionId: [1024, 1025, 999999] }), }) const { data } = await res.json() ``` ## Поля ответа Ответ — `{ "success": true, "data": { "sessions": [...] } }`. По одному объекту на каждый уникальный запрошенный `sessionId`, в том числе недоступные (с `null`-полями). | Ключ | Описание | |---|---| | `sessionId` | Идентификатор сессии | | `waitAnswer` / `waitClose` | Время до первого ответа и до закрытия, секунды | | `messagesCount` | Число сообщений в сессии | | `messagesOperatorCount` / `messagesClientCount` | Сообщения оператора и клиента | | `transfersCount` | Число переназначений | | `kpiFirstAnswer` | Уложились ли в SLA первого ответа | | `vote` | Клиентская оценка | | `voteHead` | Оценка руководителя (`null`, если нет права) | ## Пример ответа Третья сессия недоступна или не существует — отдана объектом с `null`-полями: ```json { "success": true, "data": { "sessions": [ { "sessionId": 1024, "waitAnswer": 65, "waitClose": 1330, "messagesCount": 14, "messagesOperatorCount": 6, "messagesClientCount": 8, "transfersCount": 1, "kpiFirstAnswer": true, "vote": "like", "voteHead": 5 }, { "sessionId": 1025, "waitAnswer": 12, "waitClose": 340, "messagesCount": 5, "messagesOperatorCount": 2, "messagesClientCount": 3, "transfersCount": 0, "kpiFirstAnswer": true, "vote": "none", "voteHead": null }, { "sessionId": 999999, "waitAnswer": null, "waitClose": null, "messagesCount": null, "messagesOperatorCount": null, "messagesClientCount": null, "transfersCount": null, "kpiFirstAnswer": null, "vote": null, "voteHead": null } ] } } ``` ## Пример ответа при ошибке `400` — в батче больше 100 идентификаторов: ```json { "success": false, "error": { "code": "BATCH_LIMIT_EXCEEDED", "message": "sessionId batch must not exceed 100 unique ids" } } ``` ## Ошибки | HTTP | Код | Когда | |---|---|---| | 403 | `B24_TARIFF_RESTRICTION` | Тариф не включает статистику Открытых линий (`report_open_lines`) | | 400 | `INVALID_JSON_BODY` | Тело запроса не разобралось как JSON. Проверка идёт до валидации полей, поэтому про отсутствующие параметры ответ ничего не говорит | | 400 | `MISSING_PARAMS` | `sessionId` пустой массив или не передан | | 400 | `INVALID_PARAMS` | Нечисловой элемент в `sessionId` | | 400 | `BATCH_LIMIT_EXCEEDED` | Больше 100 уникальных идентификаторов (после схлопывания дублей) | | 422 | `METHOD_NOT_YET_AVAILABLE` | Обновление `imopenlines 26.700.0` ещё не приехало на портал. Ответ содержит поле `error.release` со значением `imopenlines 26.700.0` | Полный список системных кодов — [Ошибки API](/docs/errors). ## Смотрите также - [Список сессий](/docs/openlines/sessions) - [История переназначений](/docs/openlines/sessions/transfers) - [Статистика Открытых линий](/docs/openlines) --- # Open Channels Sessions: Transfers ## История переназначений > **Метод выходит в обновлении `imopenlines 26.700.0` и доступен пока не на всех порталах Битрикс24.** Если обновление на ваш портал ещё не пришло, API вернёт `422 METHOD_NOT_YET_AVAILABLE` — это признак того, что метод на портале ещё не выпущен, а не ошибка интеграции. `POST /v1/openlines/sessions/transfers` Хронологический список переназначений (переводов) по конкретным сессиям — от кого к кому, между какими линиями, по какой причине. До 50 идентификаторов за один вызов. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `sessionId` | number[] | да | Массив идентификаторов сессий, до 50 элементов. Источник: [`POST /v1/openlines/sessions/search`](/docs/openlines/sessions). Одиночное число тоже принимается и оборачивается в массив | Дубликаты в `sessionId` схлопываются. Несуществующий, чужой или недоступный `sessionId` не приводит к ошибке — для него просто не будет записей в `transfers`. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/openlines/sessions/transfers" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "sessionId": [1024, 1025] }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/openlines/sessions/transfers" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "sessionId": [1024, 1025] }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openlines/sessions/transfers', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ sessionId: [1024, 1025] }), }) const { data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openlines/sessions/transfers', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ sessionId: [1024, 1025] }), }) const { data } = await res.json() ``` ## Поля ответа Ответ — `{ "success": true, "data": { "transfers": [...] } }`. Переводы всех запрошенных сессий идут вперемешку, в хронологическом порядке (по `date` по возрастанию). Для группировки по сессиям используйте поле `transfers[].sessionId`. | Ключ | Описание | |---|---| | `sessionId` | Идентификатор сессии | | `date` | Дата и время переназначения | | `fromOperatorId` | Оператор, от которого ушло (`null`, если из очереди) | | `toOperatorId` | Оператор, которому пришло (`null`, если в очередь) | | `fromConfigId` | Линия-источник | | `toConfigId` | Линия-назначение (если перевод в другую линию) | | `reason` | Причина: `manual` / `auto` | | `mode` | Режим: `MANUAL` / `AUTO` | | `type` | Тип: `USER` / `QUEUE` | | `initiatorId` | Инициатор перевода (`null`, если автоматически) | ## Пример ответа Сессия 1024 — авто-распределение из очереди, затем ручной перевод оператору. Сессия 1025 — без переводов: ```json { "success": true, "data": { "transfers": [ { "sessionId": 1024, "date": "2026-06-15T14:30:05+03:00", "fromOperatorId": null, "toOperatorId": 42, "fromConfigId": 3, "toConfigId": null, "reason": "auto", "mode": "AUTO", "type": "USER", "initiatorId": null }, { "sessionId": 1024, "date": "2026-06-15T14:40:00+03:00", "fromOperatorId": 42, "toOperatorId": 51, "fromConfigId": 3, "toConfigId": null, "reason": "manual", "mode": "MANUAL", "type": "USER", "initiatorId": 42 } ] } } ``` ## Пример ответа при ошибке `400` — в батче больше 50 идентификаторов: ```json { "success": false, "error": { "code": "BATCH_LIMIT_EXCEEDED", "message": "sessionId batch must not exceed 50 unique ids" } } ``` ## Ошибки | HTTP | Код | Когда | |---|---|---| | 403 | `B24_TARIFF_RESTRICTION` | Тариф не включает статистику Открытых линий (`report_open_lines`) | | 400 | `INVALID_JSON_BODY` | Тело запроса не разобралось как JSON. Проверка идёт до валидации полей, поэтому про отсутствующие параметры ответ ничего не говорит | | 400 | `MISSING_PARAMS` | `sessionId` пустой массив или не передан | | 400 | `INVALID_PARAMS` | Нечисловой элемент в `sessionId` | | 400 | `BATCH_LIMIT_EXCEEDED` | Больше 50 уникальных идентификаторов (после схлопывания дублей) | | 422 | `METHOD_NOT_YET_AVAILABLE` | Обновление `imopenlines 26.700.0` ещё не приехало на портал. Ответ содержит поле `error.release` со значением `imopenlines 26.700.0` | Полный список системных кодов — [Ошибки API](/docs/errors). ## Смотрите также - [Метрики по сессиям](/docs/openlines/sessions/stats) - [Список сессий](/docs/openlines/sessions) - [Статистика Открытых линий](/docs/openlines) --- # Open Channels: Stats ## Агрегаты по линии за период > **Метод выходит в обновлении `imopenlines 26.700.0` и доступен пока не на всех порталах Битрикс24.** Если обновление на ваш портал ещё не пришло, API вернёт `422 METHOD_NOT_YET_AVAILABLE` — это признак того, что метод на портале ещё не выпущен, а не ошибка интеграции. `POST /v1/openlines/stats` Сводные показатели Открытых линий за период — счётчики сессий, средние времена, CSAT и разбивки по каналам, часам и операторам. Основной метод для верхнеуровневых виджетов дашборда. Тяжёлый: запрашивайте не чаще одного раза в 30–60 секунд и кэшируйте результат. ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|---------| | `dateFrom` | string | да | Начало периода, ISO 8601. Период `dateFrom`..`dateTo` — не больше 1 года | | `dateTo` | string | да | Конец периода, ISO 8601 | | `configId` | number | нет | Идентификатор линии. Источник: [`GET /v1/openline-configs`](/docs/openlines/config/list) | | `configIdList` | number[] | нет | Список идентификаторов линий | | `source` | string | нет | Код коннектора, например `livechat` | | `sourceList` | string[] | нет | Список кодов коннекторов | | `operatorId` | number | нет | Идентификатор оператора. Источник: [`GET /v1/users`](/docs/entities/users) | | `operatorIdList` | number[] | нет | Список идентификаторов операторов | Если не задан ни один из `configId*`/`source*`/`operatorId*`, агрегаты считаются по всем линиям, доступным текущему пользователю. ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/openlines/stats" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "dateFrom": "2026-06-01T00:00:00+03:00", "dateTo": "2026-06-30T23:59:59+03:00", "configId": 3 }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/openlines/stats" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "dateFrom": "2026-06-01T00:00:00+03:00", "dateTo": "2026-06-30T23:59:59+03:00", "configId": 3 }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openlines/stats', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ dateFrom: '2026-06-01T00:00:00+03:00', dateTo: '2026-06-30T23:59:59+03:00', configId: 3, }), }) const { data } = await res.json() ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch('https://vibecode.bitrix24.tech/v1/openlines/stats', { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ dateFrom: '2026-06-01T00:00:00+03:00', dateTo: '2026-06-30T23:59:59+03:00', configId: 3, }), }) const { data } = await res.json() ``` ## Поля ответа Ответ — `{ "success": true, "data": {...} }`. Все числовые метрики при отсутствии данных за период возвращаются как `0` (или `0.0`), никогда как `null`. | Ключ | Описание | |---|---| | `totalSessions` / `closedSessions` / `spamSessions` | Счётчики сессий за период | | `avgWaitAnswer` / `avgSessionDuration` | Средние показатели, секунды | | `likeCount` / `dislikeCount` / `votedSessions` / `positiveRate` | CSAT: клиентская оценка — лайк/дизлайк, `positiveRate` — доля лайков | | `kpiFirstAnswerOk` / `kpiFirstAnswerFail` | Счётчики по SLA первого ответа | | `sessionsBySource` | Разбивка по каналам, `[{ source, count }]` | | `sessionsByHour` | Ровно 24 записи (часы 0–23, часовой пояс сервера портала) | | `sessionsByOperator` | Разбивка по операторам, `[{ operatorId, count, avgWaitAnswer, positiveRate }]` | ## Пример ответа ```json { "success": true, "data": { "totalSessions": 340, "closedSessions": 318, "spamSessions": 4, "avgWaitAnswer": 42.7, "avgSessionDuration": 612.3, "likeCount": 210, "dislikeCount": 15, "votedSessions": 225, "positiveRate": 0.9333, "kpiFirstAnswerOk": 300, "kpiFirstAnswerFail": 18, "sessionsBySource": [ { "source": "livechat", "count": 200 }, { "source": "whatsapp", "count": 140 } ], "sessionsByHour": [0,0,0,0,0,0,2,10,25,40,38,30,28,22,20,25,30,20,15,10,8,5,3,1], "sessionsByOperator": [ { "operatorId": 42, "count": 120, "avgWaitAnswer": 38.1, "positiveRate": 0.95 }, { "operatorId": 51, "count": 90, "avgWaitAnswer": 51.4, "positiveRate": 0.88 } ] } } ``` ## Пример ответа при ошибке `400` — не передан период: ```json { "success": false, "error": { "code": "MISSING_PARAMS", "message": "Required: dateFrom, dateTo (ISO 8601 strings)" } } ``` ## Ошибки | HTTP | Код | Когда | |---|---|---| | 403 | `B24_TARIFF_RESTRICTION` | Тариф не включает статистику Открытых линий (`report_open_lines`) | | 400 | `INVALID_JSON_BODY` | Тело запроса не разобралось как JSON. Проверка идёт до валидации полей, поэтому про отсутствующие параметры ответ ничего не говорит | | 400 | `MISSING_PARAMS` | Не передан `dateFrom` и/или `dateTo` | | 422 | `BITRIX_ERROR` (`error.b24Code: PERIOD_REQUIRED`) | Период не распознан Битрикс24 | | 422 | `BITRIX_ERROR` (`error.b24Code: INVALID_FILTER`) | Недопустимое значение фильтра или формат даты | | 422 | `BITRIX_ERROR` (`error.b24Code: PERIOD_TOO_LARGE`) | Период превышает 1 год | | 422 | `METHOD_NOT_YET_AVAILABLE` | Обновление `imopenlines 26.700.0` ещё не приехало на портал. Ответ содержит поле `error.release` со значением `imopenlines 26.700.0` | Полный список системных кодов — [Ошибки API](/docs/errors). ## Смотрите также - [Операторы в реальном времени](/docs/openlines/operators) - [Список сессий](/docs/openlines/sessions) - [Статистика Открытых линий](/docs/openlines) --- # Infrastructure: Access # Доступ и режимы Управление видимостью приложения и режимом сервера. Политика доступа (`accessPolicy`) определяет, кто из Битрикс24 может открыть HTTPS-субдомен приложения: только владелец, список конкретных пользователей и отделов, все пользователи портала или вообще любой посетитель. Режим сервера (`mode`) переключает между Black Hole (всё закрыто фаерволом) и OPEN (прямой доступ по IP). > **Смена `accessPolicy` с `OWNER_ONLY` на более открытую напрямую влияет на безопасность.** Никогда не делайте её от имени пользователя без явного подтверждения — это открывает приложение другим людям портала или всему интернету. Скоуп: `vibe:infra` ## Операции - [SSH-данные](./access/ssh.md) — `GET /v1/infra/servers/:id/ssh` - [Переключить режим](./access/mode.md) — `PATCH /v1/infra/servers/:id/mode` - [Политика доступа](./access/access-policy.md) — `PATCH /v1/infra/servers/:id/access-policy` - [Список доступа](./access/access-list.md) — `GET /v1/infra/servers/:id/access` - [Добавить пользователя/отдел](./access/access-add.md) — `POST /v1/infra/servers/:id/access` - [Удалить запись доступа](./access/access-delete.md) — `DELETE /v1/infra/servers/:id/access/:accessId` - [Поиск пользователей Битрикс24](./access/b24-users.md) — `GET /v1/infra/servers/:id/b24-users` ## Политики доступа (от самой закрытой к самой открытой) | Политика | Кто видит HTTPS-субдомен | |----------|--------------------------| | `OWNER_ONLY` | Только владелец API-ключа (по умолчанию) | | `NAMED_USERS` | Пользователи из списка доступа | | `DEPARTMENT` | Отделы Битрикс24 из списка доступа | | `PORTAL` | Все пользователи портала Битрикс24 | | `AUTHENTICATED` | Все авторизованные пользователи (включая не-членов портала) | | `PUBLIC` | Все, без авторизации | ## Типовой сценарий (NAMED_USERS) Открыть приложение для конкретных сотрудников Битрикс24: 1. Найти пользователей: [`GET /b24-users?search=Иван`](./access/b24-users.md). 2. Переключить политику: [`PATCH /access-policy`](./access/access-policy.md) `{ accessPolicy: "NAMED_USERS" }`. 3. Добавить пользователя: [`POST /access`](./access/access-add.md) `{ type: "user", userId: "243", userName: "Катя Иванова" }`. 4. Проверить список: [`GET /access`](./access/access-list.md). 5. Позже — удалить запись: [`DELETE /access/:accessId`](./access/access-delete.md). ## Сценарий «вернуть приватность» 1. Перевести политику обратно в `OWNER_ONLY`: [`PATCH /access-policy`](./access/access-policy.md) `{ accessPolicy: "OWNER_ONLY" }`. Записи пользователей и отделов остаются в базе, но больше не применяются. 2. При необходимости очистить историю — удалить все записи через [`DELETE /access/:accessId`](./access/access-delete.md). ## Смотрите также - [Жизненный цикл](/docs/infra/lifecycle) - [Корневой раздел — Инфраструктура](/docs/infra) --- # Infrastructure: Access Tokens # Токены доступа Краткосрочные токены для внешнего доступа к развёрнутому приложению на BLACKHOLE-сервере. Два режима: `api-bearer` — JWT для HTTP-заголовка `Authorization`, `share-url` — ссылка для передачи получателю, аутентификация по куки. Скоуп: `vibe:infra` ## Операции - [Выпустить токен](./access-tokens/create.md) — `POST /v1/infra/servers/:id/access-tokens` - [Обновить токен](./access-tokens/refresh.md) — `POST /v1/infra/servers/:id/access-tokens/:tokenId/refresh` - [Список токенов](./access-tokens/list.md) — `GET /v1/infra/servers/:id/access-tokens` - [Отозвать токен](./access-tokens/delete.md) — `DELETE /v1/infra/servers/:id/access-tokens/:tokenId` ## Доступность Раздел включается на стороне платформы, и на портале он может быть выключен. Признак до вызова — поле `available` блока `data.capabilities.servers.preview` в ответе [`GET /v1/me`](/docs/keys-auth/me): | `available` | Что это означает | |-------------|------------------| | `true` | Все четыре эндпоинта раздела работают | | `false`, рядом приходит `reason: "FEATURE_DISABLED"` | Токены доступа этому ключу недоступны. Когда раздел выключен на платформе, каждый из четырёх эндпоинтов отвечает `503 FEATURE_DISABLED` | Тот же признак приходит в блоке `data.infra.preview` — он есть в ответе и тогда, когда блока `data.capabilities` нет, потому что ключ не привязан к порталу. В блоке `data.deployment` у ключей Cowork поля `preview` нет вовсе, опираться на него как на единственный признак не стоит. Раздел включает администратор платформы, вызовом API это не делается. Когда раздел выключен, ближайшая доступная проверка деплоя — шаги в массиве `data.steps[]` ответа [`POST /v1/infra/servers/:id/deploy`](/docs/infra/deploy/deploy), у каждого шага есть поле `status` со значениями `ok`, `warning` и `error`. Шаг `healthcheck` подтверждает, что приложение отвечает на своём порту. Шаг `tunnel_routing` подтверждает, что туннель Gateway ведёт на этот порт — у galaxy-приложения такого шага нет. Публичный маршрут с авторизацией на входе оба шага не проверяют, это остаётся свойством режима `api-bearer`. ## Сценарии **E2E-проверка деплоя через публичный путь:** Режим `api-bearer` позволяет убедиться, что запросы проходят через реальный маршрут `nginx → Gateway → туннель → приложение`. Вызов `exec + curl 127.0.0.1:3000` проверяет только localhost и не затрагивает Gateway-слой. 1. [`POST /access-tokens`](./access-tokens/create.md) с `mode: "api-bearer"`, `ttlSeconds: 600`. 2. Прогнать ключевые эндпоинты приложения с заголовком `Authorization: Bearer `. 3. Если проверка идёт дольше 10 минут — [`POST /access-tokens/:tokenId/refresh`](./access-tokens/refresh.md) выдаёт свежий JWT для той же записи. 4. [`DELETE /access-tokens/:tokenId`](./access-tokens/delete.md) — отозвать после проверки. Если Bearer возвращает 502, а `exec + curl 127.0.0.1:3000` проходит — проблема в Gateway или туннеле, а не в приложении. `api-bearer` подтверждает, что запрос сделан владельцем ключа, но не создаёт сессию пользователя Битрикс24 — маршрут приложения, которому нужен проверенный администратор через `X-Vibe-Authorization` и `GET /v1/me`, под ним получит `currentUser: null`. Подробнее — [Выпустить токен](./access-tokens/create.md) и [Что приходит в приложение](/docs/infra/app-runtime). **Ссылка для внешнего просмотра:** 1. [`POST /access-tokens`](./access-tokens/create.md) с `mode: "share-url"` и нужным `ttlSeconds`. 2. Передать поле `url` из ответа получателю — первый переход устанавливает куки, дальнейшие запросы работают без параметра `?s=`. 3. При необходимости: [`DELETE /access-tokens/:tokenId`](./access-tokens/delete.md) для досрочного отзыва. ## Смотрите также - [Deploy API](/docs/infra/deploy) - [Доступ и режимы](/docs/infra/access) - [Инфраструктура](/docs/infra) --- # Infrastructure Access Tokens: Create ## Выпустить токен доступа `POST /v1/infra/servers/:id/access-tokens` Выпускает краткосрочный токен для внешнего доступа к развёрнутому приложению. Два режима: `api-bearer` — JWT для HTTP-заголовка `Authorization`. `share-url` — ссылка, при переходе по которой устанавливается куки. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | string (UUID) | да | ID BLACKHOLE-сервера. Список: [`GET /v1/infra/servers`](/docs/infra/servers/list) | ## Поля запроса (body) | Поле | Тип | Обяз. | По умолч. | Описание | |------|-----|:-----:|-----------|----------| | `mode` | string | да | — | `"api-bearer"` или `"share-url"` | | `ttlSeconds` | number | нет | `86400` | Время жизни токена в секундах. Диапазон: 300–315 360 000 (от 5 минут до 10 лет). Значение 315 360 000 отображается в интерфейсе как «Бессрочно» | | `identityBound` | boolean | нет | `true` | Только для `share-url`. При `true` — потребует входа через Битрикс24, и в журнале окажется реальный идентификатор пользователя. При `false` — анонимный переход, синтетический идентификатор | | `name` | string | нет | — | Метка токена для отображения в списке (до 100 символов) | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/access-tokens" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "mode": "api-bearer", "ttlSeconds": 600, "name": "ci-smoke" }' ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/access-tokens" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "mode": "share-url", "ttlSeconds": 2592000, "identityBound": false, "name": "предпросмотр" }' ``` ### JavaScript — личный ключ ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/access-tokens`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ mode: 'api-bearer', ttlSeconds: 600 }), } ) const { data } = await res.json() // E2E-проверка через публичный путь const check = await fetch(`${data.appUrl}/api/health`, { headers: { Authorization: `Bearer ${data.token}` }, }) console.log(check.status) // 200 — приложение отвечает через Gateway ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/access-tokens`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ mode: 'share-url', ttlSeconds: 2592000, name: 'предпросмотр', }), } ) const { data } = await res.json() console.log(data.url) // https://app-xxxx.vibecode.bitrix24.tech/?s=R8k3Zm2P ``` ## Поля ответа Набор полей зависит от режима. **Режим `api-bearer`:** | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | string | ID токена для последующего отзыва | | `data.mode` | string | `"api-bearer"` | | `data.token` | string | JWT для заголовка `Authorization: Bearer`. Сохраните его сразу: повторно эта же строка не отдаётся, свежий JWT для той же записи выдаёт [обновление токена](./refresh.md) | | `data.expiresAt` | string (ISO 8601) | Срок хранения записи токена — для листинга и отзыва | | `data.jwtExpiresAt` | string (ISO 8601) | Реальный срок действия Bearer-токена. Ограничен 10 минутами независимо от `ttlSeconds`. После истечения выпустите новый токен | | `data.note` | string | Пояснение о разнице между `expiresAt` и `jwtExpiresAt` | | `data.subdomain` | string | Субдомен сервера | | `data.appUrl` | string | Полный HTTPS-адрес приложения | | `data.curlExample` | string | Готовый `curl`-пример с токеном для быстрой проверки | **Режим `share-url`:** | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | string | ID токена для последующего отзыва | | `data.mode` | string | `"share-url"` | | `data.shortcode` | string | Код, вставляемый в URL как `?s=` | | `data.url` | string | Полная распространяемая ссылка | | `data.identityBound` | boolean | Требует ли переход входа через Битрикс24 | | `data.expiresAt` | string (ISO 8601) | Момент истечения токена | | `data.name` | string \| null | Метка, переданная при выпуске | ## Пример ответа **Режим `api-bearer`:** ```json { "success": true, "data": { "id": "9f1c4b7e-3d52-4a18-9c0e-7b2a1f6d84c3", "mode": "api-bearer", "token": "eyJhbGciOiJFUzI1NiJ9...", "expiresAt": "2026-05-18T10:50:00.000Z", "jwtExpiresAt": "2026-05-18T10:40:10.000Z", "subdomain": "app-91306a4c", "appUrl": "https://app-91306a4c.vibecode.bitrix24.tech", "curlExample": "curl -H \"Authorization: Bearer eyJhbGciOiJFUzI1NiJ9...\" https://app-91306a4c.vibecode.bitrix24.tech/api/health", "note": "JWT is a 10-minute Gateway session token. The row's `expiresAt` is the long-lived TTL for listing/revoking, but the Bearer token itself stops working at `jwtExpiresAt`. To keep a long-running client authenticated, POST /v1/infra/servers/:id/access-tokens/:tokenId/refresh before jwtExpiresAt to re-mint a fresh JWT for the SAME token (no new row — does not consume the active-token cap or mint rate-limit), or use mode=share-url for browser links that auto-refresh on each visit." } } ``` **Режим `share-url`:** ```json { "success": true, "data": { "id": "2a7d5e61-84bc-4f39-b0d7-5e6c9a3f1b28", "mode": "share-url", "shortcode": "R8k3Zm2P", "url": "https://app-91306a4c.vibecode.bitrix24.tech/?s=R8k3Zm2P", "identityBound": false, "expiresAt": "2026-06-17T08:44:00.000Z", "name": "предпросмотр" } } ``` ## Пример ответа при ошибке 429 — превышен лимит выпуска токенов: ```json { "success": false, "error": { "code": "TOKEN_MINT_RATE_LIMIT", "message": "Rate limit: 50 mints/hour per API key" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_MODE` | Передан недопустимый `mode` либо неверный тип значения в теле запроса | | 400 | `UNKNOWN_PARAM` | В теле запроса есть неизвестное поле. Ответ содержит `details` со списком допустимых полей и подсказкой | | 400 | `INVALID_TTL` | `ttlSeconds` вне допустимого диапазона [300, 315 360 000] | | 400 | `NAME_TOO_LONG` | `name` превышает 100 символов | | 400 | `SERVER_NO_SUBDOMAIN` | У сервера нет субдомена, обращаться не к чему | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ | | 403 | `TOKEN_OWNER_MISMATCH` | Сервер принадлежит другому API-ключу | | 403 | `AGENT_OWNER_ONLY` | Сервер создан под AI-агента — токены доступа для него отключены | | 404 | `SERVER_NOT_FOUND` | Сервер не найден или удалён | | 409 | `ACTIVE_TOKEN_LIMIT` | Достигнут лимит 100 активных токенов на сервер | | 429 | `TOKEN_MINT_RATE_LIMIT` | Превышен лимит 50 выпусков в час на API-ключ. Заголовок `Retry-After: 3600` | | 503 | `FEATURE_DISABLED` | Раздел токенов доступа выключен на платформе. Признак до вызова и запасной путь — [Доступность](/docs/infra/access-tokens#доступность) | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Продление доступа дешевле повторного выпуска.** [Обновление токена](./refresh.md) выдаёт свежий JWT для той же записи и не расходует ни лимит активных токенов, ни лимит выпусков в час. - **У `api-bearer` идентификатор в журнале всегда один.** Это UUID владельца API-ключа, поле `identityBound` на него не влияет и в ответе списка приходит как `true`. - **`api-bearer` подтверждает, что запрос сделан владельцем ключа, но не создаёт сессию пользователя Битрикс24.** Токен аутентифицирует запрос как владельца API-ключа и открывает доступ к приложению по его политике доступа. Он не подставляет заголовок `X-Vibe-Authorization` и не даёт `currentUser` в ответе `GET /v1/me`. Поэтому маршрут приложения, который проверяет администратора Битрикс24 через `X-Vibe-Authorization` и `GET /v1/me`, под `api-bearer`-токеном получит `currentUser: null`. Такому маршруту нужна полноценная авторизация пользователя через OAuth-приложение (`placement`) — см. [Что приходит в приложение](/docs/infra/app-runtime). ## Смотрите также - [Обновить токен](./refresh.md) - [Список токенов](./list.md) - [Отозвать токен](./delete.md) - [Токены доступа](/docs/infra/access-tokens) - [Deploy API](/docs/infra/deploy) --- # Infrastructure Access Tokens: Delete ## Отозвать токен `DELETE /v1/infra/servers/:id/access-tokens/:tokenId` Отзывает токен досрочно. Новые переходы по `share-url` и вызовы с `api-bearer` блокируются немедленно. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | string (UUID) | да | ID BLACKHOLE-сервера. Список: [`GET /v1/infra/servers`](/docs/infra/servers/list) | | `tokenId` | path | string (UUID) | да | ID токена из [`POST /access-tokens`](./create.md) или [`GET /access-tokens`](./list.md) | ## Примеры ### curl — личный ключ ```bash curl -X DELETE \ -H "X-Api-Key: YOUR_API_KEY" \ "https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/access-tokens/TOKEN_ID" ``` ### curl — OAuth-приложение ```bash curl -X DELETE \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ "https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/access-tokens/TOKEN_ID" ``` ### JavaScript — личный ключ ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/access-tokens/${tokenId}`, { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, } ) // 204 No Content — тело ответа отсутствует if (res.status !== 204) { const { error } = await res.json() throw new Error(error.code) } ``` ### JavaScript — OAuth-приложение ```javascript await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/access-tokens/${tokenId}`, { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, } ) ``` ## Ответ `204 No Content` — тело ответа отсутствует. Признак успеха — код ответа, не содержимое. ## Пример ответа ``` HTTP/1.1 204 No Content ``` ## Пример ответа при ошибке 410 — токен уже отозван: ```json { "success": false, "error": { "code": "ALREADY_REVOKED", "message": "Token already revoked" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ | | 403 | `TOKEN_OWNER_MISMATCH` | Сервер принадлежит другому API-ключу | | 404 | `SERVER_NOT_FOUND` | Сервер не найден или удалён | | 404 | `NOT_FOUND` | Токен с таким ID не найден или принадлежит другому серверу | | 410 | `ALREADY_REVOKED` | Токен уже отозван | | 503 | `FEATURE_DISABLED` | Раздел токенов доступа выключен на платформе. Признак до вызова и запасной путь — [Доступность](/docs/infra/access-tokens#доступность) | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Куки `share-url` продолжают работать до 10 минут после отзыва.** Отзыв немедленно блокирует новые переходы, но браузер с уже установленными куки видит приложение до истечения сессионного JWT. - **Истёкший токен отзывается штатно.** Отзыв смотрит только на признак отзыва, поэтому запись с истёкшим `expiresAt` принимает `DELETE` и отвечает `204`. Обновление такой записи, наоборот, отвечает `410 TOKEN_EXPIRED` — [Обновить токен](./refresh.md). ## Смотрите также - [Выпустить токен](./create.md) - [Список токенов](./list.md) - [Токены доступа](/docs/infra/access-tokens) --- # Infrastructure Access Tokens: List ## Список токенов сервера `GET /v1/infra/servers/:id/access-tokens` Возвращает токены сервера с фильтрацией по статусу. По умолчанию — только активные. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | string (UUID) | да | ID BLACKHOLE-сервера. Список: [`GET /v1/infra/servers`](/docs/infra/servers/list) | | `status` | query | string | нет | Фильтр: `active` (по умолч.) \| `expired` \| `revoked` \| `all`. Значение вне этого набора не отбрасывается — выборка ведёт себя как `all` | ## Примеры ### curl — личный ключ ```bash curl -H "X-Api-Key: YOUR_API_KEY" \ "https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/access-tokens?status=active" ``` ### curl — OAuth-приложение ```bash curl -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ "https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/access-tokens?status=all" ``` ### JavaScript — личный ключ ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/access-tokens?status=active`, { headers: { 'X-Api-Key': 'YOUR_API_KEY' } } ) const { data } = await res.json() console.log(`Активных токенов: ${data.tokens.length} / ${data.limits.activeCountMax}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/access-tokens`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, } ) const { data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data.tokens` | array | Массив токенов | | `data.tokens[].id` | string | ID токена | | `data.tokens[].mode` | string | `"api-bearer"` или `"share-url"` | | `data.tokens[].createdVia` | string | Откуда выпущен токен: `PLATFORM` — через API или интерфейс Вайбкод, `BITRIX24_PORTAL` — со стороны Битрикс24 при публикации ссылки на приложение | | `data.tokens[].name` | string \| null | Метка токена | | `data.tokens[].identityBound` | boolean | Для `api-bearer` всегда `true`, для `share-url` — требуется ли вход через Битрикс24 | | `data.tokens[].shortcode` | string \| null | Код ссылки для `share-url`, `null` для `api-bearer` | | `data.tokens[].expiresAt` | string (ISO 8601) | Момент истечения | | `data.tokens[].revokedAt` | string (ISO 8601) \| null | Момент отзыва, `null` если не отозван | | `data.tokens[].createdAt` | string (ISO 8601) | Момент выпуска | | `data.tokens[].lastUsedAt` | string (ISO 8601) \| null | Последнее использование | | `data.tokens[].sessionCount` | number | Число сессий, созданных через этот токен | | `data.tokens[].createdBy.id` | string | ID пользователя, выпустившего токен | | `data.tokens[].createdBy.name` | string | Имя пользователя | | `data.tokens[].createdBy.email` | string | Электронная почта пользователя | | `data.limits.activeCount` | number | Текущее число активных токенов сервера | | `data.limits.activeCountMax` | number | Лимит активных токенов на сервер (100) | | `data.limits.mintRateLimitPerHour` | number | Лимит выпусков в час на API-ключ (50) | | `data.limits.mintsLastHour` | number | Количество выпущенных токенов за последний час по данному API-ключу | ## Пример ответа ```json { "success": true, "data": { "tokens": [ { "id": "9f1c4b7e-3d52-4a18-9c0e-7b2a1f6d84c3", "mode": "api-bearer", "createdVia": "PLATFORM", "name": "ci-smoke", "identityBound": true, "shortcode": null, "expiresAt": "2026-05-18T10:50:00.000Z", "revokedAt": null, "createdAt": "2026-05-18T10:40:00.000Z", "lastUsedAt": "2026-05-18T10:41:30.000Z", "sessionCount": 1, "createdBy": { "id": "c4e8b1a7-6f30-4d92-8a15-3b7e0c2d94f6", "name": "Иван Петров", "email": "ivan@example.bitrix24.ru" } }, { "id": "2a7d5e61-84bc-4f39-b0d7-5e6c9a3f1b28", "mode": "share-url", "createdVia": "BITRIX24_PORTAL", "name": "предпросмотр", "identityBound": false, "shortcode": "R8k3Zm2P", "expiresAt": "2026-06-17T08:44:00.000Z", "revokedAt": null, "createdAt": "2026-05-18T08:44:00.000Z", "lastUsedAt": null, "sessionCount": 0, "createdBy": { "id": "c4e8b1a7-6f30-4d92-8a15-3b7e0c2d94f6", "name": "Иван Петров", "email": "ivan@example.bitrix24.ru" } } ], "limits": { "activeCount": 2, "activeCountMax": 100, "mintRateLimitPerHour": 50, "mintsLastHour": 1 } } } ``` ## Пример ответа при ошибке 404 — сервер не найден: ```json { "success": false, "error": { "code": "SERVER_NOT_FOUND", "message": "Server not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ | | 403 | `TOKEN_OWNER_MISMATCH` | Сервер принадлежит другому API-ключу | | 404 | `SERVER_NOT_FOUND` | Сервер не найден или удалён | | 503 | `FEATURE_DISABLED` | Раздел токенов доступа выключен на платформе. Признак до вызова и запасной путь — [Доступность](/docs/infra/access-tokens#доступность) | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Поле `token` (JWT) не включается в список.** JWT приходит только в ответе на [выпуск](./create.md) и на [обновление](./refresh.md) токена. - **`status=all` возвращает истёкшие и отозванные токены.** Статус токена определяется по полям `revokedAt` (не `null` → отозван) и `expiresAt` (меньше текущего времени → истёк). - **Список ограничен 500 токенами.** Фильтр `status` сужает выборку до нужной категории. ## Смотрите также - [Выпустить токен](./create.md) - [Отозвать токен](./delete.md) - [Токены доступа](/docs/infra/access-tokens) --- # Infrastructure Access Tokens: Refresh ## Обновить токен доступа `POST /v1/infra/servers/:id/access-tokens/:tokenId/refresh` Выпускает свежий JWT для уже существующего токена режима `api-bearer` — **без создания новой записи**. Долгоживущий клиент (CI, AI-агент) вызывает обновление перед истечением `jwtExpiresAt` вместо выпуска нового токена: обновление не расходует ни лимит активных токенов, ни лимит выпусков в час. Тело запроса не требуется. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | string (UUID) | да | ID BLACKHOLE-сервера. Список: [`GET /v1/infra/servers`](/docs/infra/servers/list) | | `tokenId` | path | string (UUID) | да | ID токена `api-bearer` — поле `data.id` из ответа на [выпуск](./create.md) или элемент [списка токенов](./list.md) | ## Примеры ### curl — личный ключ ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/access-tokens/TOKEN_ID/refresh" \ -H "X-Api-Key: YOUR_API_KEY" ``` ### curl — OAuth-приложение ```bash curl -X POST "https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/access-tokens/TOKEN_ID/refresh" \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" ``` ### JavaScript — личный ключ ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/access-tokens/${tokenId}/refresh`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, } ) const { data } = await res.json() console.log(data.token, data.jwtExpiresAt) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/access-tokens/${tokenId}/refresh`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, } ) const { data } = await res.json() ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data.id` | string | ID токена — **тот же**, что и при выпуске (новая запись не создаётся) | | `data.mode` | string | `"api-bearer"` | | `data.token` | string | Свежий JWT для заголовка `Authorization: Bearer` | | `data.expiresAt` | string (ISO 8601) | Срок хранения записи токена — не меняется при обновлении | | `data.jwtExpiresAt` | string (ISO 8601) | Реальный срок действия нового JWT. Ограничен 10 минутами (или `expiresAt` записи, если он ближе) | | `data.subdomain` | string | Субдомен сервера | | `data.appUrl` | string | Полный HTTPS-адрес приложения | | `data.curlExample` | string | Готовый `curl`-пример с новым токеном | | `data.note` | string | Пояснение о сроках действия и о повторном вызове | ## Пример ответа ```json { "success": true, "data": { "id": "9f1c4b7e-3d52-4a18-9c0e-7b2a1f6d84c3", "mode": "api-bearer", "token": "eyJhbGciOiJFUzI1NiJ9...", "expiresAt": "2026-06-25T10:50:00.000Z", "jwtExpiresAt": "2026-06-25T10:40:10.000Z", "subdomain": "app-91306a4c", "appUrl": "https://app-91306a4c.vibecode.bitrix24.tech", "curlExample": "curl -H \"Authorization: Bearer eyJhbGciOiJFUzI1NiJ9...\" https://app-91306a4c.vibecode.bitrix24.tech/api/health", "note": "Refreshed the Gateway session JWT for this api-bearer token (same token id, no new row). The JWT is valid for up to 10 minutes (or until the row's expiresAt, whichever is sooner). Call this endpoint again before jwtExpiresAt to keep a long-running client authenticated." } } ``` ## Пример ответа при ошибке 410 — срок хранения записи истёк: ```json { "success": false, "error": { "code": "TOKEN_EXPIRED", "message": "The long-lived token row has expired; mint a new token." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `WRONG_TOKEN_MODE` | Токен в режиме `share-url`. Обновление применимо только к `api-bearer`, ссылки `share-url` обновляются сами при переходе | | 400 | `SERVER_NO_SUBDOMAIN` | У сервера нет субдомена | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ | | 403 | `TOKEN_OWNER_MISMATCH` | Токен принадлежит другому ключу либо сервер больше не привязан к вашему ключу | | 404 | `NOT_FOUND` | Токен не найден на этом сервере | | 404 | `SERVER_NOT_FOUND` | Сервер не найден или удалён | | 410 | `ALREADY_REVOKED` | Токен отозван — выпустите новый | | 410 | `TOKEN_EXPIRED` | Срок хранения записи истёк — выпустите новый токен через `POST /access-tokens` | | 503 | `FEATURE_DISABLED` | Раздел токенов доступа выключен на платформе. Признак до вызова и запасной путь — [Доступность](/docs/infra/access-tokens#доступность) | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Диагностика отказа Gateway Если запрос к приложению с заголовком `Authorization: Bearer` возвращает `401` с кодом `BH_LOGIN_REQUIRED`, тело ответа содержит поле `reason` с конкретной причиной отказа Gateway: | `reason` | Что произошло | Что делать | |----------|---------------|------------| | `expired` | JWT просрочен (истёк 10-минутный срок) | Обновите токен этим эндпоинтом или выпустите новый | | `signature` | Подпись не сошлась | Используйте токен, выпущенный для этого сервера, и не редактируйте его | | `subdomain` | Токен привязан к другому субдомену | Обращайтесь к собственному субдомену `app-*` сервера | | `revoked` | Токен отозван | Выпустите новый токен | | `type` | Передан не `api-bearer`-токен | Используйте токен режима `api-bearer`, а не сессию по куки | | `malformed` / `invalid` | Строка не является корректным JWT | Проверьте целостность токена | ## Известные особенности - **Один отзыв гасит все выданные JWT токена.** [`DELETE`](./delete.md) по записи прекращает работу и исходного JWT, и всех выпущенных обновлением. - **Ссылки `share-url` обновляются сами.** При каждом переходе они проходят через `/auth/bh-login`, поэтому вызывать обновление для них не нужно. - **Готовый цикл «использовал → при 401 обновил → повторил».** Вместо слежения за таймером клиент реагирует на отказ: ```javascript async function callWithRefresh(serverId, tokenId, appUrl, jwt) { let res = await fetch(`${appUrl}/api/health`, { headers: { Authorization: `Bearer ${jwt}` }, }) if (res.status === 401) { const r = await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/access-tokens/${tokenId}/refresh`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY' } }, ) const { data } = await r.json() jwt = data.token // тот же tokenId, свежий JWT res = await fetch(`${appUrl}/api/health`, { headers: { Authorization: `Bearer ${jwt}` }, }) } return res } ``` ## Смотрите также - [Выпустить токен](./create.md) - [Список токенов](./list.md) - [Отозвать токен](./delete.md) - [Токены доступа](/docs/infra/access-tokens) --- # Infrastructure Access: Access Add ## Добавить пользователя или отдел `POST /v1/infra/servers/:id/access` Добавляет запись доступа к BLACKHOLE-серверу: конкретного пользователя Битрикс24 (при политике `NAMED_USERS`) или отдел (при политике `DEPARTMENT`). Политика при этом не меняется автоматически — смените её через [`PATCH /access-policy`](./access-policy.md) отдельно, если ещё не переключали. Дубликаты (тот же `userId` или `departmentId` на том же сервере) возвращают 409 `ALREADY_EXISTS`. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | string (UUID) | да | ID BLACKHOLE-сервера | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|----------| | `type` | string | **да** | `user` — добавить пользователя, `department` — добавить отдел | | `userId` | string | да (для `type: "user"`) | ID пользователя Битрикс24. Ищите через [`GET /b24-users?search=`](./b24-users.md) | | `userName` | string | нет | Имя пользователя (до 255 символов). Опционально, но рекомендуется для удобства чтения в UI | | `departmentId` | string | да (для `type: "department"`) | ID отдела Битрикс24 | | `departmentName` | string | да (для `type: "department"`) | Имя отдела (до 255 символов) | ## Примеры ### curl — личный ключ ```bash # Добавить пользователя curl -X POST https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/access \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"type": "user", "userId": "243", "userName": "Катя Иванова"}' # Добавить отдел curl -X POST https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/access \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"type": "department", "departmentId": "5", "departmentName": "Разработка"}' ``` ### curl — OAuth-приложение ```bash curl -X POST https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/access \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"type": "user", "userId": "243", "userName": "Катя Иванова"}' ``` ### JavaScript — личный ключ ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/access`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ type: 'user', userId: '243', userName: 'Катя Иванова', }), } ) if (res.status === 201) { const { data } = await res.json() console.log(`Добавлен: ${data.userName} (запись ${data.id})`) } ``` ### JavaScript — OAuth-приложение ```javascript await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/access`, { method: 'POST', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ type: 'department', departmentId: '5', departmentName: 'Разработка', }), } ) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | `true` при успешном добавлении. HTTP-статус — 201 | | `data.id` | string (UUID) | ID созданной записи — передавайте в [`DELETE /access/:accessId`](./access-delete.md) для удаления | | `data.serverId` | string (UUID) | ID сервера | | `data.userId` | string | ID пользователя Битрикс24 (только для `type: "user"`) | | `data.userName` | string \| null | Имя пользователя (только для `type: "user"`) | | `data.networkUserId` | string \| null | Network ID пользователя. `null` сразу после создания, заполняется асинхронно (только для `type: "user"`) | | `data.departmentId` | string | ID отдела Битрикс24 (только для `type: "department"`) | | `data.departmentName` | string | Имя отдела (только для `type: "department"`) | | `data.grantedBy` | string (UUID) | ID пользователя Вайбкод, который создал запись | | `data.createdAt` | string (ISO 8601) | Момент добавления | ## Пример ответа Добавление пользователя: ```json { "success": true, "data": { "id": "b3a6f8d1-3c2a-4e17-9f0b-1a7c2d4e5f60", "serverId": "e765edfc-ba0a-43de-b8ea-838dd872c522", "userId": "243", "userName": "Катя Иванова", "networkUserId": null, "grantedBy": "f1d2e3c4-5b6a-4d0e-8f1a-2b3c4d5e6f70", "createdAt": "2026-04-22T10:15:00.000Z" } } ``` Добавление отдела: ```json { "success": true, "data": { "id": "c7d8e9f0-1a2b-3c4d-5e6f-7a8b9c0d1e2f", "serverId": "e765edfc-ba0a-43de-b8ea-838dd872c522", "departmentId": "5", "departmentName": "Разработка", "grantedBy": "f1d2e3c4-5b6a-4d0e-8f1a-2b3c4d5e6f70", "createdAt": "2026-04-22T11:30:00.000Z" } } ``` ## Пример ответа при ошибке 409 — запись уже существует: ```json { "success": false, "error": { "code": "ALREADY_EXISTS", "message": "Access entry already exists" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `VALIDATION_ERROR` | Поля не прошли валидацию: неверный `type`, отсутствует обязательное поле для выбранного типа | | 400 | `BLACKHOLE_ONLY` | Сервер в режиме OPEN | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ | | 404 | `NOT_FOUND` | Сервер не существует, удалён или принадлежит другому API-ключу | | 409 | `ALREADY_EXISTS` | Запись для этого `userId`/`departmentId` на этом сервере уже существует | | 429 | `RATE_LIMITED` | Превышен общий лимит запросов платформы | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **`userName` и `departmentName` — только для отображения.** Для сопоставления при проверке доступа используются `userId`/`departmentId` — имя на авторизацию не влияет. Имя используется для отображения в списке, когда интеграция с Битрикс24 временно недоступна. - **`networkUserId` заполняется асинхронно.** Сразу после `POST` поле `null`. В фоне платформа вызывает веб-хук Битрикс24 (если доступен), находит Network ID пользователя и обновляет запись. Это нужно для сопоставления, когда пользователь входит в Вайбкод через Network OAuth (а не через ваш портал). - **Уникальность — пара `(serverId, userId)` для пользователей и `(serverId, departmentId)` для отделов.** Чтобы «обновить» запись — сначала `DELETE`, потом `POST`. - **Политика не меняется автоматически.** Если сервер в `OWNER_ONLY`, добавление записи не сработает как «открытие доступа» — сначала переключите политику на `NAMED_USERS` (или `DEPARTMENT`) через [`PATCH /access-policy`](./access-policy.md). ## Смотрите также - [Список доступа](./access-list.md) - [Удалить запись](./access-delete.md) - [Политика доступа](./access-policy.md) - [Поиск пользователей Битрикс24](./b24-users.md) --- # Infrastructure Access: Access Delete ## Удалить запись доступа `DELETE /v1/infra/servers/:id/access/:accessId` Удаляет запись доступа — пользователя или отдел — из списка BLACKHOLE-сервера. Эндпоинт универсальный: один и тот же `accessId` может относиться либо к пользователю (`BlackHoleAccess`), либо к отделу (`BlackHoleDepartment`) — платформа сначала ищет в первой таблице, потом во второй. После удаления запись исчезает из [`GET /access`](./access-list.md). ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | string (UUID) | да | ID BLACKHOLE-сервера | | `accessId` | path | string (UUID) | да | ID записи доступа из [`GET /access`](./access-list.md) или [`POST /access`](./access-add.md) | ## Примеры ### curl — личный ключ ```bash curl -X DELETE -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/access/b3a6f8d1-3c2a-4e17-9f0b-1a7c2d4e5f60 ``` ### curl — OAuth-приложение ```bash curl -X DELETE -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/access/ACCESS_ID ``` ### JavaScript — личный ключ ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/access/${accessId}`, { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY' }, } ) const { success } = await res.json() if (success) console.log('Запись удалена') ``` ### JavaScript — OAuth-приложение ```javascript await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/access/${accessId}`, { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, } ) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | `true` при успешном удалении | ## Пример ответа ```json { "success": true } ``` ## Пример ответа при ошибке 404 — запись не найдена (уже удалена, неверный accessId, либо accessId другого сервера): ```json { "success": false, "error": { "code": "NOT_FOUND", "message": "Access entry not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `BLACKHOLE_ONLY` | Сервер в режиме OPEN | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ | | 404 | `NOT_FOUND` | Сервер не существует или запись не найдена (неверный `accessId`, уже удалена, или принадлежит другому серверу) | | 429 | `RATE_LIMITED` | Превышен общий лимит запросов платформы | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Физическое удаление, не пометка на удаление.** Запись стирается из базы. Восстановить нельзя — придётся повторно вызывать [`POST /access`](./access-add.md). - **`accessId` привязан к серверу.** Попытка удалить запись доступа другого сервера (правильный `accessId`, но неверный `:id` в пути) вернёт 404 `NOT_FOUND`. Платформа намеренно не раскрывает факт существования записей чужих серверов. - **Удаление не меняет политику.** Если вы удалите всех пользователей при `accessPolicy: "NAMED_USERS"`, политика останется `NAMED_USERS` (и приложение станет недоступно никому, кроме владельца ключа). Чтобы «полностью вернуть приватность» — меняйте политику обратно на `OWNER_ONLY` через [`PATCH /access-policy`](./access-policy.md). - **Владельца ключа удалить нельзя.** Владелец всегда имеет доступ, даже если его нет в списке. Чтобы забрать у себя доступ — нужен другой API-ключ. ## Смотрите также - [Список доступа](./access-list.md) - [Добавить пользователя/отдел](./access-add.md) - [Политика доступа](./access-policy.md) --- # Infrastructure Access: Access List ## Список доступа `GET /v1/infra/servers/:id/access` Возвращает список пользователей и отделов Битрикс24 с доступом к приложению. Применяется, когда [`accessPolicy`](./access-policy.md) установлено в `NAMED_USERS` (список пользователей) или `DEPARTMENT` (список отделов). Работает только для BLACKHOLE-серверов. При `OWNER_ONLY`, `PORTAL`, `AUTHENTICATED`, `PUBLIC` списки в базе сохраняются, но не применяются. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | string (UUID) | да | ID BLACKHOLE-сервера | ## Примеры ### curl — личный ключ ```bash curl -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/access ``` ### curl — OAuth-приложение ```bash curl -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/access ``` ### JavaScript — личный ключ ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/access`, { headers: { 'X-Api-Key': 'YOUR_API_KEY' } } ) const { data } = await res.json() console.log(`Пользователей: ${data.users.length}`) console.log(`Отделов: ${data.departments.length}`) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/access`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, } ) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data.users` | array | Записи доступа пользователей, отсортированные по `createdAt` (новые сверху) | | `data.users[].id` | string (UUID) | ID записи в таблице — нужен для [`DELETE`](./access-delete.md) | | `data.users[].userId` | string | ID пользователя Битрикс24 | | `data.users[].userName` | string \| null | Имя пользователя (необязательное, заполняется при добавлении) | | `data.users[].networkUserId` | string \| null | Network ID пользователя — заполняется асинхронно после добавления, используется для сопоставления при входе через Вайбкод-сессию | | `data.users[].grantedBy` | string (UUID) | ID пользователя Вайбкод, который создал запись | | `data.users[].createdAt` | string (ISO 8601) | Момент добавления | | `data.departments` | array | Записи доступа отделов | | `data.departments[].id` | string (UUID) | ID записи — нужен для [`DELETE`](./access-delete.md) | | `data.departments[].departmentId` | string | ID отдела Битрикс24 | | `data.departments[].departmentName` | string | Имя отдела (обязательное при добавлении) | | `data.departments[].grantedBy` | string (UUID) | ID пользователя Вайбкод, который создал запись | | `data.departments[].createdAt` | string (ISO 8601) | Момент добавления | ## Пример ответа ```json { "success": true, "data": { "users": [ { "id": "b3a6f8d1-3c2a-4e17-9f0b-1a7c2d4e5f60", "serverId": "e765edfc-ba0a-43de-b8ea-838dd872c522", "userId": "243", "userName": "Катя Иванова", "networkUserId": "net_90126", "grantedBy": "f1d2e3c4-5b6a-4d0e-8f1a-2b3c4d5e6f70", "createdAt": "2026-04-20T10:15:00.000Z" } ], "departments": [ { "id": "c7d8e9f0-1a2b-3c4d-5e6f-7a8b9c0d1e2f", "serverId": "e765edfc-ba0a-43de-b8ea-838dd872c522", "departmentId": "5", "departmentName": "Разработка", "grantedBy": "f1d2e3c4-5b6a-4d0e-8f1a-2b3c4d5e6f70", "createdAt": "2026-04-20T11:30:00.000Z" } ] } } ``` ## Пример ответа при ошибке 400 — сервер в режиме OPEN: ```json { "success": false, "error": { "code": "BLACKHOLE_ONLY", "message": "Access lists are a Black Hole feature. Server is in OPEN mode — switch to BLACKHOLE via PATCH /v1/infra/servers/:id/mode first." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `BLACKHOLE_ONLY` | Сервер в режиме OPEN | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ | | 404 | `NOT_FOUND` | Сервер не существует, удалён или принадлежит другому API-ключу | | 429 | `RATE_LIMITED` | Превышен общий лимит запросов платформы | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Обе коллекции отдаются независимо от текущей политики.** Можно вести список пользователей и список отделов параллельно, а переключать активную политику через [`PATCH /access-policy`](./access-policy.md) позже. - **`networkUserId` заполняется асинхронно.** Первые секунды после [`POST /access`](./access-add.md) поле может быть `null` — затем фоновый запрос к Битрикс24 проставит Network ID (он нужен для Вайбкод-сессий, если пользователь входит в Вайбкод через Вайбкод-логин, а не через OAuth Битрикс24). - **`grantedBy` — ID пользователя Вайбкод, не Битрикс24.** Соответствует `User.id` в базе платформы, не `userId` на портале Битрикс24. Если запись создана из UI — это автор вызова. Если через API-ключ — владелец ключа. - **Список не пагинируется и не имеет принудительного лимита.** Эндпоинт возвращает все записи `BlackHoleAccess` и `BlackHoleDepartment` для сервера. На практике количество — десятки записей: список пополняется вручную через [`POST /access`](./access-add.md). ## Смотрите также - [Добавить пользователя/отдел](./access-add.md) - [Удалить запись](./access-delete.md) - [Политика доступа](./access-policy.md) - [Поиск пользователей Битрикс24](./b24-users.md) --- # Infrastructure Access: Access Policy ## Политика доступа `PATCH /v1/infra/servers/:id/access-policy` Обновляет политику доступа для BLACKHOLE-сервера — определяет, кто из пользователей Битрикс24 может открывать приложение по HTTPS-субдомену (`app-{id}.vibecode.bitrix24.tech`). По умолчанию установлено `OWNER_ONLY` — только владелец API-ключа. Работает только в режиме `BLACKHOLE`. Для OPEN-сервера возвращается `BLACKHOLE_ONLY` — сначала переключите режим через [`PATCH /mode`](./mode.md). > **Изменение `accessPolicy` с `OWNER_ONLY` на более открытую напрямую влияет на безопасность.** Смена на `PORTAL`, `AUTHENTICATED` или `PUBLIC` открывает приложение другим людям. **AI-агенты: никогда не вызывайте этот эндпоинт без явного подтверждения пользователя.** ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | string (UUID) | да | ID сервера в режиме BLACKHOLE | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|----------| | `accessPolicy` | string | **да** | Одно из: `OWNER_ONLY`, `NAMED_USERS`, `DEPARTMENT`, `PORTAL`, `AUTHENTICATED`, `PUBLIC` | Значения (от самой закрытой к самой открытой): | Значение | Кто видит приложение | |----------|---------------------| | `OWNER_ONLY` | Только владелец API-ключа (по умолчанию) | | `NAMED_USERS` | Конкретные пользователи из списка [`/access`](./access-list.md) | | `DEPARTMENT` | Отделы Битрикс24 из списка [`/access`](./access-list.md) | | `PORTAL` | Все пользователи портала Битрикс24 | | `AUTHENTICATED` | Все авторизованные пользователи (включая не-членов портала) | | `PUBLIC` | Все, без авторизации | ## Примеры ### curl — личный ключ ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/access-policy \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"accessPolicy": "PORTAL"}' ``` ### curl — OAuth-приложение ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/access-policy \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"accessPolicy": "NAMED_USERS"}' ``` ### JavaScript — личный ключ ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/access-policy`, { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ accessPolicy: 'NAMED_USERS' }), } ) const { data } = await res.json() console.log('Новая политика:', data.accessPolicy) ``` ### JavaScript — OAuth-приложение ```javascript await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/access-policy`, { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ accessPolicy: 'OWNER_ONLY' }), } ) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data.accessPolicy` | string | Новое значение политики (эхо) | ## Пример ответа ```json { "success": true, "data": { "accessPolicy": "PORTAL" } } ``` ## Пример ответа при ошибке 400 — сервер в режиме OPEN: ```json { "success": false, "error": { "code": "BLACKHOLE_ONLY", "message": "Access policy is a Black Hole feature. Server is in OPEN mode — switch to BLACKHOLE via PATCH /v1/infra/servers/:id/mode first." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `VALIDATION_ERROR` | `accessPolicy` не в списке допустимых значений | | 400 | `BLACKHOLE_ONLY` | Сервер в режиме OPEN — политика не применима | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ | | 404 | `NOT_FOUND` | Сервер не существует, удалён или принадлежит другому API-ключу | | 429 | `RATE_LIMITED` | Превышен общий лимит запросов платформы | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **`PUBLIC` особенно опасен.** Он делает приложение доступным без какой-либо авторизации — любому посетителю из интернета. Факт смены политики фиксируется в аудит-логе портала. - **`NAMED_USERS` и `DEPARTMENT` требуют непустых списков доступа.** Сама смена политики не добавляет пользователей — список ведётся отдельно через [`POST /access`](./access-add.md). Если список пустой при `NAMED_USERS`/`DEPARTMENT`, приложение будет недоступно никому, кроме владельца (автоматического отката к `OWNER_ONLY` не происходит). - **При возврате в `OWNER_ONLY` записи в `/access` сохраняются в базе.** Они не применяются, пока политика не `NAMED_USERS`/`DEPARTMENT`. Если захотите очистить историю — удалите записи через [`DELETE /access/:accessId`](./access-delete.md). - **При смене режима на OPEN `accessPolicy` не меняется**, но и не применяется: в OPEN защита идёт через SSH-ключи и iptables. При возврате в BLACKHOLE политика снова станет действующей. - **`AUTHENTICATED` включает не-членов портала.** В отличие от `PORTAL`, `AUTHENTICATED` пропускает любого авторизованного пользователя Битрикс24 (в том числе тех, кто не состоит в вашем портале). Подходит для приложений-гостевых форм, но снимает привязку к своему портальному коллективу. - **Владелец API-ключа всегда имеет доступ** — он не удаляется из списка при смене политики. Чтобы забрать доступ у себя, нужен запрос с другого ключа. - **При открытии из каталога Битрикс24 членство в портале подтверждает сам портал.** Сотруднику не нужна учётная запись Вайбкод: приложение с политикой `PORTAL` (а также `AUTHENTICATED` и `PUBLIC`) открывается всем сотрудникам, как и обещано. Платформа дополнительно спрашивает у Битрикс24, что это активный сотрудник, а не уволенный и не внешний гость. Именные политики (`OWNER_ONLY`, `NAMED_USERS`, `DEPARTMENT`) этим путём не открываются — они решают по конкретному человеку, поэтому сотруднику нужно один раз войти в Вайбкод. ## Смотрите также - [Список доступа](./access-list.md) - [Добавить пользователя/отдел](./access-add.md) - [Удалить запись доступа](./access-delete.md) - [Поиск пользователей Битрикс24](./b24-users.md) - [Переключить режим](./mode.md) --- # Infrastructure Access: B24 Users ## Поиск пользователей Битрикс24 `GET /v1/infra/servers/:id/b24-users` Ищет активных сотрудников на портале Битрикс24 по имени, фамилии или email — возвращает `userId`, имя, должность и фото для каждого совпадения. Неактивные пользователи и пользователи других типов в результат не попадают. Используется для заполнения списка `NAMED_USERS` через [`POST /access`](./access-add.md), когда известно имя человека, но не его ID на портале. Работает через B24-креды сервера: веб-хук-ключ из [apiKey.webhookUrl](/docs/keys-auth), а если ключ сервера — OAuth-приложение без пользовательского токена, применяется автоматический фоллбэк: сначала personal-ключ связанного приложения, затем личные ключи владельца сервера — от свежего к старому, до первого, который действительно даёт доступ к Битрикс24. Если ни один источник не даёт креды (приложение ещё не авторизовано на портале, ключ отозван или управляющий ключ не имеет доступа к Битрикс24 — например, нет webhook или нужного скоупа), эндпоинт возвращает пустой `data` вместе с полем `hint`, которое объясняет причину. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | string (UUID) | да | ID сервера | | `search` | query | string | **да** | Строка поиска, минимум 2 символа. Ищет по имени, фамилии и email | ## Примеры ### curl — личный ключ ```bash curl -H "X-Api-Key: YOUR_API_KEY" \ "https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/b24-users?search=Иван" ``` ### curl — OAuth-приложение ```bash curl -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ "https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/b24-users?search=Иван" ``` ### JavaScript — личный ключ ```javascript const q = encodeURIComponent('Иван') const res = await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/b24-users?search=${q}`, { headers: { 'X-Api-Key': 'YOUR_API_KEY' } } ) const { data: users } = await res.json() users.forEach(u => console.log(`${u.id}: ${u.name} — ${u.position ?? 'без должности'}`)) ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/b24-users?search=${q}`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, } ) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data` | array | Массив найденных активных сотрудников | | `data[].id` | string | ID пользователя Битрикс24 — передавайте в `userId` при [`POST /access`](./access-add.md) | | `data[].name` | string | Полное имя (имя + фамилия) | | `data[].photo` | string \| null | URL аватарки (может быть `null`) | | `data[].position` | string \| null | Должность (может быть `null`) | | `hint` | string | Необязательное. Присутствует только когда `data` пуст из-за отсутствия B24-кредов (приложение не авторизовано на портале, ключ отозван или управляющий ключ не имеет webhook/нужного скоупа). При непустой выдаче отсутствует | ## Пример ответа ```json { "success": true, "data": [ { "id": "243", "name": "Катя Иванова", "photo": null, "position": null } ] } ``` ## Пример ответа при ошибке 400 — строка поиска короче 2 символов: ```json { "success": false, "error": { "code": "VALIDATION_ERROR", "message": "search query required (min 2 chars)" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `VALIDATION_ERROR` | `search` отсутствует или короче 2 символов | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ | | 404 | `NOT_FOUND` | Сервер не существует, удалён или принадлежит другому API-ключу | | 429 | `RATE_LIMITED` | Превышен общий лимит запросов платформы | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Пустой `data` с полем `hint`, когда B24-кредов нет.** Если ключ сервера — OAuth-приложение без пользовательского токена, платформа сначала пробует personal-ключ связанного приложения, а затем перебирает личные ключи владельца сервера от свежего к старому. Если доступа не даёт ни один (приложения нет, ключи отозваны/истекли, владелец заблокирован или ни у одного ключа нет webhook/нужного скоупа), эндпоинт возвращает `data: []` и строку `hint` с причиной — вместо немого пустого массива. Клиент может отобразить `hint` пользователю или переключиться на альтернативный инструмент. - **Поиск выполняется через метод `user.search` на портале Битрикс24.** То есть логика совпадения с UI портала — те же правила по имени/фамилии/email. - **Кириллица в URL — через `encodeURIComponent`.** На JS: `encodeURIComponent('Иван')`. На curl: `?search=%D0%98%D0%B2%D0%B0%D0%BD`. - **Не зависит от режима сервера.** Поиск работает для любого сервера — и BLACKHOLE, и OPEN. Логически он нужен для `NAMED_USERS`, но эндпоинт не ограничивает вызов по `mode`. ## Смотрите также - [Добавить пользователя/отдел](./access-add.md) - [Список доступа](./access-list.md) - [Политика доступа](./access-policy.md) --- # Infrastructure Access: Mode ## Переключить режим `PATCH /v1/infra/servers/:id/mode` Переключает сервер между режимами `BLACKHOLE` (всё закрыто фаерволом, доступ только через HTTPS-субдомен) и `OPEN` (прямой доступ по IP, SSH на порту 22 открыт). При переходе в `OPEN` фаервол полностью снимается и генерируется SSH-пароль. При обратном переходе фаервол восстанавливается и пароль удаляется. Переход в `OPEN` запрещён, если платформа (флаг `openModeEnabled`) или портал (политика `allowOpenMode`) не разрешают его. > **OPEN отключает защиту Black Hole.** Сервер становится доступен из интернета по IP. Все Deploy API эндпоинты (`/exec`, `/upload`, `/logs`, `/deploy`) работают только в BLACKHOLE-режиме — в OPEN они вернут ошибку. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | string (UUID) | да | ID сервера | ## Поля запроса (body) | Поле | Тип | Обяз. | Описание | |------|-----|:-----:|----------| | `mode` | string | **да** | Целевой режим: `OPEN` или `BLACKHOLE` | ## Примеры ### curl — личный ключ ```bash # BLACKHOLE → OPEN curl -X PATCH https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/mode \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"mode": "OPEN"}' # OPEN → BLACKHOLE (вернуть защиту) curl -X PATCH https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/mode \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"mode": "BLACKHOLE"}' ``` ### curl — OAuth-приложение ```bash curl -X PATCH https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/mode \ -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"mode": "OPEN"}' ``` ### JavaScript — личный ключ ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/mode`, { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ mode: 'OPEN' }), } ) const { data } = await res.json() if (data.sshPassword) console.log(`Новый SSH-пароль: ${data.sshPassword}`) ``` ### JavaScript — OAuth-приложение ```javascript await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/mode`, { method: 'PATCH', headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ mode: 'BLACKHOLE' }), } ) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data.mode` | string | Новый режим (`OPEN` или `BLACKHOLE`) | | `data.ip` | string \| null | IP сервера (не меняется при переключении) | | `data.sshPassword` | string \| null | Сгенерированный SSH-пароль. Отдаётся только при переходе в `OPEN`. При переходе в `BLACKHOLE` — `null` | ## Пример ответа Переход BLACKHOLE → OPEN: ```json { "success": true, "data": { "mode": "OPEN", "ip": "178.154.230.106", "sshPassword": "rT9xQ2mKaPzFHyB3" } } ``` Переход OPEN → BLACKHOLE: ```json { "success": true, "data": { "mode": "BLACKHOLE", "ip": "178.154.230.106", "sshPassword": null } } ``` ## Пример ответа при ошибке 403 — переход в `OPEN` запрещён политикой портала: ```json { "success": false, "error": { "code": "OPEN_MODE_NOT_ALLOWED", "message": "OPEN mode is not allowed by portal policy", "userMessage": "Режим OPEN не разрешён политикой портала. Администратор включает его в Настройки → Создание. Пока используйте Deploy API (exec/upload/logs)." } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 400 | `INVALID_MODE` | `mode` не равен `OPEN` или `BLACKHOLE` | | 400 | `SAME_MODE` | Сервер уже в запрошенном режиме | | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ | | 403 | `OPEN_MODE_DISABLED` | Режим OPEN отключён на платформе (флаг `openModeEnabled`). Обратитесь к администратору платформы. Ответ несёт `error.userMessage` — готовый текст на языке пользователя | | 403 | `OPEN_MODE_NOT_ALLOWED` | Режим OPEN запрещён политикой портала (флаг `allowOpenMode`). Обратитесь к администратору портала. Ответ несёт `error.userMessage`. Исключение — вторая ветка этого же кода с сообщением `Portal context required`: она приходит без `userMessage` | | 404 | `NOT_FOUND` | Сервер не существует, удалён или принадлежит другому API-ключу | | 429 | `RATE_LIMITED` | Превышен общий лимит запросов платформы | | 502 | `PROVIDER_ERROR` | Облачный провайдер вернул ошибку при смене конфигурации сети | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Порядок разрешения OPEN** (оба уровня должны пропустить): сначала платформенный флаг `openModeEnabled` — **платформенный админ тоже не обходит эту проверку**. Затем портальная политика `allowOpenMode` — **платформенный админ обходит её**. Только если оба разрешают, переход в OPEN возможен. - **IP не меняется при переключении.** Облачная виртуальная машина остаётся той же — меняются только правила iptables и SSH-конфигурация. - **Туннель (`blackholeStatus`) сохраняется в OPEN-режиме.** Агент Black Hole продолжает работать, HTTPS-субдомен остаётся рабочим — просто фаервол больше не блокирует внешний трафик. Однако Deploy API всё равно откажет: он требует именно BLACKHOLE. - **`accessPolicy` не применяется в OPEN.** В OPEN защита строится на SSH-ключах и iptables (который снят). Политика HTTPS-субдомена фактически не работает. При переключении значение `accessPolicy` сохраняется в базе — и снова начнёт действовать после возврата в BLACKHOLE. ## Смотрите также - [SSH-данные](./ssh.md) - [Политика доступа](./access-policy.md) - [Deploy API](/docs/infra/deploy) - [Получить сервер](/docs/infra/servers/get) --- # Infrastructure Access: Ssh ## SSH-данные `GET /v1/infra/servers/:id/ssh` Возвращает данные для SSH-подключения. Полноценный SSH-доступ (с паролем, приватным ключом и публичным ключом) возвращается только для серверов в режиме `OPEN`. Для `BLACKHOLE` все SSH-поля — `null`: сервер закрыт фаерволом iptables, и прямой SSH невозможен. Вместо SSH для BLACKHOLE используйте [Deploy API](/docs/infra/deploy) — `/exec`, `/upload`, `/logs`. Rate-limit: до 10 запросов в минуту на сервер. ## Параметры | Параметр | В | Тип | Обяз. | Описание | |----------|---|-----|:-----:|----------| | `id` | path | string (UUID) | да | ID сервера | ## Примеры ### curl — личный ключ ```bash curl -H "X-Api-Key: YOUR_API_KEY" \ https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/ssh ``` ### curl — OAuth-приложение ```bash curl -H "X-Api-Key: YOUR_APP_KEY" \ -H "Authorization: Bearer USER_SESSION_TOKEN" \ https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/ssh ``` ### JavaScript — личный ключ ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/ssh`, { headers: { 'X-Api-Key': 'YOUR_API_KEY' } } ) const { data } = await res.json() if (data.mode === 'OPEN') { console.log('Команда:', data.sshCommand) console.log('Пароль:', data.sshPassword) // если выдавался } else { console.log(data.note) // BLACKHOLE — используйте Deploy API } ``` ### JavaScript — OAuth-приложение ```javascript const res = await fetch( `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/ssh`, { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', }, } ) ``` ## Поля ответа | Поле | Тип | Описание | |------|-----|----------| | `success` | boolean | Всегда `true` при успехе | | `data.mode` | string | `OPEN` или `BLACKHOLE` | | `data.ip` | string | Публичный IP сервера | | `data.sshDirect` | boolean | `true` для `OPEN` (SSH работает по IP), `false` для `BLACKHOLE` (закрыт файрволом) | | `data.sshUser` | string \| null | Пользователь SSH: `ubuntu` или `root`. `null` для BLACKHOLE | | `data.sshPort` | number \| null | Порт SSH: `22`. `null` для BLACKHOLE | | `data.sshPassword` | string \| null | Пароль. Для BLACKHOLE всегда `null`. Для OPEN — пароль если сервер сгенерил один при переходе в OPEN | | `data.sshPrivateKey` | string \| null | Приватный ключ OpenSSH (ed25519). Возвращается для OPEN-сервера, когда платформа его сгенерировала | | `data.sshPublicKey` | string \| null | Публичный ключ (ed25519) — соответствующая публичная часть к `sshPrivateKey` | | `data.sshCommand` | string \| null | Готовая команда для копирования: `ssh ubuntu@IP`. Для BLACKHOLE — `null` | | `data.appUrl` | string | HTTPS-адрес приложения (присутствует только для BLACKHOLE, где SSH недоступен) | | `data.note` | string | Пояснение для BLACKHOLE: «BLACKHOLE servers do not expose SSH. Use the Deploy API…» | ## Пример ответа OPEN-сервер: ```json { "success": true, "data": { "mode": "OPEN", "ip": "111.88.251.211", "sshUser": "ubuntu", "sshPort": 22, "sshPassword": "Oi9owBO6zMbueGmM75J9hg", "sshPrivateKey": "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmU…\n-----END OPENSSH PRIVATE KEY-----\n", "sshPublicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM0JAP1EMGh0CkT7RkZ26pTSa4X1FsWXe61cB5Fiqqjz vibe-generated", "sshCommand": "ssh ubuntu@111.88.251.211", "sshDirect": true } } ``` BLACKHOLE-сервер: ```json { "success": true, "data": { "mode": "BLACKHOLE", "ip": "93.77.184.167", "sshDirect": false, "sshPassword": null, "sshPrivateKey": null, "sshPublicKey": null, "sshCommand": null, "appUrl": "https://app-abc12345.vibecode.bitrix24.tech", "note": "BLACKHOLE servers do not expose SSH. Use the Deploy API (exec/upload/logs) instead." } } ``` ## Пример ответа при ошибке 404 — сервер не существует: ```json { "success": false, "error": { "code": "NOT_FOUND", "message": "Server not found" } } ``` ## Ошибки | HTTP | Код | Описание | |------|-----|----------| | 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` | | 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ | | 404 | `NOT_FOUND` | Сервер не существует, удалён или принадлежит другому API-ключу | | 429 | `RATE_LIMITED` | Превышен rate-limit (до 10 запросов в минуту на сервер) либо общий rate-limit платформы | Полный список общих ошибок API — [Ошибки](/docs/errors). ## Известные особенности - **Каждый BLACKHOLE → OPEN переход генерирует новый пароль.** Старые пароли (если они были) становятся недействительными. То же при обратном цикле BLACKHOLE → OPEN → BLACKHOLE → OPEN: на каждый вход в OPEN платформа генерирует свежий `sshPassword`. Пароль также возвращается в ответе на [`PATCH /mode`](./mode.md) — можно сохранить оттуда. - **`sshPrivateKey` и `sshPublicKey` отдаются только для ключей, сгенерированных платформой.** Если при создании сервера через [`POST /v1/infra/servers`](/docs/infra/servers/create) вы передали свой `sshPublicKey`, платформа не генерировала приватный ключ — поле `sshPrivateKey` в ответе будет `null`. Используйте свой приватный ключ со стороны клиента. - **`sshCommand` — готовая к копированию строка для AI-агентов и скриптов.** Это не отдельная команда запуска — просто `ssh ubuntu@IP`. Аутентификация через пароль или ключ — отдельный шаг на стороне SSH-клиента. - **Отдельное ограничение — 10 запросов в минуту на сервер** существует именно из-за чувствительности возвращаемых данных. Общий лимит платформы выше, но `/ssh` ограничивается жёстче. ## Смотрите также - [Переключить режим](./mode.md) - [Выполнить команду](/docs/infra/deploy/exec) - [Загрузить файл](/docs/infra/deploy/upload) - [Политика доступа](./access-policy.md) --- # Infrastructure: App Icon ## Иконка приложения Иконка приложения — это **SVG**, который показывается в каталоге приложений Bitrix24 и как фавикон во вкладке браузера. Платформа иконку не генерирует — вы загружаете свою через Deploy API. Эта страница — единый источник по формату и порядку загрузки; промпт «Иконка приложения» в кабинете ссылается сюда. **Скоуп:** `vibe:infra` (добавляется в каждый API-ключ автоматически) · **Базовый URL:** `https://vibecode.bitrix24.tech/v1` · **Авторизация:** заголовок `X-Api-Key` ## Формат - **Только SVG** (`image/svg+xml`). Другие форматы отклоняются. - **До 256 КБ.** - **Без скриптов, обработчиков событий и внешних ссылок** — никаких `