By Sean Donahoe · Published July 16, 2026 · Model names, rates, and limits are accurate as of this date.
How do I get speech-to-text on FluxRouter?
Speech-to-text on FluxRouter runs through the flux-voice model on the OpenAI-compatible /v1/audio/transcriptions endpoint. Same key, same base URL (https://api.fluxrouter.ai/v1) you already use for chat. If you call OpenAI-style transcription today, it's a base-URL-and-key change plus one model string. Voice runs on any paid plan.
That's the whole setup. If your code already hits audio.transcriptions.create somewhere, you're minutes from your first transcript through Flux.
What's worth staying for is the part the setup doesn't tell you: the ten-second billing floor that quietly changes the math on short clips, when it's worth pinning the accurate variant, and the errors you'll want your client to catch before they surprise you in production.
The easy button
Don't want to read a guide? Hand this to your coding agent and let it do the swap:
Point my OpenAI transcription call at FluxRouter. Base URL
https://api.fluxrouter.ai/v1, my Flux key, model flux-voice. Keep
everything else exactly the same.
That's it. No config files, no rollback surface to babysit. Nothing on your machine changes except one base URL and one model string.
Or do it by hand in one command:
curl https://api.fluxrouter.ai/v1/audio/transcriptions \
-H "Authorization: Bearer $FLUX_API_KEY" \
-F model="flux-voice" \
-F file="@meeting.m4a" \
-F response_format="text"
One gate before you copy that: Voice runs on a paid plan. A key without one comes back with 402 and the code premium_locked. The OpenAI SDK raises on that, so catch it and send the user to upgrade instead of letting it throw. Read 402 as "turn this on," not a dead end. A 401 means the key itself is missing or bad.
The model id
Use flux-voice as your model. Your text aliases (flux-fast, flux-standard, flux-reasoning) route to text models; flux-voice routes to a speech-to-text model behind the same key and the same endpoint.
flux-voice auto-balances speed and accuracy per clip. Omit model entirely and you get that default.
Two variants you can pin when you want to force the call yourself:
flux-voice-accuratefavors accuracy.flux-voice-fastfavors latency.
Same paid-plan gate on all three.
Rule of thumb: leave it on the default and let flux-voice balance speed and accuracy for each clip. Pin a variant only when you've got a specific reason to force one.
Want to confirm the ids are live right now? One call returns every usable flux-* id your key can reach:
curl -s https://api.fluxrouter.ai/v1/models \
-H "Authorization: Bearer $FLUX_API_KEY"
That list is the always-current authority. A blog post can go stale, so when the two disagree, trust the call.
Transcribe a file
The request is an OpenAI transcription request. A file, and optionally a model, sent as multipart/form-data. The OpenAI SDK ships it for you through audio.transcriptions.create, so on an existing OpenAI setup the base URL is the line that changes.
Python, OpenAI SDK:
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.fluxrouter.ai/v1", # the one line that changes
api_key=os.environ["FLUX_API_KEY"],
)
with open("meeting.m4a", "rb") as audio:
result = client.audio.transcriptions.create(
model="flux-voice",
file=audio,
)
print(result.text)
Same request as raw curl:
curl https://api.fluxrouter.ai/v1/audio/transcriptions \
-H "Authorization: Bearer $FLUX_API_KEY" \
-F model="flux-voice" \
-F file="@meeting.m4a"
Base URL, key, model, file. That's the job.
Request fields
| Field | Required | What it does |
|---|---|---|
file | Yes | The audio. Formats: wav, mp3, mp4/m4a, mpeg/mpga, ogg, webm, flac. Up to 8 MB. |
model | No | flux-voice (default, omit to get it), flux-voice-accurate, or flux-voice-fast. |
language | No | ISO-639-1 code (en, es, de). Omit and it auto-detects. |
prompt | No | A short hint of names, jargon, or spellings to improve accuracy. |
response_format | No | json (default), verbose_json, or text. |
timestamp_granularities[] | No | word and/or segment. Needs verbose_json. |
temperature | No | Sampling temperature. |
What comes back
Three response shapes, and you pick with response_format:
json(default) gives you{ "text": "..." }.textgives you the transcript as a plain string, nothing to parse.verbose_jsonaddslanguage,duration, andsegments. Ask fortimestamp_granularities[]=wordand you get per-word timestamps too.
Two things it won't do, and both return 400: streaming (stream: true) and subtitle formats (srt, vtt). If you need captions, take verbose_json with word timestamps and build the file your side.
Read the headers
Every successful response carries three transparency headers. Log them from day one:
| Header | What it tells you |
|---|---|
x-flux-routed-model | Which variant actually served the clip. |
x-flux-billed-seconds | Seconds billed on this request. |
x-flux-cost-usd | What it cost, in USD. |
Here's a real one off my own probe. I sent a one-second clip. It came back x-flux-routed-model: flux-voice-accurate, x-flux-billed-seconds: 10, x-flux-cost-usd: 0.016670. Ten seconds billed on a one-second clip, because there's a ten-second floor per request (more on that below). Ten seconds at ten cents a minute is about $0.0167, and the exact charge is right there on the header, so you never have to back it out yourself.
Now that it's wired
The pipe works. Here's what to actually do with it. Copy-paste, all runnable. Each one reuses the client from the transcribe example above; the batch loop sets it up in full.
1. Transcribe a meeting into timestamped, jump-to notes. Ask for verbose_json with word timestamps, then roll the words up into short lines, each stamped with the second it starts, so you can drop a ?t= link straight to that moment in the recording.
with open("standup.m4a", "rb") as audio:
result = client.audio.transcriptions.create(
model="flux-voice",
file=audio,
response_format="verbose_json",
timestamp_granularities=["word"],
)
def stamp(sec): # 95.0 -> "1:35" (and a ?t=95 you can link to)
return f"{int(sec) // 60}:{int(sec) % 60:02d}"
line, start = [], None
for w in result.words:
if start is None:
start = w.start
line.append(w.word)
if w.word.endswith((".", "?", "!")) or len(line) >= 12:
print(f"[{stamp(start)}] " + " ".join(line))
line, start = [], None
2. A quick voice memo to text, fast. No structure, just the words, and it favors latency. Pin -fast and take text.
result = client.audio.transcriptions.create(
model="flux-voice-fast",
file=open("memo.ogg", "rb"),
response_format="text",
)
print(result)
3. Batch a whole folder. Loop a directory, transcribe each file, write the text next to it. Mind the 8 MB ceiling (413 over it) and the per-account rate limit (429 on a burst), so back off and retry instead of hammering.
import os, time, pathlib
from openai import OpenAI
client = OpenAI(
base_url="https://api.fluxrouter.ai/v1",
api_key=os.environ["FLUX_API_KEY"],
)
def transcribe(path):
delay = 1.0
while True:
try:
with open(path, "rb") as f:
return client.audio.transcriptions.create(model="flux-voice", file=f)
except Exception as e: # 429 = rate limited
if "429" in str(e) and delay <= 16:
time.sleep(delay) # back off, then retry
delay *= 2
continue
raise
for path in pathlib.Path("audio/").glob("*.m4a"):
if path.stat().st_size > 8 * 1024 * 1024:
print("skip (over 8 MB):", path.name)
continue
result = transcribe(path)
path.with_suffix(".txt").write_text(result.text)
print("done:", path.name)
time.sleep(0.5) # gentle between files
4. Nail the jargon and the names. Feed the odd spellings in through prompt, and pin -accurate when getting them right matters more than shaving latency.
result = client.audio.transcriptions.create(
model="flux-voice-accurate",
file=open("call.wav", "rb"),
prompt="Acme, Kubernetes, Dr. Nguyen",
)
print(result.text)
One note while you're wiring these up: if your audio comes from a browser MediaRecorder, it usually arrives as an ogg/opus blob, and that's a supported format. Send it straight through on flux-voice, no transcoding step first.
Deeper dictation-UI and prompt-pack patterns are their own piece. This gets you transcribing today.
What it costs, and the limits
Billing is simple. $0.10 per audio-minute, charged per second, with a ten-second minimum per request. Same price whichever variant serves the clip. It lands on the same Flux bill as everything else, one invoice, nothing separate to reconcile. That's the rate as of July 16, 2026, and pricing in this space moves, so the live guide is the number that counts on any given day.
The limits worth coding against:
- Files up to 8 MB. Over that comes back
413. - Rate-limited per account. Burst too hard and you get
429, so back off and retry.
And the error map, so your client handles the common cases instead of guessing:
| Code | Means | Do this |
|---|---|---|
401 | Key missing or invalid | Fix the key. |
402 premium_locked | Valid key, no paid plan | Upgrade to a paid plan; Voice turns on. |
413 | File over 8 MB | Split or compress before sending. |
429 | Rate limited | Back off and retry. |
400 | Unsupported option | You asked for streaming or srt/vtt. Drop it. |
Those model ids, that rate, the 8 MB limit, the format list: all current as of July 16, 2026. If you're reading this later, run GET /v1/models and check the guide before you trust the numbers on this page.
Receipts
Every claim here traces to a public surface. Run the curl commands yourself; the live API is the final word.
FluxRouter (published docs and live API):
- The
flux-voicemodel, the/v1/audio/transcriptionsendpoint, same key and base URL, request fields, response formats, the transparency headers, the paid-plan gate, the 8 MB limit, and the $0.10/audio-minute rate: Transcribe audio guide - The live, always-current id list (
flux-voice,flux-voice-accurate,flux-voice-fast):GET https://api.fluxrouter.ai/v1/models - The full id scheme and how the voice ids sit next to the text ones: Models
- Getting a key and your first call: Quickstart
Compatibility note: the request and response shape follow OpenAI's transcription API, which is why pointing an OpenAI-style client at Flux is a base-URL-and-key change.
Ready to wire it up? Grab a key from the quickstart, open the transcribe-audio guide, and remember Voice runs on a paid plan.
