# Create embeddings

Source: https://platform.lyrouter.com/ai_gateway/docs/embeddings/en
Last updated: 2026-10-19

Converts one or more pieces of text into vectors, for retrieval-augmented generation (RAG), semantic search and deduplication; to sort documents by relevance to a query, use [Rerank documents](https://platform.lyrouter.com/ai_gateway/docs/rerank/en). The endpoint uses the OpenAI Embeddings API format: the OpenAI SDK's `client.embeddings.create()` works once you set the Base URL to `https://api.lyrouter.com/v1`. Requests and responses are JSON, and streaming is not supported. The gateway only replaces `model` with the provider's real model name and forwards the other fields unchanged, so parameters and response formats follow the provider the model belongs to.

`POST /v1/embeddings`

## Authentication

Send your API key in a request header:

```text
Authorization: Bearer <API Key>
```

`Bearer` is case-sensitive. You can use `x-api-key: <API Key>` instead; when both are present, only `Authorization` is read. Create API keys on the workspace's **API Keys** page. Your API key is used only to authenticate with LYRouter and is never forwarded to the upstream provider. See [Base URLs and authentication](https://platform.lyrouter.com/ai_gateway/docs/call-gateway/en); to set the `LYROUTER_API_KEY` environment variable, see [Your first model call](https://platform.lyrouter.com/ai_gateway/docs/quickstart/en).

## Headers

| Header | Required | Description |
| --- | --- | --- |
| `Content-Type` | Yes | `application/json`; other types return 400 |

## Request body

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `model` | string | Yes | Embedding model ID; see "Choosing a model" below. Always specify it: when it is omitted, the workspace's Default Model is used, which is usually a chat model, and requests that land on it return 400 `unsupported_model_api` or an upstream error; see "Gateway behavior" below |
| `input` | string \| array | Yes | A piece of text, or an array of texts (to generate several vectors at once). The number of items per request and the length limit per item are set by the provider |
| `encoding_format` | string | No | `float` (array of numbers) or `base64`. Passed through to the upstream; support depends on the model |
| `dimensions` | integer | No | Dimensions of the output vectors. Passed through to the upstream; whether it takes effect depends on the model |
| `user` | string | No | End-user identifier. Passed through to the upstream; whether it takes effect depends on the model |

Fields not listed in the table are forwarded unchanged to the upstream; whether they take effect depends on the model.

### Choosing a model

The embedding models you can use are those in your workspace's model marketplace: search the model marketplace for keywords such as `embedding`, then copy the model ID to replace `MODEL_ID` in the examples.

You can also filter with [`GET /v1/models`](https://platform.lyrouter.com/ai_gateway/docs/models/en). Each model returned has an `api_types` field; a model whose list includes `embeddings` can call this endpoint:

```bash
curl -s https://api.lyrouter.com/v1/models \
  -H "Authorization: Bearer $LYROUTER_API_KEY" \
  | jq -r '.data[] | select((.api_types // []) | index("embeddings")) | .id'
```

Models that do not declare `api_types` do not appear in the filtered result; confirm them in the model marketplace. For field descriptions, see [List models](https://platform.lyrouter.com/ai_gateway/docs/models/en); to filter rerank models, see [Rerank documents](https://platform.lyrouter.com/ai_gateway/docs/rerank/en).

## Request examples

**Request examples**

cURL:
```bash
curl https://api.lyrouter.com/v1/embeddings \
  -H "Authorization: Bearer $LYROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "MODEL_ID",
    "input": ["LYRouter is a trusted model service and token governance platform", "Call many models with one API key"],
    "encoding_format": "float"
  }'
```

Python:
```python
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["LYROUTER_API_KEY"],
    base_url="https://api.lyrouter.com/v1",
)
result = client.embeddings.create(
    model="MODEL_ID",
    input=["LYRouter is a trusted model service and token governance platform", "Call many models with one API key"],
    encoding_format="float",
)
for item in result.data:
    print(item.index, len(item.embedding))
print(result.usage)
```

Node.js:
```js
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.LYROUTER_API_KEY,
  baseURL: "https://api.lyrouter.com/v1",
});
const result = await client.embeddings.create({
  model: "MODEL_ID",
  input: ["LYRouter is a trusted model service and token governance platform", "Call many models with one API key"],
  encoding_format: "float",
});
for (const item of result.data) {
  console.log(item.index, item.embedding.length);
}
console.log(result.usage);
```

When `encoding_format` is not specified, the official OpenAI SDK requests `base64` and decodes it locally. If the upstream does not support `base64` and returns an error, pass `encoding_format="float"` explicitly as in the example above.

## Response

A successful request returns a `list` object whose `data` holds one vector per input; an error returns an `error` object. The 200 example below is a typical response from an OpenAI-compatible provider (vectors truncated); the 400 means the request landed on a model that does not support the embeddings endpoint (usually the Default Model; see "Gateway behavior" below); the 403 means the model is not enabled in this workspace and the workspace has no Default Model.

**Response examples**

200:
```json
{
  "object": "list",
  "data": [
    { "object": "embedding", "index": 0, "embedding": [0.0123, -0.0456, 0.0789] },
    { "object": "embedding", "index": 1, "embedding": [-0.0211, 0.0334, 0.0102] }
  ],
  "model": "MODEL_ID",
  "usage": { "prompt_tokens": 19, "total_tokens": 19 }
}
```

400:
```json
{
  "error": {
    "message": "This model does not support the embeddings API",
    "type": "invalid_request_error",
    "code": "unsupported_model_api"
  }
}
```

403:
```json
{
  "error": {
    "message": "Model is not available in the model plaza",
    "type": "access_denied",
    "code": "model_not_available"
  }
}
```

| Field | Description |
| --- | --- |
| `data[].index` | Position in the `input` array; align results by it rather than relying on the order returned |
| `data[].embedding` | The vector. A Base64 string when `encoding_format` is `base64` |
| `model` | Model name returned by the upstream, which may be written differently from the model ID in the request; the model actually used is the one shown in "Model (actual)" in the logs |
| `usage.prompt_tokens` | Input token count for this call, which is the billed quantity. Recorded in the [logs](https://platform.lyrouter.com/ai_gateway/docs/logs/en) as "Input (cache miss)", with "Output", "Input (cache hit)" and "Explicit cache write" all 0 |
| `usage.total_tokens` | Same as `prompt_tokens` |

### Billing

Billed by input tokens, taken from `usage.prompt_tokens` in the response. Unit prices are those shown in the model marketplace, and the actual cost of each call is in the [logs](https://platform.lyrouter.com/ai_gateway/docs/logs/en). For how to estimate costs, see [Estimating costs and cache pricing](https://platform.lyrouter.com/ai_gateway/docs/estimate/en).

## Gateway behavior

- **Requests forwarded unchanged**: the gateway only replaces `model` with the channel's real model name and forwards the other fields unchanged (for calls through a virtual model, see below). The gateway re-encodes the JSON: object keys are sorted into a fixed order, and numbers keep at most 14 significant digits.
- **Channel fallback**: when a model has several channels, the gateway tries them in turn according to the workspace's [routing strategy](https://platform.lyrouter.com/ai_gateway/docs/routing/en), moving to the next channel when one fails.
- **Default Model fallback**: when the workspace has a Default Model set in Smart routing, the three cases below land on the Default Model. The Default Model is usually a chat model, so you get an error instead of the result you expected (when the Default Model declares `api_types`, the gateway returns 400 `This model does not support the embeddings API`; when it does not, the request is forwarded to the upstream and the upstream returns the error; see "Common errors" below):
  - the request has no `model`;
  - `model` is misspelled, or the model is not enabled in this workspace;
  - every channel of the model failed. In this case the upstream's real error is replaced by the Default Model's error; check the reason for each earlier attempt under "Upstream call attempts" in the log details.
- **Virtual models and Auto**: [virtual models](https://platform.lyrouter.com/ai_gateway/docs/presets/en) can be used with this endpoint, provided that every model in the virtual model's model list is an embedding model. A virtual model's system prompt is not injected, but its inference params are merged into the request body by field name, so do not set inference params on virtual models used for embeddings. The candidates of [`lyrouter/auto`](https://platform.lyrouter.com/ai_gateway/docs/auto/en) are chat models; do not use it with this endpoint. The gateway currently does not reject such requests: the request hangs for about 2 minutes and then returns HTTP 200 with the upstream's native error as the body (such as `{"vectors":null,"base_resp":{"status_code":2013,...}}`) instead of a list of vectors, so a program that checks only the status code mistakes it for success; over HTTP/2 the connection may also drop midway.
- **Guardrails**: bans, Model access and Client access in [guardrails](https://platform.lyrouter.com/ai_gateway/docs/guardrails/en) apply as usual; Sensitive data, Prompt injection and Intent security detection do not apply to this endpoint.

## Common errors

Error responses take the form `{"error":{"message":"...","type":"...","code":"..."}}`; only some errors include `code`.

| Status code | `error.message` | `error.code` | Cause and fix |
| --- | --- | --- | --- |
| 400 | `This model does not support the embeddings API` | `unsupported_model_api` | The model used declares `api_types` and does not support the embeddings endpoint, usually because the request landed on the Default Model; see "Default Model fallback" above. Specify the correct embedding model ID |
| 400 | `you must provide a model parameter` | `missing_model` | No `model` was given and the workspace has no Default Model |
| 400 | `unsupported content-type: <type>, only application/json is supported` | — | `Content-Type` is not JSON. The response body is a single line of plain text, but the `Content-Type` response header is currently `application/json`, so check whether the body is JSON before parsing it |
| 403 | `Model is not available in the model plaza` | `model_not_available` | The model is not enabled in this workspace and no Default Model is set. Ask an administrator to enable it in the model marketplace, or use a model that is enabled |
| 503 | `all routed candidates exhausted` | `no_route_candidate` | No channel can serve this request; see [Unavailable models](https://platform.lyrouter.com/ai_gateway/docs/unavailable/en) |

- Errors such as input that is too long or too many items are returned by the upstream provider; the status code and error text come from the upstream.
- Calling this endpoint with a chat model that does not declare `api_types` (see [List models](https://platform.lyrouter.com/ai_gateway/docs/models/en)) does not return 400 `unsupported_model_api`: the request is forwarded to the upstream, which returns the error, possibly after a long wait. For example, one chat model returned the upstream's 404 ``Unsupported model `<model>` for OpenAI compatibility mode.`` after about 60 seconds, with `error.code` `model_not_supported`.
- The gateway resolves the model before it checks `Content-Type`: when `model` is missing or the model is not enabled, a model-related error comes first (400 `missing_model`, 403 `model_not_available`); only with a valid model do you get 400 `unsupported content-type: …`.
- For 401 / 403 authentication issues, see [401 / 403: authentication and access](https://platform.lyrouter.com/ai_gateway/docs/auth-errors/en); for 429, see [429: rate limits and quotas](https://platform.lyrouter.com/ai_gateway/docs/rate-errors/en). For the full list, see [Errors and request identifiers](https://platform.lyrouter.com/ai_gateway/docs/errors/en).
