POST /v1/audio/transcriptions
The exact contract for Flux speech to text: multipart request fields, the response for each format, receipt headers, limits and every error code.
Turns speech in an audio file into text. For a guided introduction, see Speech to text.
| Endpoint | POST https://api.fluxrouter.ai/v1/audio/transcriptions |
| Request | multipart/form-data |
| Auth | Authorization: Bearer <your Flux key> |
| Plan | Paid |
| Streaming | No |
| Status | Live |
The same route also answers at /audio/transcriptions, without the /v1.
Request fields
| Field | Required | Type | Notes |
|---|---|---|---|
file | yes | file | The audio. The format is read from the contents: wav, mp3, mp4/m4a, ogg (including Opus), webm or flac. Up to 8 MB. |
model | no | string | flux-voice (the default), flux-voice-accurate or flux-voice-fast. An unknown id is treated as flux-voice. |
language | no | string | ISO-639-1 code, such as en. Leave it out to detect the language. |
prompt | no | string | Names, jargon or spellings to expect. Cut to 2,000 characters. |
temperature | no | number | Sampling temperature. |
response_format | no | string | json (the default), verbose_json or text. srt and vtt are refused. |
timestamp_granularities[] | no | string, repeatable | word, segment or both. Only affects verbose_json. |
Sending stream=true is refused with 400: there is no streaming transcription.
Response
The body depends on response_format.
json (the default):
{ "text": "Let's move the launch to Thursday." }
text: the transcript as a plain text body, with no JSON around it.
verbose_json:
{
"task": "transcribe",
"language": "english",
"duration": 3.2,
"text": "Let's move the launch to Thursday.",
"segments": [
{ "id": 0, "start": 0.0, "end": 3.2, "text": "Let's move the launch to Thursday." }
],
"words": [
{ "word": "Let's", "start": 0.0, "end": 0.3 }
]
}
segmentsis always present inverbose_json. Segments can carry more fields than shown; rely onstart,endandtext.wordsis present only when you sendtimestamp_granularities[]=word.- Times are in seconds from the start of the file.
Response headers
| Header | Meaning |
|---|---|
x-flux-routed-model | The model id that served: flux-voice, flux-voice-accurate or flux-voice-fast |
x-flux-billed-seconds | Seconds billed: the audio length rounded up, at least 10 seconds |
x-flux-cost-usd | What this request cost, in US dollars |
Limits
| Limit | Value |
|---|---|
| File size | 8 MB |
| Processing time | 60 seconds, then 504 |
| Requests | 60 requests a minute per account |
| Audio | 36,000 seconds of audio an hour per account, shared with speech |
Errors
Errors use this envelope:
{
"error": {
"message": "unsupported or unrecognized audio format",
"type": "invalid_request_error",
"code": "unsupported_file_format",
"param": "file"
}
}
code and param are present only when they apply.
| Status | code | Meaning | Billed |
|---|---|---|---|
400 | unsupported_file_format | The file is not audio in a format listed above. | No |
400 | none, param set | A field is wrong: stream, response_format, or a missing or unreadable file. param names it. | No |
401 | none | The key was missing or not accepted, or flux-voice is not on the key's model list. | No |
402 | premium_locked | The key's plan does not include transcription. | No |
402 | credit_unresolved | Your credit balance could not be checked. Retry shortly. | No |
402 | another code | A spend cap or prepaid balance stopped the request. See Spend caps. | No |
404 | none | Transcription is not switched on for this deployment. | No |
413 | file_too_large | The file is over the size limit. | No |
429 | rate_limit_error | Over the per-account request rate or hourly audio budget. Wait, then retry. | No |
502 | capability_unavailable | Transcription failed upstream. Retry. | No |
504 | capability_unavailable | Transcription took too long. Retry, or send a shorter file. | No |
Fixes for each are on Speech to text problems.
Example requests
curl https://api.fluxrouter.ai/v1/audio/transcriptions \
-H "Authorization: Bearer sk-YOUR-FLUX-KEY" \
-F "file=@meeting.m4a" \
-F "model=flux-voice"
from openai import OpenAI
client = OpenAI(
api_key="sk-YOUR-FLUX-KEY",
base_url="https://api.fluxrouter.ai/v1",
)
with open("meeting.m4a", "rb") as audio:
result = client.audio.transcriptions.create(
model="flux-voice",
file=audio,
)
print(result.text)
import fs from "node:fs";
import OpenAI from "openai";
const client = new OpenAI({
apiKey: "sk-YOUR-FLUX-KEY",
baseURL: "https://api.fluxrouter.ai/v1",
});
const result = await client.audio.transcriptions.create({
model: "flux-voice",
file: fs.createReadStream("meeting.m4a"),
});
console.log(result.text);
Word timestamps, with the receipt headers printed:
curl -i https://api.fluxrouter.ai/v1/audio/transcriptions \
-H "Authorization: Bearer $FLUX_API_KEY" \
-F "file=@note.ogg" \
-F "model=flux-voice" \
-F "language=en" \
-F "response_format=verbose_json" \
-F "timestamp_granularities[]=word"
With Python's requests, reading the cost:
import requests
with open("meeting.m4a", "rb") as audio:
r = requests.post(
"https://api.fluxrouter.ai/v1/audio/transcriptions",
headers={"Authorization": "Bearer sk-YOUR-FLUX-KEY"},
files={"file": ("meeting.m4a", audio)},
data={"model": "flux-voice", "response_format": "json"},
timeout=90,
)
r.raise_for_status()
print(r.json()["text"])
print(r.headers["x-flux-billed-seconds"], r.headers["x-flux-cost-usd"])