# Embeddings

> Turn text, token arrays, images and PDFs into vectors with POST /embeddings for search, clustering, deduplication and retrieval.

Source: https://0.0.0.0:3000/docs/multimodal/embeddings
Documentation index: https://0.0.0.0:3000/docs/llms.txt

`POST /embeddings` follows the OpenAI request and response shapes, so the official SDKs work after you change the base URL and key. Batch up to 2,048 inputs per request, choose float or compact base64 output, and embed images and PDFs with multimodal models.

```endpoint
POST /api/v1/embeddings
```

Text inputs preserve JSON-escaped control characters, including terminal escapes. Input and request size limits still apply.

Each input accepts at most 4 MiB of combined text in UTF-8 bytes. A multimodal
input accepts up to 128 content parts across text, images, PDFs and audio, subject
to media size limits and the selected model's supported inputs.

## Create embeddings

```request
{
  "method": "POST",
  "path": "/embeddings",
  "body": {
    "model": "author/embedding-model",
    "input": [
      "How do I reset my password?",
      "Steps to recover a locked account",
      "Quarterly revenue grew by 12 percent"
    ]
  }
}
```

The response holds one vector per input, in input order. Real vectors have hundreds or thousands of dimensions:

```json title="Response"
{
  "id": "embd-3f0c6a5e-9d7b-4c1e-8a2f-6b5d4e3c2a10",
  "object": "list",
  "model": "author/embedding-model",
  "data": [
    { "object": "embedding", "index": 0, "embedding": [0.0213, -0.0447, 0.0182, 0.0031] },
    { "object": "embedding", "index": 1, "embedding": [0.0198, -0.0402, 0.0211, -0.0007] },
    { "object": "embedding", "index": 2, "embedding": [-0.0315, 0.0126, -0.0088, 0.0402] }
  ],
  "usage": {
    "prompt_tokens": 21,
    "total_tokens": 21,
    "cost": 0.000002
  }
}
```

:::fields Response body
- `id` `string` — `embd-` followed by the generation ID, which also appears in the `X-Generation-Id` header.
- `object` `"list"` — Always `list`.
- `model` `string` — The canonical model ID that served the request.
- `data` `object[]` — One entry per input item, sorted by `index`.
  - `object` `"embedding"` — Always `embedding`.
  - `index` `integer` — Position of the input item, from 0.
  - `embedding` `number[] | string` — The vector: an array of numbers for `float`, or a base64 string for `base64`.
- `usage` `object` — Usage for the request.
  - `prompt_tokens` `integer` — Input tokens for the whole batch.
  - `total_tokens` `integer` — Equal to `prompt_tokens`; embeddings produce no output tokens.
  - `cost` `number` — Total charge in your key's currency.
:::

## Request fields

:::fields Request body
- `model` `string` required — Canonical ID of an embedding model, such as `author/embedding-model`.
- `input` `string | string[] | integer[] | integer[][] | ContentPart[][]` required — What to embed. See [Input formats](#input-formats).
- `dimensions` `integer` — Length of the returned vectors, from 1 to 65,536, for models that can shorten their output.
- `encoding_format` `string` default `float` — `float` for arrays of numbers, or `base64` for packed little-endian float32 vectors.
- `input_type` `string` — Task hint, such as a query or document type. Accepted values depend on the model; at most 128 bytes.
- `provider` `object` — Routing preferences, as for chat. See [Provider routing](/docs/routing/provider-routing).
:::

Other fields, including `user`, are rejected with 400.

## Input formats

| `input` shape | Vectors returned | Limits |
| --- | --- | --- |
| A string | 1 | Non-empty, at most 4 MiB |
| An array of strings | One per string | 1–2,048 strings, each non-empty and at most 4 MiB |
| An array of token IDs (non-negative integers) | 1 | At least one token |
| An array of token-ID arrays | One per inner array | 1–2,048 arrays |
| An array of content-part arrays | One per inner array | 1–2,048 items |

The first element decides how an array is read, so don't mix strings with arrays in one `input`. Token IDs must come from the model's own tokenizer.

### Multimodal inputs

Multimodal embedding models place text, images and documents in one vector space. Each item is an array of content parts, using the same `text`, `image_url`, `file` and `input_audio` parts as [chat](/docs/multimodal/overview#content-parts), and all parts of one item produce one vector:

```request
{
  "method": "POST",
  "path": "/embeddings",
  "body": {
    "model": "author/multimodal-embedding-model",
    "input": [
      [
        { "type": "text", "text": "Red trail running shoe, side view" },
        { "type": "image_url", "image_url": { "url": "https://example.com/images/shoe.jpg" } }
      ],
      [
        { "type": "text", "text": "Waterproof hiking boot" }
      ]
    ]
  }
}
```

Wrap a single multimodal item in an outer array as well. Media follows the [chat media rules](/docs/multimodal/overview#sending-media): at most 8 MiB per item and 24 MiB in total. A request with images, PDFs or audio needs an endpoint whose `input_modalities` include `image`, `file` or `audio`. Video is rejected with 400.

## Optional controls and routing

`dimensions`, `input_type` and `encoding_format: "base64"` are forwarded to the selected endpoint. To route only to endpoints that declare every one you set in their `supported_parameters`, add `provider.require_parameters: true`; if none does, the request fails with 503 `provider_unavailable`:

```request
{
  "method": "POST",
  "path": "/embeddings",
  "body": {
    "model": "author/embedding-model",
    "input": "How do I reset my password?",
    "dimensions": 256,
    "input_type": "search_query",
    "provider": { "require_parameters": true }
  }
}
```

`encoding_format: "float"`, or leaving it unset, adds no requirement.

## Use the OpenAI SDK

:::code-group
```python title="Python"
import os

from openai import OpenAI

client = OpenAI(base_url="https://api.numes.ai/api/v1", api_key=os.environ["NUMES_API_KEY"])

response = client.embeddings.create(
    model="author/embedding-model",
    input=["How do I reset my password?", "Steps to recover a locked account"],
    encoding_format="float",
)
for item in response.data:
    print(item.index, len(item.embedding))
```

```typescript title="TypeScript"
import OpenAI from "openai";

const client = new OpenAI({ baseURL: "https://api.numes.ai/api/v1", apiKey: process.env.NUMES_API_KEY });

const response = await client.embeddings.create({
  model: "author/embedding-model",
  input: ["How do I reset my password?", "Steps to recover a locked account"],
  encoding_format: "float",
});
for (const item of response.data) console.log(item.index, item.embedding.length);
```
:::

:::note The SDKs request base64 unless you say otherwise
Recent OpenAI SDKs send `encoding_format: "base64"` when you omit it and decode the vectors for you. Under `provider.require_parameters: true`, that also requires endpoints that declare `encoding_format`, so pass `encoding_format="float"` explicitly, as above.
:::

## Base64 vectors

With `encoding_format: "base64"`, each `embedding` is a base64 string of little-endian 32-bit floats, considerably smaller than JSON numbers. Decode it like this:

:::code-group
```python title="Python"
import base64

import numpy as np

def decode_embedding(value: str) -> np.ndarray:
    return np.frombuffer(base64.b64decode(value), dtype="<f4")
```

```typescript title="TypeScript"
function decodeEmbedding(value: string): Float32Array {
  const bytes = Buffer.from(value, "base64");
  const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
  const vector = new Float32Array(bytes.byteLength / 4);
  for (let i = 0; i < vector.length; i++) vector[i] = view.getFloat32(i * 4, true);
  return vector;
}
```
:::

## Find embedding models

```request
{
  "method": "GET",
  "path": "/models",
  "query": { "output_modalities": "embeddings" }
}
```

Embedding models have `"embeddings": true` and `embeddings` in `architecture.output_modalities`. To see which endpoints accept image or file input or support `dimensions`, `input_type` or `encoding_format`, read `input_modalities` and `supported_parameters` in [`GET /models/{author}/{slug}/endpoints`](/docs/api-reference/models/list-model-endpoints).

Vectors from different models aren't comparable. Store the model ID with every vector, and re-embed your corpus when you change models. Compare vectors with cosine similarity, or store them in a vector database for nearest-neighbour search.

## Batching and limits

| Limit | Value |
| --- | --- |
| Items per request | 2,048 |
| One string | 4 MiB |
| Request body | 10 MiB |
| Request timeout | 10 minutes |
| Media | 8 MiB per item, 24 MiB per request |

- **Keep each input within the model's context length.** The limit applies per input, not to the whole batch.
- **Split very large batches.** The funds held before a batch runs grow with the number of items, and its tokens count toward your key's token rate limit, so one huge batch can fail with 402 or 429 where several smaller ones pass. See [Limits](/docs/api-reference/limits).
- **Match results by `index`** to map each vector back to its input.
- **Use base64 for large batches** to shrink the response.
- **Use a new `X-Request-Id` for each retry.** A reused request ID is rejected with 400.

## Billing

Embeddings are billed by input at the endpoint's rates, including any per-request and media prices; there are no output tokens. `usage.cost` is the exact total in your key's currency, and [`GET /generation`](/docs/api-reference/chat/get-generation) is the authoritative record. See [Usage accounting](/docs/account/usage-accounting).

## Errors

| Status | `error_type` | Cause |
| --- | --- | --- |
| 400 | `invalid_request` | Empty or malformed `input`, more than 2,048 items, `dimensions` outside 1–65,536, unknown `encoding_format`, video parts, invalid media, unknown field |
| 402 | `insufficient_credits` | Balance or key limit can't cover the held amount |
| 408 | `timeout` | The request didn't finish within 10 minutes |
| 413 | `payload_too_large` | Body larger than 10 MiB |
| 429 | `rate_limited` | Key or account rate limit; wait for `Retry-After` |
| 503 | `provider_unavailable` | No eligible endpoint for the model, its input modalities, required parameters or batch size |

## Next steps

:::cards
- {image} [Image inputs](/docs/multimodal/images) The image part used in multimodal embedding items.
- {file} [PDFs and files](/docs/multimodal/pdfs) The file part used for PDF embeddings.
- {network} [Provider routing](/docs/routing/provider-routing) Require parameters and choose endpoints.
- {code} [API reference](/docs/api-reference/embeddings/create-embedding) Full schema for `POST /embeddings`.
:::
