
## Создать чат-комплишен

> **Ответ приходит в сыром 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[].reasoning_content` | string \| null | нет | — | Рассуждение модели из прошлого ответа, возвращённое в историю диалога. Учитывается только у роли `assistant`, у сообщений других ролей игнорируется. Значение `null` равнозначно отсутствию поля, пустая строка допустима. Значение не строкой или длиннее 4 000 000 символов отклоняется с `400 invalid_request`. Поле доходит до модели, у которой `owned_by` в [`GET /v1/models`](/docs/ai/models/list) равно `bitrix`, `openrouter` или `vibecode`, и не передаётся моделям OpenAI, Anthropic и других OpenAI-совместимых провайдеров. Модель, которая читает рассуждение, учитывает его во входных токенах. Применение — [вызов функций](./tools.md) |
| `messages[].tool_call_id` | string | нет | — | ID вызова функции — обязателен в сообщении с `role: "tool"` |
| `temperature` | number | нет | по модели | Температура генерации, диапазон `0..2`. Меньше — точнее и детерминированнее, больше — креативнее |
| `max_tokens` | number | нет | по модели | Максимум токенов в ответе |
| `top_p` | number | нет | — | Nucleus sampling, диапазон `0..1` |
| `reasoning_effort` | string | нет | по модели | OpenAI-совместимый уровень рассуждения: `none`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`. Нормализуется в ступень платформы — см. [«Управление рассуждением»](#управление-рассуждением) |
| `reasoning` | object | нет | — | Канонический объект. `effort` — уровень из того же словаря. `max_tokens` — бюджет токенов рассуждения, действует только у моделей с `budgetTokens: true`. `enabled` — `false` выключает рассуждение. `exclude` — `true` убирает `reasoning_content` из ответа, токены рассуждения при этом оплачиваются. Старше, чем `reasoning_effort` |
| `chat_template_kwargs` | object | нет | — | Вендорский формат `{"thinking": boolean, "reasoning_effort": string}`. Принимается для совместимости, разбирается в ту же ступень и в модель сырым не передаётся. Неизвестные ключи внутри игнорируются. Младше двух полей выше |
| `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": "..."}}` (форсировать конкретную) |

## Управление рассуждением

Модели с рассуждением думают перед ответом. Токены рассуждения входят в `usage.completion_tokens` и **тарифицируются как выходные по той же ставке** — рычаг цены не тариф, а объём. Вайбкод описывает объём пятью ступенями: `none` — ответ сразу, `low` — короткая прикидка, `medium` — стандартное рассуждение модели, когда оно включено, а уровень не задан, `high` — сильнее стандартного, `max` — всё, что модель умеет.

Что умеет конкретная модель, показывает поле `reasoning` в [`GET /v1/models`](/docs/ai/models/list). Его `map` — карта ступеней на родные режимы модели, две ступени с одним родным значением — объявленное схлопывание. `default` — ступень по умолчанию, `budgetTokens` — поддержка бюджета токенов рассуждения. У модели с `reasoning: null` управление недоступно: параметр игнорируется с предупреждением `REASONING_NOT_SUPPORTED`, и в модель ничего не добавляется.

Нормализация входа: `minimal` → `low`, `xhigh` → `max`. `reasoning.enabled: true` или `chat_template_kwargs.thinking: true` без уровня дают `medium`. `reasoning.max_tokens` без `effort` — `medium` с бюджетом. Пустой `reasoning: {}` или `chat_template_kwargs: {}` — то же, что параметра нет. `null` в любом из трёх полей равнозначен отсутствию. Пришло несколько полей — берётся старшее: сначала `reasoning`, затем `reasoning_effort`, затем `chat_template_kwargs`. Значение вне словаря, неположительный `reasoning.max_tokens` или `chat_template_kwargs` не-объект отклоняются с `400 invalid_request`.

Если запрошенной ступени у модели нет, применяется ближайшая **ниже** из ступеней с рассуждением, а в `warnings` приходит `REASONING_EFFORT_ADJUSTED` с полями `requested`, `applied`, `direction`. Ступень `none` округлением не выбирается никогда — выключить рассуждение можно только явно. Если ниже ничего нет, берётся ближайшая выше. Просьба `none` у модели, где выключить нельзя, даёт низшую ступень и `REASONING_CANNOT_BE_DISABLED`. Бюджет у модели без `budgetTokens` игнорируется с `REASONING_BUDGET_NOT_SUPPORTED`.

**Без параметра в запросе платформа передаёт модели с декларацией ступень `default` явно.** Режим не остаётся на усмотрение провайдера модели, поэтому обновление модели на его стороне не меняет поведение запросов без параметра. Поле `reasoning` ответа сообщает эту ступень.

В ответе: поле `reasoning` с `requested`, `applied`, `native` и предупреждения в `warnings`. В потоковом режиме тело предупреждений не несёт — состояние едет заголовками `X-Reasoning-Applied`, `X-Reasoning-Native`, `X-Reasoning-Warnings` с кодами через запятую. У синхронного ответа те же заголовки дублируют тело. Заголовок отсутствует, когда сообщать нечего. При подмене модели — DISABLED-перенаправлении или переключении на резервную — ступень разрешается по модели, которая выполнила запрос, и поле `reasoning` с заголовками описывают её. `reasoning.exclude` исполняется у любой модели, в том числе без декларации.

## Алиасы моделей

Поле `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).

Кроме того, `model` принимает идентификатор модели без префикса провайдера: `bitrixgpt-5.5` разрешается в `bitrix/bitrixgpt-5.5`. Короткое имя должно целиком и с учётом регистра совпасть с идентификатором из [`GET /v1/models`](/docs/ai/models/list), у которого отброшен первый сегмент. Поиска по части идентификатора нет: запрос с `bitrixgpt` получит `404 ai_model_not_found`, а не первую модель, идентификатор которой содержит это слово. Короткое имя, под которое подходят несколько доступных ключу моделей, тоже получает `404` — передайте полный идентификатор. Модель, найденная по короткому имени, отмечается в ответе заголовком `X-Model-Resolved` с её полным идентификатором.

## Примеры

### 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`, `REASONING_EFFORT_ADJUSTED` (несёт `requested`, `applied`, `direction`), `REASONING_NOT_SUPPORTED`, `REASONING_CANNOT_BE_DISABLED`, `REASONING_BUDGET_NOT_SUPPORTED`, `TEMPERATURE_OVERRIDDEN_BY_REASONING`. Поле отсутствует, когда предупреждений нет |
| `reasoning` | object | Присутствует у моделей с декларацией рассуждения. `requested` — нормализованная ступень из запроса, `null`, если параметра не было. `applied` — применённая ступень. `native` — родной режим модели для неё. См. [«Управление рассуждением»](#управление-рассуждением) |
| `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 | `account_frozen` | Вызов заблокирован заморозкой платёжного аккаунта из-за отрицательного баланса. Пополните его; причину блокировки конкретного вызова уточняет сообщение ответа. Вызовы, покрытые тарифной AI-квотой, могут продолжать работать; состав ограничений — [заморозка счёта](/docs/errors) |
| 402 | `ai_quota_exhausted` | Месячная [AI-квота портала](/docs/ai/consumption/quota) исчерпана. Поле `reason` уточняет причину |
| 402 | `cowork_subscription_inactive` | У ключа со скоупом `vibe:cowork` нет действующей подписки Cowork/Code. Подписку возобновляют в разделе Cowork/Code в кабинете платформы Вайбкод, сам ключ остаётся действительным |
| 402 | `cowork_quota_exhausted` | Исчерпано одно из окон квоты подписки Cowork/Code. Тело несёт `window` (`5h`/`week`/`month`), `resetAt` и `nextTier`, заголовок `Retry-After` — число секунд до сброса окна |
| 402 | `company_budget_exhausted` | Исчерпан месячный бюджет расхода компании, который задаёт администратор портала. Поле `scope` называет пробитый бюджет: `USER` — личный бюджет вызывающего, `PORTAL` — бюджет всего портала. Поле `canRequest` говорит, можно ли запросить увеличение: у личного бюджета `true`, у портального `false` — его поднимает только администратор. Отказ приходит только на вызовах, которые списывают средства с баланса портала. Вызовы внутри тарифной квоты, по подписке Cowork/Code и на собственном ключе продолжают работать |
| 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai`. Ключу стороннего приложения из [Partner Connect](/docs/partner-connect) право добавляют не перевыпуском, а запросом на странице согласия — [Платформенные права](/docs/partner-connect#платформенные-права) |
| 404 | `ai_model_not_found` | Модель не найдена или отключена |
| 404 | `ai_model_not_found` | Короткое имя модели подходит нескольким доступным моделям. Передайте полный идентификатор |
| 409 | `agent_turn_awaiting_confirmation` | [AI-агент](/docs/agents) ждёт, пока пользователь подтвердит или отменит операцию. До ответа запросы его ключа на этот адрес отклоняются в любом разговоре. Запрос к модели не уходит, списания нет. При `stream: true` отказ приходит JSON-ответом. Ожидание снимается ответом пользователя или истекает само: срок задаёт агент, не больше 30 минут. Запросы других ключей отказ не затрагивает |
| 409 | `agent_turn_loop_detected` | Ход агента зациклился: в `messages` после последнего сообщения с ролью `user` накопилось 20 и более ответов с ролью `assistant` без `tool_calls`. Считаются все такие ответы, а не только идущие подряд, ответы с `tool_calls` в счёт не входят. Запрос к модели не уходит, списания нет. При `stream: true` отказ приходит JSON-ответом, поток событий не открывается. Чтобы продолжить, добавьте в `messages` новое сообщение с ролью `user` — счёт начнётся заново |
| 422 | `structured_output_truncated` | Запрос с `response_format` не дал полного JSON: генерация оборвана по `finish_reason: "length"` без обнаруженного повтора либо поле `content` пустое при любой причине завершения и без `tool_calls`. В режиме `json_object` есть исключение — готовый JSON, попавший в служебный канал `reasoning_content`, восстанавливается, и ответ остаётся `200`. Подробнее — [гарантированный JSON-ответ](./json.md) |
| 422 | `structured_output_invalid_json` | Запрос с `response_format` дал непустой ответ, который не разбирается как JSON-объект или массив — текст вокруг объекта, ответ в markdown-ограждении кода, одиночное значение вроде `42`. Полей `param` и `suggestedMaxTokens` в теле нет: увеличение `max_tokens` результат не меняет. В режиме `json_object` действует то же исключение — готовый JSON из служебного канала `reasoning_content` восстанавливается, и ответ остаётся `200`. Подробнее — [гарантированный JSON-ответ](./json.md) |
| 422 | `reasoning_repetition` | Модель зациклилась в рассуждении: повторяла одни и те же фразы и не начала ответ. В синхронном ответе приходит на запросах с `response_format` вместо `structured_output_truncated`, в потоке — событием перед `data: [DONE]` на любом запросе. Повторите запрос с `reasoning_effort: "none"`, больший `max_tokens` не поможет. Подробнее — [гарантированный JSON-ответ](./json.md) |
| 422 | `reasoning_repetition` | Обнаружен повтор в непустом незавершённом JSON при `json_object` или `json_schema` после `finish_reason: "length"`. Проверка терминальная. Это эвристическая диагностика: она может сработать и на законном повторяющемся массиве, которому не хватило бюджета. Проверьте, ожидаемы ли повторы; если да, проверьте лимит токенов, иначе уточните запрос или смените модель. Подсказки отключить рассуждение нет |
| 429 | `rate_limit_exceeded` | Превышен [лимит запросов](./rate-limits.md). Заголовок `X-RateLimit-Scope` указывает уровень — `per-key` или `per-user`. Тот же код приходит, когда ограничил сам кластер моделей: тогда в теле есть поле `providerStatusCode`, а поля `scope` и заголовка `X-RateLimit-Scope` нет, пауза берётся из `Retry-After` |
| 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`). Исходный статус приходит в поле `providerStatusCode` всегда, когда провайдер ответил HTTP-статусом, — в том числе когда поток уже открыт, а провайдер отказал на его установке. Поля нет там, где статуса не было: ошибка пришла кадром из тела уже открытого потока (из тела платформа принимает только статус `429`, такой кадр идёт кодом `rate_limit_exceeded`) или сбой случился при обработке ответа провайдера |
| 502 | `ai_provider_network` | Платформа не смогла соединиться с провайдером или соединение оборвалось до ответа. Поля `providerStatusCode` у этого ответа нет: провайдер не ответил. Повторите запрос |
| 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` в этом ответе — строка. Когда у портала нет оплаченного доступа к AI-моделям, ответ с `reason: "wallet_off"` дополнительно несёт `details.learnMoreUrl` — страницу с описанием подписки или тарифа Битрикс24, в которые входит AI, а поле `message` называет нужный продукт. При других причинах `wallet_off` поля `details.learnMoreUrl` нет. Пока расход укладывается в квоту, поведение эндпоинта не меняется. Сверх квоты, если такой расход для портала разрешён, запросы списываются с денежного баланса портала по базовой цене модели из каталога.

**Бюджет обработки синхронного запроса — около 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)
- [Бот-помощник по сделкам и процессам](/docs/recipes/crm-assistant-bot)

