# Embeddings

> Generate vector embeddings using /v1/embeddings, including the Modal EmbeddingGemma 2 experiment.

Canonical: https://ai-gateway.sassmaker.com/docs/embeddings

## Endpoint

```
POST /v1/embeddings
```

## Request Body

| Field | Type | Required | Description |
|---|---|---|---|
| `model` | string | **yes** | Embedding model to use. There is no default — you must specify a model. See [supported models](https://ai-gateway.sassmaker.com/docs/embeddings#supported-models) below. |
| `input` | string \| string[] | **yes** | Text to embed. Pass a single string or an array of strings for batch embedding. |
| `encoding_format` | string | no | Output format. Currently `"float"` is supported. |
| `dimensions` | number | no | Number of dimensions for the output vector. Supported by select models. |
| `task` | string | no | Modal models only. Defaults to `retrieval_document`. Use `retrieval_query` for searches. |
| `project_id` | string | **yes** | Project attribution, or supply the `x-gateway-project-id` header. |

:::caution[Model is required]
Unlike the chat endpoint, `model` has no `"auto"` default for embeddings. You must explicitly choose a model that matches your use case — different models are not interchangeable as their vector spaces are incompatible.
:::

## Supported Models

| Provider | Example Models | Notes |
|---|---|---|
| **Cloudflare Workers AI** | `@cf/baai/bge-small-en-v1.5`, `@cf/baai/bge-base-en-v1.5`, `@cf/baai/bge-large-en-v1.5` | General-purpose English embeddings |
| **Google Gemini** | `gemini-embedding-001` (`text-embedding-004`, `text-embedding-3-small`, and `text-embedding-3-large` aliases) | Multilingual, supports requested dimensions |
| **Voyage AI** | `voyage-3.5-lite`, `voyage-3-lite` | Domain-specialised embeddings |
| **Modal experiment** | `google/embeddinggemma-2` | Text/code embeddings; 128, 256, 512 or 768 dimensions (default 768) |
| **Modal experiment** | `BAAI/bge-small-en-v1.5` | Smaller English baseline; 384 dimensions |

Use [`GET /v1/models`](https://ai-gateway.sassmaker.com/models) to get the full current list with provider metadata, dimensions, aliases, and `enabled` availability based on configured provider credentials/bindings.

### Modal experiment

Use your existing Free AI gateway key. Modal models are explicit experiments:
each request returns the selected model or an error, without switching embedding
spaces. Other provider requests never fall back into Modal. `enabled` in the
catalog indicates configured credentials; it does not prove live model health.

```bash
curl https://ai-gateway.sassmaker.com/v1/embeddings \
  -H "Authorization: Bearer <GATEWAY_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "google/embeddinggemma-2",
    "project_id": "embedding-trial",
    "input": "How do I find relevant documents?",
    "task": "retrieval_query",
    "dimensions": 256
  }'
```

Embed stored documents with `task: "retrieval_document"`; use
`task: "retrieval_query"` when searching them. Keep the model and dimensions
identical for documents and queries. Gemma also supports `code_retrieval`,
`sentence_similarity`, `classification` and `clustering`. BGE supports
retrieval and `sentence_similarity`.

Each batch accepts 1–8 nonblank strings of at most 16,000 characters each.
Token limits are 2,048 per string for Gemma, 512 for BGE, and 8,192 across the
batch, including task prefixes. Excess token input is rejected rather than
silently truncated.

Allow up to 150 seconds for a request. Live gateway binding checks took about
35 seconds for Gemma and 93 seconds for BGE, including cold startup and proxy
transport. Warm backend SDK calls took about half a second. These small samples
do not establish typical public API latency or retrieval quality on your corpus.

The trial has a shared allowance across both models and all projects: an initial
burst of five requests, then approximately one request every 24 minutes. A
blocked allowance returns HTTP 429; an unavailable allowance service returns
HTTP 503. Failed upstream calls still consume allowance. The persistent bucket
can reset when its 24-hour alarm fires. This controls demand rather than setting
a dollar budget. Modal bills compute against the account's shared $30 monthly
credit; other account usage can consume that credit.

## Response

The response follows the standard OpenAI embeddings format:

```json
{
  "object": "list",
  "data": [
    {
      "object": "embedding",
      "index": 0,
      "embedding": [0.0023, -0.0089, 0.0412, ...]
    }
  ],
  "model": "voyage-3",
  "usage": {
    "prompt_tokens": 8,
    "total_tokens": 8
  }
}
```

For batch inputs, `data` contains one entry per input string, in the same order.

## Examples

### Single String



### curl

```bash
curl https://your-gateway.workers.dev/v1/embeddings \
  -H "Authorization: Bearer <GATEWAY_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "voyage-3",
    "project_id": "my_project",
    "input": "The quick brown fox jumps over the lazy dog"
  }'
```


### JavaScript

```js
const response = await fetch('https://your-gateway.workers.dev/v1/embeddings', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer <GATEWAY_API_KEY>',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'voyage-3',
    input: 'The quick brown fox jumps over the lazy dog',
  }),
});

const data = await response.json();
const vector = data.data[0].embedding;
console.log(`Embedding dimensions: ${vector.length}`);
```



### Batch Embedding



### curl

```bash
curl https://your-gateway.workers.dev/v1/embeddings \
  -H "Authorization: Bearer <GATEWAY_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "@cf/baai/bge-base-en-v1.5",
    "project_id": "my_project",
    "input": [
      "How do I reset my password?",
      "Where can I find my invoice?",
      "How do I cancel my subscription?"
    ]
  }'
```


### JavaScript

```js
const texts = [
  'How do I reset my password?',
  'Where can I find my invoice?',
  'How do I cancel my subscription?',
];

const response = await fetch('https://your-gateway.workers.dev/v1/embeddings', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer <GATEWAY_API_KEY>',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: '@cf/baai/bge-base-en-v1.5',
    input: texts,
  }),
});

const data = await response.json();
const embeddings = data.data.map((item) => item.embedding);
console.log(`Got ${embeddings.length} vectors of length ${embeddings[0].length}`);
```



### With Dimensions (Gemini)



### curl

```bash
curl https://your-gateway.workers.dev/v1/embeddings \
  -H "Authorization: Bearer <GATEWAY_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "text-embedding-004",
    "project_id": "my_project",
    "input": "Semantic search query",
    "dimensions": 256
  }'
```


### JavaScript

```js
const response = await fetch('https://your-gateway.workers.dev/v1/embeddings', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer <GATEWAY_API_KEY>',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'text-embedding-004',
    input: 'Semantic search query',
    dimensions: 256,
  }),
});

const data = await response.json();
console.log(data.data[0].embedding.length); // 256
```



### OpenAI SDK

The gateway is fully compatible with the OpenAI Node.js SDK:

```js

const client = new OpenAI({
  baseURL: 'https://your-gateway.workers.dev/v1',
  apiKey: '<GATEWAY_API_KEY>',
});

const result = await client.embeddings.create({
  model: 'voyage-3-lite',
  input: ['cat', 'dog', 'fish'],
});

result.data.forEach((item, i) => {
  console.log(`Text ${i}: ${item.embedding.length} dims`);
});
```
