When you compare embeddings apis for production search or classification, the devil is in the dimensionality, token limits, and client semantics—not the headline model names. This article walks through five hosted embedding services engineers actually wire into retrieval pipelines, with minimal code to show how each expects to be called.
1. OpenAI
OpenAI’s text-embedding-3-small (1536 dims) and text-embedding-3-large (3072 dims) are the default choice for many teams because the SDK is boring and the endpoint is stable. Input is capped at 8191 tokens; longer texts must be truncated or chunked upstream. There is no separate multilingual SKU, but the models handle non-English input acceptably for mixed corpora.
The API takes a single string or an array of strings. It does not support an explicit query/document mode—asymmetry is your problem to solve at the application layer. The response shape is a list of objects with an embedding array and an index; token usage is reported at the top level.
from openai import OpenAI
client = OpenAI()
r = client.embeddings.create(
model="text-embedding-3-small",
input=["chunk one", "chunk two"]
)
vecs = [d.embedding for d in r.data]
One gotcha: vectors are not guaranteed to be L2-normalized. If your vector store (e.g., pgvector with cosine) assumes unit norm, normalize client-side. When you compare embeddings apis on operational simplicity, OpenAI wins on SDK maturity and batch throughput.
2. Cohere
Cohere’s Embed v3 models (embed-english-v3, embed-multilingual-v3) output 1024-dim vectors and force you to declare input_type. This is a real feature: passing search_query vs search_document changes the projected space and measurably improves recall on asymmetric retrieval tasks. The multilingual variant covers 100+ languages with the same dimension.
Token limit is 512, which is tight for RAG chunks. You will chunk more aggressively than with OpenAI, and you must handle overlap yourself. The SDK returns a flat embeddings list (not a list of objects), which saves a line of extraction but breaks the pattern used by every other vendor here.
import cohere
co = cohere.Client("api-key")
r = co.embed(
model="embed-english-v3",
texts=["doc text"],
input_type="search_document"
)
vecs = r.embeddings
Cohere also exposes truncate="NONE" to error on overflow instead of silently clipping—use it in tests. For TypeScript callers, the shape is identical via the cohere-ai package:
import { CohereClient } from "cohere-ai";
const co = new CohereClient({ token: "api-key" });
const r = await co.embed({ model: "embed-multilingual-v3", texts: ["hi"], inputType: "search_query" });
3. Voyage
Voyage AI built its reputation on retrieval benchmarks. The voyage-2 (1024-dim) and voyage-large-2 (1536-dim) models accept up to 4096 tokens, and voyage-multilingual-2 covers 100+ languages at 1024 dims. That token headroom lets you embed whole sections without fine-grained chunking.
The request mirrors OpenAI but adds an optional input_type field (document/query). Voyage returns data with embedding and sets a truncation boolean if you exceeded the limit—handle it explicitly or you’ll silently lose context. The client is thin and the REST route is OpenAI-compatible enough to swap in a proxy.
import voyageai
vo = voyageai.Client("api-key")
r = vo.embed(
model="voyage-2",
input=["long section text"],
input_type="document"
)
vecs = [d.embedding for d in r.data]
If you compare embeddings apis for long-document retrieval, Voyage’s limit and retrieval-tuned training make it a strong default. Pricing is per token like the others; meter it before bulk backfills.
4. Gemini
Google’s text-embedding-004 (Gecko) returns a fixed 768-dim vector, which simplifies ANN index configuration—you always allocate the same footprint regardless of task. Max input is 2048 tokens, and the model is accessed through the Generative Language API or GCP Vertex. Auth requires a project and API key, which adds IAM overhead compared to pure API-key vendors.
Unlike the others, the legacy SDK embeds a single content object per call; there is no native batch array in the convenience method. For multiple texts, loop or hit the REST batch endpoint. Task types (retrieval_document, retrieval_query, clustering) tune the output similarly to Cohere’s input_type.
import google.generativeai as genai
genai.configure(api_key="key")
r = genai.embed_content(
model="models/text-embedding-004",
content="text",
task_type="retrieval_document"
)
vec = r["embedding"]
Gemini embeddings are L2-normalized by default, so cosine and dot product are equivalent. For multilingual corpora, the model performs well but lags dedicated multilingual SKUs from Cohere and Voyage.
5. Mistral
Mistral’s mistral-embed is the minimalist option: 1024 dims, 512-token cap, single model. It is served from the same La Plateforme endpoint as their chat models, so if you already call Mistral for generation, embeddings need no new vendor relationship. There is no query/document distinction.
The request is OpenAI-flavored but not fully compatible; you must use the Mistral SDK or the /v1/embeddings route with a Mistral key. The response uses inputs (plural) rather than input, a small divergence that breaks naive client shims.
from mistralai import Mistral
client = Mistral(api_key="key")
r = client.embeddings.create(
model="mistral-embed",
inputs=["text"]
)
vecs = [d.embedding for d in r.data]
Mistral is a reasonable pick when you want one vendor for both generation and embeddings and your chunks are small. Beyond that, the 512-token limit and single model family make it the least flexible in this list.
Synthesis
The table below summarizes the concrete differences. Dimensions drive memory and index size; token limits dictate chunking strategy; query/document modes signal retrieval tuning.
| API | Model(s) | Dims | Token limit | Multilingual | Query/doc mode |
|---|---|---|---|---|---|
| OpenAI | text-embedding-3-small/large | 1536 / 3072 | 8191 | Partial | No |
| Cohere | embed-english-v3 / embed-multilingual-v3 | 1024 | 512 | Yes (multi SKU) | Yes (input_type) |
| Voyage | voyage-2 / voyage-large-2 / multilingual-2 | 1024 / 1536 | 4096 | Yes (multi SKU) | Yes (input_type) |
| Gemini | text-embedding-004 | 768 | 2048 | Partial | Yes (task_type) |
| Mistral | mistral-embed | 1024 | 512 | No | No |
When you compare embeddings apis across languages, the client surface matters as much as the model. Python SDKs are first-class for all five; TypeScript support is solid for OpenAI, Cohere, and Mistral, adequate for Voyage, and awkward for Gemini’s batching. If you’d rather not operate five SDKs and rate limits, an OpenAI-compatible gateway like n4n.ai fronts 240+ models—including several embeddings endpoints—behind one /v1/embeddings route with automatic fallback when a provider is degraded.