Embeddings
Last updated
POST /v1/embeddings — OpenAI's embeddings API, with your own provider keys. Point a codebase indexer (Roo Code, Kilo Code, Continue) or any OpenAI SDK at Tempr and it embeds with OpenAI, Gemini, Mistral, Cohere, Bedrock and more, on the same virtual key, limits and logs as your chat traffic.
Request
POST https://api.temprhq.io/v1/embeddings
Authorization: Bearer tvk_...
Content-Type: application/json
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
model | string | Yes | provider/model, e.g. openai/text-embedding-3-small. Must be on your virtual key's allowlist. A bare id resolves among the embedding models of the providers you have keys for; see models. |
input | string or array | Yes | A string, an array of strings, an array of token ids, or an array of token-id arrays, up to 2,048 inputs. Strings can't be empty. Token ids work only on OpenAI-compatible providers; see providers. |
encoding_format | string | No | float (the default) or base64: little-endian float32 bytes, as OpenAI encodes them. Honored on every provider: Tempr encodes the vectors itself when a provider can't. The OpenAI SDKs ask for base64 by default. |
dimensions | integer | No | Output size, for models that can shorten their vectors. Sent to Gemini as outputDimensionality, to Mistral and Cohere as output_dimension. A model that can't take the size you ask for returns the provider's error. |
user | string | No | Your end user's id. Recorded on the request log for the Portal's End users view, and passed to providers that take it. |
input_type | string | No | Tempr's addition: whether the inputs are documents or queries, for the models that embed the two differently. See input type. |
Example
curl https://api.temprhq.io/v1/embeddings \
-H "Authorization: Bearer $TEMPR_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "openai/text-embedding-3-small", "input": ["def add(a, b):", "return a + b"]}'
Response
OpenAI's shape on every provider, one item per input, in input order:
{
"object": "list",
"data": [
{ "object": "embedding", "index": 0, "embedding": [0.0023064255, -0.009327292, ...] },
{ "object": "embedding", "index": 1, "embedding": [-0.012154937, 0.0026786416, ...] }
],
"model": "text-embedding-3-small",
"usage": { "prompt_tokens": 9, "total_tokens": 9 }
}
An OpenAI-compatible provider's answer comes back as the provider sent it, other fields included, unless Tempr has to re-encode its vectors or add the usage it left out. A translated provider's answer (Gemini, Cohere, Bedrock) is built in this shape. Every response carries x-tempr-request-id, and x-tempr-usage-estimated: true when the provider reported no token count: the count in usage, which is also what's billed, is then Tempr's estimate of four characters a token.
Providers & models
The model id picks the provider, as it does for chat. OpenAI-compatible providers get your request as sent, with the model id swapped for theirs; Gemini, Cohere and Bedrock are translated to their own APIs and back. Codebase indexers ask for the model's dimension, so the defaults are listed for the common models.
| Provider | Example models (default dimensions) | How |
|---|---|---|
| OpenAI | openai/text-embedding-3-small (1536), openai/text-embedding-3-large (3072) | Passed through. Both take dimensions. |
| Azure OpenAI | azure-openai/<deployment> | Passed through to your resource's v1 API. Name an embedding deployment. |
| Azure AI Foundry | azure-ai-foundry/<model> | Passed through to your resource's model inference API. |
google/gemini-embedding-001 (3072) | Translated to batchEmbedContents, 100 inputs a call. Text only. | |
| Mistral | mistral/mistral-embed (1024), mistral/codestral-embed (1536) | Passed through. |
| Cohere | cohere/embed-v4.0 (1536), cohere/embed-english-v3.0 (1024) | Translated to the v2 embed API, 96 inputs a call. Text only. |
| AWS Bedrock | aws-bedrock/amazon.titan-embed-text-v2:0 (1024), aws-bedrock/cohere.embed-v4:0 (1536) | Translated to InvokeModel with your Bedrock key and region. Titan takes one input a call, so Tempr sends them a few at a time. Amazon Titan Text and Cohere Embed models only. Text only. |
| DeepInfra | deepinfra/BAAI/bge-m3 (1024), deepinfra/Qwen/Qwen3-Embedding-8B (4096) | Passed through. |
| Together AI | together-ai/BAAI/bge-base-en-v1.5 (768) | Passed through. Together runs its embedding models on dedicated endpoints only: start one in Together first. |
| Fireworks AI | fireworks-ai/accounts/fireworks/models/qwen3-embedding-8b (4096), fireworks-ai/nomic-ai/nomic-embed-text-v1.5 (768) | Passed through. |
| Nscale | nscale/Qwen/Qwen3-Embedding-8B (4096) | Passed through. |
| OpenRouter | openrouter/openai/text-embedding-3-small, openrouter/qwen/qwen3-embedding-8b, … | Passed through, billed at OpenRouter's reported cost. |
| Custom models | custom/<alias> | Passed through to your endpoint's /embeddings, beside its /chat/completions: the route vLLM, Ollama, LM Studio, TEI and LiteLLM serve. See custom models. |
Anthropic has no embedding models, so an anthropic/… model gets 400 embeddings_unsupported, as does every other provider not listed here (Hugging Face's router, for one, serves chat only). Token-id input to a text-only provider gets 400 unsupported_input. Both come back before any quota is spent; see embeddings errors. Each provider's own limits still apply, such as the most tokens one input may hold.
Input type
Some models embed a search query differently from the documents it searches. Tell them which with input_type, in either Cohere's words or Gemini's:
input_type | Cohere gets | Gemini gets (taskType) |
|---|---|---|
| Not set | search_document (Cohere requires one) | Nothing: Gemini's default |
search_document or RETRIEVAL_DOCUMENT | search_document | RETRIEVAL_DOCUMENT |
search_query or RETRIEVAL_QUERY | search_query | RETRIEVAL_QUERY |
CODE_RETRIEVAL_QUERY | search_query | CODE_RETRIEVAL_QUERY |
classification, clustering | The same | CLASSIFICATION, CLUSTERING |
OpenRouter and custom endpoints get input_type as sent. Other providers don't take it, so it isn't sent to them. Indexers that can't set it embed queries as documents, which works; setting it where you can improves search.
Models list
GET /v1/models?type=embedding lists the embedding models of the providers you have keys for, each marked "type": "embedding" with "architecture": {"output_modalities": ["embeddings"]}; ?type=all lists them beside the chat models, which have "type": "language". Plain GET /v1/models lists chat models only, so a chat model picker filled from it never offers an embedding model. From AWS Bedrock it lists the embedding models you entered with your Bedrock key. Azure deployments and custom models aren't listed as embedding models, because nothing says which of them embed, but you can call them by id.
A bare model id, such as text-embedding-3-small, resolves among those embedding models, the way a bare chat model id resolves among chat models.
What applies
Embeddings go through the same pipeline as chat, with these differences:
| Feature | On /v1/embeddings |
|---|---|
| Virtual keys, model allowlists, RPM and TPM limits, key and organization budgets | The same as chat. |
| Monthly quota | One embeddings call is one request, however many inputs it holds. |
| Usage and cost | Input tokens at the model's input price, no output tokens. Counted toward budgets, analytics and cost alerts like chat usage. |
| Request logs | Logged like chat, with the input as the request content. The logged response keeps its usage but not its vectors: each is replaced by a note of its size. |
| Guardrails | The sensitive-content scan runs on the input, which leaves for a provider the way a prompt does. The prompt-injection check doesn't run: an embedding model follows no instructions. |
| Fallback chains and backup keys | The same as chat. Candidates whose provider has no embeddings are skipped. Make a chain's candidates the same model on different providers: vectors from different models can't be compared, so a chain across models would mix them in one index. |
Response caching (x-tempr-cache-ttl) | Not applied: the header is ignored. Indexers already skip content they've embedded before. |
Prompt templates (x-tempr-prompt), prompt caching (x-tempr-prompt-cache) | Not applied: an embeddings request has no system prompt or conversation for them to act on, and their headers are ignored rather than rejected, so a client that sends them on every call still works. |