## Create embeddings

`POST /v1/embeddings`

Converts text into a vector representation. Vectors are needed for semantic search, clustering, duplicate detection, and finding similar CRM cards. The request and response format is compatible with the OpenAI API. There is no streaming.

Embeddings are supported only by models whose `capabilities.embeddings` field equals `true` in [`GET /v1/models`](/docs/ai/models/list).

## Request fields (body)

| Field | Type | Req. | Default | Description |
|------|-----|:-----:|-----------|---------|
| `model` | string | yes | — | Identifier of a model that supports embeddings. List: [`GET /v1/models`](/docs/ai/models/list) |
| `input` | string \| string[] | yes | — | Text to vectorize: a single string or an array of strings. One vector is returned per string. An empty string and an empty array are rejected with `400` |
| `encoding_format` | string | no | `float` | Format of the vector values: `float` or `base64` |
| `dimensions` | integer | no | — | Desired vector dimensionality. Applies only to models that support it |

## Examples

### curl — personal key

```bash
curl -X POST https://vibecode.bitrix24.com/v1/embeddings \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "bitrix/embeddings",
    "input": "We want a CRM for 50 users"
  }'
```

### curl — OAuth application

```bash
curl -X POST https://vibecode.bitrix24.com/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": "We want a CRM for 50 users"
  }'
```

### JavaScript — personal key

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/embeddings', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'bitrix/embeddings',
    input: ['First text', 'Second text'],
  }),
})

const result = await res.json()
console.log(result.data.length)        // 2 — one vector per string
console.log(result.data[0].embedding)  // [0.0203, 0.0034, ...]
```

### JavaScript — OAuth application

```javascript
const res = await fetch('https://vibecode.bitrix24.com/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: ['First text', 'Second text'],
  }),
})

const result = await res.json()
```

## Response fields

The response comes in raw OpenAI format, without the `success` and `data` wrapper.

| Field | Type | Description |
|------|-----|---------|
| `object` | string | Always `list` |
| `data` | array | Array of vectors, one per `input` string |
| `data[].object` | string | Always `embedding` |
| `data[].embedding` | number[] | The vector values |
| `data[].index` | number | Position of the string in the original `input` |
| `model` | string | The model that processed the request |
| `usage.prompt_tokens` | number | Input text tokens. Usage is counted by them |
| `usage.completion_tokens` | number | Always `0` — embeddings produce no response tokens |
| `usage.total_tokens` | number | Equals `prompt_tokens` |

## Response example

The first three vector values are shown. The full dimensionality depends on the model — for `bitrix/embeddings` it is 4096 values.

```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
  }
}
```

## Error response example

`501 embeddings_unsupported` — the model does not support embeddings:

```json
{
  "error": {
    "message": "Model \"bitrix/bitrixgpt-5.5\" does not support embeddings.",
    "type": "server_error",
    "code": "embeddings_unsupported"
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|---------|
| 400 | `invalid_request` | Invalid parameters — empty `input`, malformed request body |
| 404 | `ai_model_not_found` | Model not found or disabled |
| 501 | `embeddings_unsupported` | The model or provider does not support embeddings |
| 402 | `ai_credentials_not_configured` | No provider credentials for the model — connect your own key |
| 402 | `insufficient_balance` | Insufficient funds for the paid model |
| 402 | `ai_quota_exhausted` | The Bitrix24 account's monthly AI quota is exhausted. The `reason` field distinguishes the case: `breaker` — the hourly over-quota spending breaker fired, `wallet_empty` — the quota is exhausted and the account balance has no funds, `wallet_off` — over-quota spend is not available for this Bitrix24 account. `resetAt` — the moment when requests will start passing again, may be absent for `wallet_off`. In the `wallet_empty` case the response may additionally carry a `hint` string and a `topupUrl` link — see "Known specifics" below |
| 403 | `scope_missing` | The API key is missing the `vibe:ai` scope |
| 429 | `ai_congested` | The AI cluster pool is overloaded. The request was not executed, nothing was charged, retry it per the `Retry-After` header. The response carries the `X-AI-Admission: shed` header, not `X-RateLimit-Scope` |
| 400 | `ai_provider_rejected` | The provider rejected the request itself (responded `400` or `422`). Retrying it unchanged will not help |
| 502 | `ai_provider_unavailable` | The external provider returned `401`/`403`/`5xx` or a network error |
| 429 | `ai_pacing_limited` | A daily or weekly pacing window is exceeded. This is not quota exhaustion — repeat the request after the time in the `Retry-After` header. See [Pacing (day/week smoothing)](/docs/ai/consumption/quota#pacing-day-week-smoothing) |

The full list of common API errors — [Errors](/docs/errors).

## Known specifics

**Error codes come in lowercase.** Most error bodies use the raw OpenAI format `{ "error": { "message", "type", "code" } }`, without a `success` field. Two cases arrive in the `{ "success": false, "error": { … } }` envelope instead: quota and pacing rejections (`402 ai_quota_exhausted`, `429 ai_pacing_limited`), and an unexpected server error `5xx`, whose code is written in upper case. A handler must accept both envelopes.

**The `input` array preserves order.** The vector `data[i]` corresponds to the string `input[i]`, and the `data[].index` field duplicates this position — you can use it to match the result after parallel processing.

**The processing budget for a request is about 850 seconds.** Once the budget runs out, `503 ai_provider_timeout` is returned. This response deliberately carries no `Retry-After` header: repeating the same request would hit the same budget. Split the `input` array into smaller parts.

**The top-up hint in a `402 ai_quota_exhausted` response.** Only in the `reason: "wallet_empty"` case may the response additionally carry a `hint` string and a `topupUrl` link to top up the balance. Both fields appear when enforced quota control and the top-up hint are enabled on the platform, so read them as optional. The `hint` field in this response is a string.

**Usage is counted only by input tokens.** The `usage.completion_tokens` field is always `0`, so you pay only for the input. For the `bitrix/embeddings` model the input price is zero.

## See also

- [Models list](/docs/ai/models/list)
- [Create a chat completion](/docs/ai/chat/completions)
- [Company AI quota](/docs/ai/consumption/quota)
- [AI Router](/docs/ai)
