For AI agents: markdown of this page — /docs-content-en/ai/embeddings.md documentation index — /llms.txt
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.
Request fields (body)
| Field | Type | Req. | Default | Description |
|---|---|---|---|---|
model |
string | yes | — | Identifier of a model that supports embeddings. List: GET /v1/models |
input |
string | string[] | yes | — | Text to vectorize: a single string or an array of 1 to 64 strings. One vector is returned per string. An empty string, an empty array, and an array longer than 64 strings are rejected with 400 |
encoding_format |
string | no | float |
Format of the vector values: float or base64 |
dimensions |
integer | no | — | Desired vector dimensionality. For bitrix/embeddings — an integer from 32 to 4096: the vector is cut to that many leading values and re-normalised to unit length. A value outside the range is rejected with 400 invalid_request. Other models receive the parameter unchanged and answer by their own rules |
Examples
curl — personal key
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
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
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
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. With encoding_format: base64 it arrives as a string |
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, and the vector arrives re-normalised to unit length.
{
"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:
{
"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 |
| 400 | invalid_request |
dimensions outside the 32…4096 range was passed for bitrix/embeddings. The response carries a param field set to dimensions. The request was not executed and nothing was charged |
| 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 |
| 402 | company_budget_exhausted |
The monthly company spend budget set by the portal administrator is exhausted. The scope field names the budget that was hit: USER — the caller's own budget, PORTAL — the budget of the whole portal. The canRequest field tells whether an increase can be requested: true for a personal budget, false for the portal one, which only an administrator raises. The rejection arrives only on calls that draw on the portal balance. Calls inside the tariff quota and on your own key keep working |
| 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 |
| 429 | ai_provider_cooldown |
The model cluster is temporarily unavailable and the platform holds a pause so retries do not pile onto it. The request was not executed and nothing was charged — retry it after the number of seconds in Retry-After. This response carries neither X-RateLimit-Scope nor X-AI-Admission |
| 502 | ai_provider_unavailable |
The external provider answered with an error (401/403/5xx). The original status arrives in the providerStatusCode field when the provider answered the request with an HTTP status; a failure while processing the provider's response (for example, a vector shorter than the requested dimensions) carries no such field |
| 502 | ai_provider_network |
The platform could not connect to the provider, or the connection dropped before a response. This response carries no providerStatusCode: the provider never answered. Retry the request |
| 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) |
The full list of common API errors — Errors.
Known specifics
Error codes come in lowercase. Most error bodies use the raw OpenAI format { "error": { "message", "type", "code" } }, without a success field. The 402 company_budget_exhausted rejection uses the same format — the scope and canRequest fields sit inside the same error object. Only quota and pacing rejections — 402 ai_quota_exhausted and 429 ai_pacing_limited — and an unexpected server error 5xx, whose code is written in upper case, arrive in the { "success": false, "error": { … } } envelope. 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.
Response latency is not guaranteed — neither for a single text nor for an input array. It can vary from call to call, and several requests with an input array sent in a row may respond increasingly slower one after another. The dimensions parameter does not affect response speed. Add a pause between such requests and do not rely on the input array in an interactive scenario.
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. The current input price of every model comes from GET /v1/models — read it there rather than from a fixed number in the documentation.
The dimensionality can be reduced. The bitrix/embeddings model is built so that the meaningful part of a vector is concentrated at its start: keeping the first k values and re-normalising the vector to unit length left the ordering of search results unchanged in our checks, down to the shortest widths. This is a property of the model rather than a platform guarantee — measure it on your own data. The dimensions parameter does this on the platform side; you can get the same result yourself by cutting the vector and dividing every value by the length of the resulting segment. Re-normalising is mandatory: a raw segment is shorter than one (for a 256-value vector the length is about 0.26), and without that step a dot product stops matching cosine similarity and comparisons against previously stored vectors drift.
Sensible values are 256, 512, 1024, 2048; these are reference points rather than the only accepted ones — any integer from 32 to 4096 works, including 1536 and 2000. The shorter the vector, the smaller the margin between a relevant result and a close competitor, so choose the dimensionality by measuring on your own data.
A smaller dimensionality does not make a request cheaper or faster. The model still computes the full vector and the platform cuts it in the response: input-token usage and processing time do not change. The saving is on your side — less index storage, less memory and a faster search.
Vectors of different dimensionality must not be mixed in one similarity index. A 256-value and a 1024-value vector live in different spaces, and distances between them are meaningless. If you change the dimensionality, rebuild the index as a whole.