Embeddings, rerank, images and audio
Configure the providers that serve one surface each, from embeddings to image edits, and read the three non-token units their rows bill in.
On this page
Most of a gateway’s traffic is chat, and most of its documentation follows. But a retrieval pipeline calls embeddings and rerank far more often than it calls a chat model, and an image or audio pipeline never calls one at all. Those calls cost money that belongs in the same total.
Fifteen of the 95 built-in provider descriptors declare no chat endpoint. This page covers the earlier specialist set; fireworks_ai_embeddings and vertex_ai_embedding
are also listed in the current provider reference. Where a test gates one of these descriptors’
endpoints, the generated provider matrix names it: the test drives a request through the descriptor
against a mock shaped like that provider and asserts the ledger row’s own provider and endpoint
stamps. The verification is against mocks, not the providers’ live endpoints. Three of the eleven,
black_forest_labs, fal_ai and runwayml, carry no gated cell at all; the matrix prints
declared (no e2e gate) against them and calls that not a support claim, which is worth knowing
before you put one of the three in front of production traffic.
They are configured like any other upstream, and what changes is the unit on the row.
Some of them answer later
Seven descriptors take a job and answer out of band: replicate, fal_ai, black_forest_labs,
runwayml, stability, assemblyai and soniox. Six answer only that way; stability answers
15 of its 17 operations inside the call and polls for the other two.
A job is two rows, not one. The submit lands on the ledger immediately, terminal and unpriced,
with the typed reason settlement_pending. A settlement companion row arrives minutes later,
joined by req_id, and its figure replaces the pending zero rather than adding to it. Turning the
plane on is one key, and it is off unless you say otherwise:
jobs:
enabled: true
Your client still speaks the provider’s own async contract: take the job id off the row and poll the provider through the gateway. Providers that take a job and answer later is where that mechanism is explained, including what happens to a job nobody ever answers.
Embeddings
Fifteen descriptors serve /v1/embeddings. Most are chat providers that also carry priced
embedding models; one, voyage, exists for retrieval and nothing else.
upstreams:
voyage:
provider: voyage
base_url: https://api.voyageai.com # host only — your client already sends /v1
api_key_env: VOYAGE_API_KEY
Embeddings bill in tokens, like chat, with one difference: there is no output. The rate applied is the input rate, and the output rate is zero.
PREFIX MODEL ENDPOINT RESULT KEY RATE
voyage voyage-3 embeddings PRICED voyage/voyage/voyage-3 in=$0.06/M
openai gpt-4o embeddings UNPRICED endpoint_unpriced
The second line is worth noticing. gpt-4o has a rate, but not one that serves the embeddings
endpoint, so the answer is endpoint_unpriced rather than the chat rate applied to an embedding
call. The endpoint is part of the lookup, not decoration on it.
The full list of fifteen is in endpoints and cost shapes.
Rerank
Three descriptors serve /v1/rerank: jina_ai, voyage and novita.
upstreams:
jina:
provider: jina_ai
base_url: https://api.jina.ai
api_key_env: JINA_API_KEY
Rerank bills in tokens over the documents you submitted.
| Descriptor | Model in the catalog | Input rate |
|---|---|---|
novita |
baai/bge-reranker-v2-m3 |
$0.010 / M |
jina_ai |
jina-reranker-v2-base-multilingual |
$0.018 / M |
voyage |
rerank-2 |
$0.050 / M |
Cohere serves rerank too, and is not claimed here. Its pricing is per search unit rather than per token, and the vendored catalog carries no per-token rate for it, so a Cohere rerank call would have to be either unpriced or guessed. It is left out rather than guessed.
Images
Seven descriptors serve /v1/images/generations: openai, aiml, recraft, stability,
fal_ai, black_forest_labs and runwayml. Three of those also serve /v1/images/edits:
openai, stability and black_forest_labs. Both surfaces bill per image returned.
upstreams:
recraft:
provider: recraft
base_url: https://external.api.recraft.ai
api_key_env: RECRAFT_API_KEY
stability:
provider: stability
base_url: https://api.stability.ai
api_key_env: STABILITY_API_KEY
recraft is image-only on the OpenAI wire and answers in the call. stability speaks its own
/v2beta stable-image wire: multipart in, image bytes out, and one path (generate/sd3) serving
seven catalog rows priced from $0.035 to $0.065. It tells those seven apart by reading the model
field out of the multipart form, which is a third place a model string can live beside the URL path
and the URL query.
Where a model carries a flat per-image rate, it is used directly: recraftv3 is $0.04 per image
and aiml‘s dall-e-3 entry is $0.052. Where the wire reports no quantity at all, as Stability’s
and Black Forest Labs’ do, the row bills one image per request and says so rather than inferring a
count.
Text-to-speech
Three descriptors serve /v1/audio/speech: openai, elevenlabs and runwayml. ElevenLabs
speaks its own wire, with the voice id in the URL path and opaque binary audio coming back.
upstreams:
elevenlabs:
provider: elevenlabs
base_url: https://api.elevenlabs.io
api_key_env: ELEVENLABS_API_KEY
Speech bills per character of the text you sent, which means the figure is known from the request and does not depend on the response at all.
| Descriptor | Model | Rate |
|---|---|---|
openai |
tts-1 |
$0.000015 / character |
elevenlabs |
eleven_multilingual_v2 |
$0.00018 / character |
The response body is audio and is relayed byte for byte. Nothing parses it, and nothing needs to.
Speech-to-text
Four descriptors serve /v1/audio/transcriptions: openai, deepgram, assemblyai and
soniox. Deepgram answers in the call, with the model in the URL query and a Token prefix on
the credential; AssemblyAI and Soniox upload, submit and poll.
upstreams:
deepgram:
provider: deepgram
base_url: https://api.deepgram.com
api_key_env: DEEPGRAM_API_KEY
Transcription bills per second of audio, taken from the provider’s own response metadata.
| Descriptor | Model | Rate |
|---|---|---|
deepgram |
nova-3 |
$0.00007167 / second |
openai |
whisper-1 |
$0.0001 / second |
assemblyai |
best |
$0.00003333 / second |
soniox |
stt-async-v4 |
no rate in the catalog |
That direction matters. Because the duration comes from the response, a reply that omits it produces no cost figure rather than an estimate from the file size.
AssemblyAI’s two catalog rows are its deprecated speech_model values, best and nano. A
present-day request naming a universal-* model settles model_unknown, with the measured seconds
still on the row, because no primary AssemblyAI document maps today’s ids onto those two.
Covered is not priced
Binding a provider means its traffic is routed, governed, journaled, polled and settled. It does not mean every model produces a dollar, and the gap between those two claims is widest here.
soniox is the mirror image, and the wire is not the reason. Soniox reports a measured audio
duration in milliseconds, which is what a per-second rate consumes, and the driver settles with it
and infers nothing. Both of its catalog rows carry no rate at all, so the key resolves and then has
nothing to apply, which is what unit_missing means. One per_second rate on those two rows would
make it priceable with no driver change: a pricing-data gap rather than a driver gap.
Six image rows measure their quantity and then decline to bill it, because the catalog’s unit is
not the vendor’s unit. Five fal models carry a per_image rate while fal publishes them per
megapixel or per quality tier, and Runway’s gen4_image carries a flat rate for the 720p tier
while Runway charges more for 1080p with no tier derivable from the wire.
| Model | The catalog says | The vendor publishes |
|---|---|---|
fal-ai/flux/schnell |
per_image: 0.003 |
$0.003 per megapixel |
fal-ai/flux-pro/v1.1 |
per_image: 0.04 |
$0.04 per megapixel |
fal-ai/stable-diffusion-v35-medium |
per_image: 0.0398 |
$0.02 per megapixel |
fal-ai/recraft/v3/text-to-image |
per_image: 0.0398 |
$0.04 per image, $0.08 for a vector style |
fal-ai/ideogram/v3 |
per_image: 0.06 |
$0.03 turbo, $0.06 balanced, $0.09 quality |
runwayml/gen4_image |
per_image: 0.05 |
5 credits at 720p, 8 credits at 1080p |
The job still succeeds and the row still lands; what is withheld is the number, and the row carries
the vendor’s own published wording in its error field so you can price those calls yourself. Do
not read a missing dollar there as a free call. The withholding list is matched exactly rather than by
prefix, so a sibling id one character different, fal-ai/flux-pro/v1.1-ultra, prices normally. Runway’s other
unpriced row is a different problem. The vendored catalog carries a key called
runwayml/eleven_multilingual_v2, which is the same model name the speech table above lists under
elevenlabs/ and at a different rate. It bills per character, and Runway’s task object carries no
character count anywhere, so this is a missing quantity rather than a mismatched unit.
What can go wrong
| Symptom | Cause | Fix |
|---|---|---|
endpoint_unpriced |
the model has rates, but not for this endpoint | use a model the provider prices for that surface |
unit_missing on an image call |
no size or quality in the request, or a withheld unit | send the dimensions your provider expects; check the row’s error field |
a submit row with no settlement_pending and no later row |
the job plane is off, so nothing recognises the submission | set jobs.enabled: true and restart |
| a transcription row with no cost | the response carried no duration | check the provider’s response shape |
| an embeddings call is not routed | only chat, responses and embeddings are routable, and no rule matched | confirm the tier targets an embeddings-capable upstream |
| a rerank tier fails validation | with allow_cross_dialect on, a tier’s upstream must serve chat |
point the tier at a chat-capable upstream |
What is not claimed here
AWS Polly for audio speaks a bespoke wire with no verifiable contract, and is published as refused rather than pending. Cohere’s rerank is left out for the reason above. Video generation has no endpoint kind at all, so no descriptor can declare one: Runway is bound for images and speech only.
The coverage page carries the full uncovered set with the blocker for each, and it records the class that once held these image and audio job providers, now standing at zero.