Embeddings
Turn text into vectors on /v1/embeddings — widths, retrieval quality, and what is billed.
POST /v1/embeddings works exactly like the chat endpoint — same key, same
namespaced slugs, same limits and the same billing — and the AI SDK reaches it
through embeddingModel:
import { embed, embedMany } from 'ai';
const { embedding } = await embed({
model: faucet.embeddingModel('voyage/voyage-4'),
value: 'sunny day at the beach',
});
const { embeddings, usage } = await embedMany({
model: faucet.embeddingModel('fireworks/qwen3-embedding-8b'),
values: ['chunk one', 'chunk two', 'chunk three'],
});A model belongs to one endpoint
Sending an embedding model to /v1/chat/completions, or a chat model here, is
a 400 that names the endpoint you actually wanted — not a 404, because the
model does exist and the slug is not what needs fixing. See
Choosing a model.
Shorter vectors, where the model offers them
dimensions picks a width, and the Models reference
lists what each model will truncate to. Voyage's voyage-4 family and the Nomic
models are trained so a shorter vector is still a good vector, which makes the
width a storage decision rather than a quality one:
{ "model": "voyage/voyage-4", "input": ["a", "b"], "dimensions": 512 }From the AI SDK, that width is a provider option rather than a top-level argument:
await embed({
model: faucet.embeddingModel('voyage/voyage-4'),
value: 'sunny day at the beach',
providerOptions: { faucet: { dimensions: 512 } },
});Rather than hard-coding the widths, ask: GET /v1/models/{id} publishes
default_dimensions and, where Faucet enforces a set, supported_dimensions.
The embeddings route runs the same derivation before it resolves a credential, so
a width outside the published set is a local 400 rather than a
provider-dependent surprise. See
Model capabilities.
Retrieval quality: tell Voyage what the text is for
Voyage models embed a search query and a stored document differently, and saying
which you have measurably improves retrieval. OpenAI's format has no field for
it, so it rides on provider_options — embed your corpus as document and your
queries as query:
{
"model": "voyage/voyage-4",
"input": ["chunk one", "chunk two"],
"provider_options": { "voyage": { "input_type": "document" } }
}Billing
Input tokens only — a vector is not tokens, and nothing charges for producing one. Token counts come back on every request, including on Voyage, which reports only a total of its own accord. See Streaming and usage.