Text to speech
Turn text into spoken audio in a choice of voices, from your agent through the Flux tools server or from your own code, streamed as it is made, on the same Flux key.
Send text and a voice, and get spoken audio back. Speech runs on the same Flux key and base URL (https://api.fluxrouter.ai/v1) as your chat requests, and it lands on the same bill.
| Way in | Status |
|---|---|
API: POST /v1/audio/speech | Rolling out |
Flux tools server: the speak tool | Shipping |
Voice list: GET /v1/audio/voices | Live |
The endpoint is OpenAI-compatible. If it is not switched on for your account yet, a call answers 404 and nothing is billed. Speech needs a paid plan; see What it costs.
For the other direction, audio into text, see Speech to text.
Choose a model and a voice
Two speech models are documented here:
| Model id | Use it for |
|---|---|
flux-voice-speak | The default. Every voice on its list, a speed setting, and instructions to steer tone and delivery. |
flux-voice-speak-hd | Higher-fidelity audio from a smaller set of the same voices. No instructions. |
Every request names a voice, and the voice has to belong to the model you picked. Choose a voice lists the voices, how to read them live for your key, and which ones flux-voice-speak-hd takes.
From your agent
Add the Flux tools server to your agent once, then ask it to speak. The tool is called speak.
Built into Murage, which decides which abilities it uses. Nothing to set up here. See murage.ai.
Built into Wayland, which decides which abilities it uses. Nothing to set up here. See getwayland.com.
Add the Flux tools server from your terminal.
claude mcp add --transport http flux-tools https://api.fluxrouter.ai/mcp-tools/ \
--header "Authorization: Bearer sk-YOUR-FLUX-KEY"
Then ask Claude Code:
Use the Flux speak tool to read this summary aloud in the nova voice, then decode the audio and save it as summary.mp3.
From Claude Code's own docs, checked 2026-09-28.
Add the Flux tools server to the same config. Codex reads the key from FLUX_API_KEY, which you exported above. File: ~/.codex/config.toml
[mcp_servers.flux-tools]
url = "https://api.fluxrouter.ai/mcp-tools/"
bearer_token_env_var = "FLUX_API_KEY"
Then ask Codex:
Use the Flux speak tool to read this summary aloud in the nova voice, then decode the audio and save it as summary.mp3.
From Codex's own docs, checked 2026-09-28.
Add the Flux tools server to your global MCP config, then restart Cursor. File: ~/.cursor/mcp.json
{
"mcpServers": {
"flux-tools": {
"url": "https://api.fluxrouter.ai/mcp-tools/",
"headers": {
"Authorization": "Bearer sk-YOUR-FLUX-KEY"
}
}
}
}
Then ask Cursor:
Use the Flux speak tool to read this summary aloud in the nova voice, then decode the audio and save it as summary.mp3.
From Cursor's own docs, checked 2026-09-28.
Add the Flux tools server to the same config, then restart Hermes. File: ~/.hermes/config.yaml
mcp_servers:
flux-tools:
url: "https://api.fluxrouter.ai/mcp-tools/"
headers:
Authorization: "Bearer sk-YOUR-FLUX-KEY"
Then ask Hermes:
Use the Flux speak tool to read this summary aloud in the nova voice, then decode the audio and save it as summary.mp3.
From Hermes's own docs, checked 2026-09-28.
Not checked yet. We have not checked how OpenClaw adds an MCP server, so we do not show a recipe. See OpenClaw's own docs.
Open Cline's MCP servers panel, edit the settings file, and add the Flux tools server.
{
"mcpServers": {
"flux-tools": {
"type": "streamableHttp",
"url": "https://api.fluxrouter.ai/mcp-tools/",
"headers": {
"Authorization": "Bearer sk-YOUR-FLUX-KEY"
}
}
}
}
Then ask Cline:
Use the Flux speak tool to read this summary aloud in the nova voice, then decode the audio and save it as summary.mp3.
From Cline's own docs, checked 2026-09-28.
The tool takes:
| Argument | Required | Notes |
|---|---|---|
text | yes | Up to 1,000 characters a call. |
voice | no | A voice id. The tool picks the model that owns that voice. Defaults to alloy. |
format | no | mp3 (the default) or wav. |
speed | no | A number; see the speed range under From code. |
The agent has to save the audio itself. The tool returns the audio inside its answer as base64, with its mime_type, bytes, billed_chars and cost_usd. Nothing is written to disk until the agent decodes it and writes a file, so say where to put it in your request, as the example does.
The tool's text limit is lower than the API's (4,096 characters) on purpose: base64 audio is large, and a long clip would fill the agent's context. For longer text, have the agent split it into parts and speak each one, or call the API from code.
From code
Send JSON with model, input and voice. The answer is audio bytes, not JSON.
curl https://api.fluxrouter.ai/v1/audio/speech \
-H "Authorization: Bearer sk-YOUR-FLUX-KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "flux-voice-speak",
"input": "Your build finished. All tests passed.",
"voice": "nova",
"response_format": "mp3"
}' \
--output done.mp3
from openai import OpenAI
client = OpenAI(
api_key="sk-YOUR-FLUX-KEY",
base_url="https://api.fluxrouter.ai/v1",
)
# Stream the audio to a file as it arrives, rather than holding it in memory.
with client.audio.speech.with_streaming_response.create(
model="flux-voice-speak",
input="Your build finished. All tests passed.",
voice="nova",
response_format="mp3",
) as response:
print(response.headers.get("x-flux-cost-usd"))
response.stream_to_file("done.mp3")
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 response = await client.audio.speech.create({
model: "flux-voice-speak",
input: "Your build finished. All tests passed.",
voice: "nova",
response_format: "mp3",
});
fs.writeFileSync("done.mp3", Buffer.from(await response.arrayBuffer()));
The request fields you will use most:
response_format:mp3(the default),opus,aac,flac,wavorpcm. Useopusfor voice notes,mp3for files people will download, andpcmfor the lowest-latency playback.speed: from 0.25 to 4, where1is normal speed.instructions(flux-voice-speakonly): plain-language direction for delivery, such as "Calm and warm, like a bedtime story" or "Brisk, like a news bulletin". Up to 4,096 characters.input: up to 4,096 characters a request. Split longer text at sentence ends and send each part in turn.
Every field, the content type for each format and the error codes are in the endpoint reference.
Playing a stream as it arrives
The audio streams back as it is made, so you can start playing before the whole clip exists. The first bytes arrive quickly; the rest follows in chunks.
The simplest way to hear it on a desktop is to pipe the stream into a player. ffplay comes with ffmpeg:
curl -sN https://api.fluxrouter.ai/v1/audio/speech \
-H "Authorization: Bearer $FLUX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"flux-voice-speak","input":"Hello from Flux.","voice":"nova"}' \
| ffplay -autoexit -nodisp -loglevel quiet -
In your own app, ask for pcm and write each chunk straight to the sound card. pcm is raw audio at 24 kHz, 16-bit, signed little-endian, mono, with no header, so there is nothing to decode:
import pyaudio
from openai import OpenAI
client = OpenAI(api_key="sk-YOUR-FLUX-KEY", base_url="https://api.fluxrouter.ai/v1")
player = pyaudio.PyAudio().open(format=pyaudio.paInt16, channels=1, rate=24000, output=True)
with client.audio.speech.with_streaming_response.create(
model="flux-voice-speak",
input="Hello from Flux. This starts playing before it has finished.",
voice="nova",
response_format="pcm",
) as response:
for chunk in response.iter_bytes(chunk_size=4096):
player.write(chunk)
If you play speech in a browser, call Flux from your server and pass the audio on. Never put your Flux key in browser code.
Limits
- Text: up to 4,096 characters a request on the API, and 1,000 characters a call on the
speaktool. - Time: if no audio arrives within 30 seconds, the request ends with a
504and you are not charged. Once audio is flowing, a gap of more than 30 seconds between chunks ends the stream. - Rate: up to 60 requests a minute per account, shared with transcription and search, and an hourly audio budget of 36,000 seconds of audio an hour, shared with transcription. Speech draws on that budget by an estimate of how long the text takes to say. Over either, you get
429; wait and retry.
What it costs
Speech is billed per character of input. Price: from $26 per 1M characters. The exact price for each model is on GET /v1/models, in the list_price_microcents field of the flux-voice-speak rows.
- Slowed speech costs more on
flux-voice-speak. Withspeedbelow1, the billed characters are the input length divided by the speed, rounded up, because slower speech makes longer audio. At1or faster you pay for the plain character count.flux-voice-speak-hdalways bills the plain count. - Nothing is billed before the first byte of audio. A request that fails before any audio arrives costs nothing. Once audio has started, the charge stands, even if your client disconnects.
Every successful response carries its receipt in the headers, which arrive with the first byte:
| Header | Meaning |
|---|---|
x-flux-routed-model | The model id that served |
x-flux-billed-chars | The characters you were billed for |
x-flux-cost-usd | What this request cost, in US dollars |
A key without a paid plan gets 402 with code premium_locked, and no audio is made or billed. See Plans.
Next
- Choose a voice
- Talk to your agent: speech in, an answer, and speech out.
- Text to speech problems, keyed by status code.