
## Создать эмбеддинги

`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 | нет | — | Желаемая размерность вектора. Для `bitrix/embeddings` — целое от 32 до 4096: вектор обрезается до этого числа первых значений и заново приводится к единичной длине. Значение вне диапазона отклоняется с `400 invalid_request`. Остальные модели получают параметр без изменений и отвечают по своим правилам |

## Примеры

### 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[] | Значения вектора. При `encoding_format: base64` приходит строкой |
| `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`, неверное тело запроса |
| 400 | `invalid_request` | Для `bitrix/embeddings` передан `dimensions` вне диапазона 32…4096. Ответ несёт поле `param` со значением `dimensions`. Запрос не выполнялся, списания нет |
| 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` — см. «Известные особенности» ниже |
| 402 | `company_budget_exhausted` | Исчерпан месячный бюджет расхода компании, который задаёт администратор портала. Поле `scope` называет пробитый бюджет: `USER` — личный бюджет вызывающего, `PORTAL` — бюджет всего портала. Поле `canRequest` говорит, можно ли запросить увеличение: у личного бюджета `true`, у портального `false` — его поднимает только администратор. Отказ приходит только на вызовах, которые списывают средства с баланса портала. Вызовы внутри тарифной квоты и на собственном ключе продолжают работать |
| 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`. В этом же формате приходит отказ `402 company_budget_exhausted` — поля `scope` и `canRequest` лежат внутри того же объекта `error`. В конверте `{ "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`, поэтому платится только вход. Действующая цена входа для каждой модели приходит в [`GET /v1/models`](/docs/ai/models/list) — сверяйтесь с ним, а не с фиксированным значением в документации.

**Размерность можно уменьшить.** Модель `bitrix/embeddings` устроена так, что осмысленная часть вектора сосредоточена в его начале: если оставить первые `k` значений и заново привести вектор к единичной длине, порядок результатов поиска на наших проверках не менялся вплоть до самых коротких размерностей. Это свойство модели, а не гарантия платформы — на своих данных результат нужно замерить. Параметр `dimensions` делает это на стороне платформы; тот же результат можно получить самостоятельно, обрезав вектор и поделив каждое значение на длину получившегося отрезка. Приводить к единичной длине обязательно: сырой отрезок короче единицы (у вектора на 256 значений длина около 0,26), и без этого шага скалярное произведение перестанет совпадать с косинусной близостью, а сравнение с ранее сохранёнными векторами поедет.

Разумные значения — 256, 512, 1024, 2048; это ориентиры, а не единственные допустимые: подойдёт любое целое от 32 до 4096, включая 1536 и 2000. Чем короче вектор, тем меньше запас между релевантным результатом и близким по смыслу конкурентом, поэтому размерность стоит выбирать замером на своих данных.

**Меньшая размерность не делает запрос дешевле или быстрее.** Модель всё равно считает полный вектор, а платформа обрезает его уже в ответе: расход по входным токенам и время обработки не меняются. Экономия возникает на вашей стороне — меньше места под индекс, меньше памяти и быстрее сам поиск.

**В одном индексе близости нельзя смешивать векторы разной размерности.** Векторы на 256 и на 1024 значения лежат в разных пространствах, и расстояния между ними бессмысленны. Меняете размерность — перестраивайте индекс целиком.

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

- [Список моделей](/docs/ai/models/list)
- [Создать чат-комплишен](/docs/ai/chat/completions)
- [AI-квота компании](/docs/ai/consumption/quota)
- [AI Router](/docs/ai)
