# Embeddings

> Turn text into vectors with POST /v1/embeddings: models, request, response, pricing and examples.

```text
POST https://api.clonvo.com/v1/embeddings
```

Turns text into vectors for semantic search, retrieval-augmented generation (RAG), clustering and classification. The request and response follow OpenAI’s Embeddings API, so the OpenAI SDKs and frameworks built on them work by changing the base URL. Requests use the same API key, credits, your own provider keys and spending limits as chat completions.

## Models

| Model id | Provider | Dimensions | Max input | Price per 1M input tokens |
| --- | --- | --- | --- | --- |
| `openai/text-embedding-3-small` | OpenAI | 1,536 (1 to 1,536) | 8,192 tokens | $0.02 |
| `openai/text-embedding-3-large` | OpenAI | 3,072 (1 to 3,072) | 8,192 tokens | $0.13 |
| `google/gemini-embedding-2` | Google AI Studio | 3,072 (128 to 3,072) | 8,192 tokens | $0.20 |
| `mistralai/mistral-embed` | Mistral | 1,024 (fixed) | 8,192 tokens | $0.10 |
| `mistralai/codestral-embed` | Mistral | 1,536 (1 to 3,072) | 8,192 tokens | $0.15 |

Prices are each provider’s list price for text input, checked on November 4, 2026. Embedding models have no output price. “Max input” is the most tokens one input may have; longer inputs fail with a `400` from the provider, so split long documents into chunks first.

Embedding models only serve this endpoint: sending one to chat completions returns `400` with the code `embedding_model_not_chat`. They aren’t in the default `GET /v1/models` list, which holds chat models as on OpenRouter. List them with `GET /v1/embeddings/models` or `GET /v1/models?output_modalities=embeddings` (see [Other endpoints](https://clonvo.com/docs/other-endpoints.md#get-v1-models)).

Vectors from different models aren’t comparable. Embed your documents and your queries with the same model and the same `dimensions`.

## Request body

| Parameter | Type | Description |
| --- | --- | --- |
| `model` | string | **Required.** An embedding model id from the table above, such as `openai/text-embedding-3-small`. Aliases and bare slugs work as for chat (see [Models and model ids](https://clonvo.com/docs/models.md)). |
| `input` | string or array of strings | **Required.** The text to embed, or up to 2,048 texts in one request. Strings must not be empty. Arrays of token ids aren’t supported (`400`); send the text instead. |
| `encoding_format` | string | `float` (default) returns each vector as an array of numbers. `base64` returns it as a base64 string of little-endian 32-bit floats, as OpenAI does, which is much smaller. Works with every model. |
| `dimensions` | integer | Shorter vectors, on models that support it (see the table). Must be in the model’s range; a model with a fixed size accepts only that size. |
| `user` | string | An id for your end user. Sent to OpenAI; other providers don’t take it. |
| `provider` | object | **Extension.** `order` and `allow_fallbacks` choose between your own key and credits, as for chat (see [Fallbacks and routing](https://clonvo.com/docs/fallbacks.md)). |

Unknown fields are ignored. Requests over 4 MB are refused with `413`. Fallback `models` aren’t supported here: send one model per request.

## Response

```json
{
  "id": "gen-01M6B2XK7Q4R8S1T3V5W7Y9Z2A",
  "object": "list",
  "data": [
    { "object": "embedding", "index": 0, "embedding": [0.0023, -0.0093, 0.0157] },
    { "object": "embedding", "index": 1, "embedding": [-0.0118, 0.0204, 0.0031] }
  ],
  "model": "openai/text-embedding-3-small",
  "provider": "OpenAI",
  "usage": { "prompt_tokens": 12, "total_tokens": 12, "cost": 0.00000024, "is_byok": false }
}
```

Vectors are shortened here; `text-embedding-3-small` returns 1,536 numbers per input by default.

| Field | Description |
| --- | --- |
| `id` | The request’s generation id, also sent in the `x-clonvo-generation-id` header (errors included). It appears in **Activity** and works with [`GET /v1/generation`](https://clonvo.com/docs/other-endpoints.md#get-v1-generation). |
| `data[]` | One vector per input, in input order. `index` is the input’s position. |
| `model`, `provider` | The model that served the request and its provider. |
| `usage.prompt_tokens`, `usage.total_tokens` | Input tokens, as the provider counted them. Embeddings have no output tokens, so both are the same. |
| `usage.cost` | What the request cost at list price, in USD. |
| `usage.is_byok` | `true` when the request ran on your own provider key. |

## Pricing and billing

A request costs its input tokens times the model’s price per token, as the provider reports them. There’s nothing else: no output tokens and no per-request fee. Billing works as for chat completions:

-   **Your own key first.** With a key for the model’s provider under **Provider keys**, requests run on it and your provider bills you. Their list price counts toward your free BYOK allowance ($25,000 of list-price usage a month on Pay as you go); above it, Clonvo charges 4% of list price from your credits. See [Bring your own keys](https://clonvo.com/docs/byok.md).
-   **Then credits.** Without a key, or if your key is rejected, the request runs on Clonvo’s key and its cost comes out of your credits.
-   **Plans.** On Free, embedding models return `402` like other paid models. Buy credits of any amount to move to Pay as you go.
-   **Limits.** Before calling the provider, Clonvo holds an estimate of the request’s cost against your balance and the API key’s [spending limit](https://clonvo.com/docs/authentication.md), and refuses with `402` when it doesn’t fit. Requests count toward the key’s [request limit](https://clonvo.com/docs/rate-limits.md).

Each request appears in **Activity** with an **Embedding** tag, its input tokens and cost.

## Data

Inputs are never stored for Clonvo’s use. If your organization turned on **Store prompts and responses** (see [Data and privacy](https://clonvo.com/docs/privacy.md)), Clonvo stores each request with its input texts so you can open them in **Activity**, as it does for chat prompts. The vectors it returns are never stored.

## Examples

### curl

```bash
curl https://api.clonvo.com/v1/embeddings \
  -H "Authorization: Bearer $CLONVO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/text-embedding-3-small",
    "input": ["The food was delicious.", "The service was slow."]
  }'
```

### Python (OpenAI SDK)

```python
import os
from openai import OpenAI

client = OpenAI(base_url="https://api.clonvo.com/v1", api_key=os.environ["CLONVO_API_KEY"])

result = client.embeddings.create(
    model="google/gemini-embedding-2",
    input=["How do I reset my password?", "Where can I see my invoices?"],
    dimensions=768,
)
vectors = [item.embedding for item in result.data]
print(len(vectors[0]), result.usage.prompt_tokens)
```

### Node.js (OpenAI SDK)

```js
import OpenAI from "openai";

const client = new OpenAI({ baseURL: "https://api.clonvo.com/v1", apiKey: process.env.CLONVO_API_KEY });

const result = await client.embeddings.create({
  model: "mistralai/codestral-embed",
  input: "function add(a, b) { return a + b; }",
});
console.log(result.data[0].embedding.length);
```

The SDKs ask for `base64` unless you set `encoding_format`, and decode it for you, so you get arrays of numbers either way.

### LangChain

```python
import os
from langchain_openai import OpenAIEmbeddings

embeddings = OpenAIEmbeddings(
    model="openai/text-embedding-3-small",
    base_url="https://api.clonvo.com/v1",
    api_key=os.environ["CLONVO_API_KEY"],
    check_embedding_ctx_length=False,
)
query_vector = embeddings.embed_query("What is our refund policy?")
doc_vectors = embeddings.embed_documents(["Refunds are issued within 14 days.", "Shipping takes 3 to 5 days."])
```

Set `check_embedding_ctx_length=False`: otherwise LangChain sends token ids instead of text, which Clonvo doesn’t accept. Split long documents with a text splitter so each chunk fits the model’s input limit.

## Errors

Embeddings return the same [error shape](https://clonvo.com/docs/errors.md) as chat completions. The ones specific to this endpoint:

| Status | Code | When |
| --- | --- | --- |
| `400` | `model_not_embedding` | `model` is a chat model. Choose an embedding model. |
| `400` | `model_not_found` | `model` isn’t a model on Clonvo. |
| `400` | `invalid_request` | `input` is missing, empty, too long a list, or token ids (`param` says which), or another parameter has the wrong type. |
| `400` | `invalid_dimensions`, `unsupported_parameter` | `dimensions` is outside the model’s range, or the model only returns its fixed size. |
| `402` | `insufficient_credits`, `key_limit_exceeded`, `byok_fee_requires_credits` | The request can’t be paid for, as for chat. Send fewer or shorter inputs, add credits or raise the key’s limit. |
| `413` | `request_too_large` | The body is over 4 MB. Split the inputs over several requests. |

An input longer than the model’s limit comes back from the provider as a `400` with the provider’s message. `429`, `5xx` and timeout errors on your own key are retried on Clonvo credits when you allow it, as for chat.
