Create embeddings
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. 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.
/v1/embeddingsAuthentication
Send your API key in a request header:
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; to set the LYROUTER_API_KEY environment variable, see Your first model call.
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. Each model returned has an api_types field; a model whose list includes embeddings can call this endpoint:
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; to filter rerank models, see Rerank documents.
Request examples
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"
}'
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)
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.
{
"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 }
}
{
"error": {
"message": "This model does not support the embeddings API",
"type": "invalid_request_error",
"code": "unsupported_model_api"
}
}
{
"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 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. For how to estimate costs, see Estimating costs and cache pricing.
Gateway behavior
- Requests forwarded unchanged: the gateway only replaces
modelwith 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, 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 400This 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; modelis 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.
- the request has no
- Virtual models and Auto: virtual models 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/autoare 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 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 |
- 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) does not return 400unsupported_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 404Unsupported model `<model>` for OpenAI compatibility mode.after about 60 seconds, witherror.codemodel_not_supported. - The gateway resolves the model before it checks
Content-Type: whenmodelis missing or the model is not enabled, a model-related error comes first (400missing_model, 403model_not_available); only with a valid model do you get 400unsupported content-type: …. - For 401 / 403 authentication issues, see 401 / 403: authentication and access; for 429, see 429: rate limits and quotas. For the full list, see Errors and request identifiers.