Audio Tool
Speech-to-text and text-to-speech capabilities
Speech-to-Text (Transcription)
Transcribe audio to text. The endpoint is OpenAI-compatible, so
openai.audio.transcriptions.create(...) works against a Router9 base URL
unchanged.
Endpoint
POST /v1/audio/transcriptionsPOST /v1/audio/transcribe was removed. Use /v1/audio/transcriptions.
Request (multipart/form-data)
Upload an audio file directly — this is what the OpenAI SDKs send:
curl https://api.router9.com/v1/audio/transcriptions \
-H "Authorization: Bearer sk-r9k-your-key" \
-F [email protected] \
-F language=enRequest (JSON)
Provide audio by URL or base64, which is usually easier from a workflow or an agent that already holds a link rather than a file handle:
curl https://api.router9.com/v1/audio/transcriptions \
-H "Authorization: Bearer sk-r9k-your-key" \
-H "Content-Type: application/json" \
-d '{
"mediaUrl": "https://example.com/audio.mp3",
"language": "en"
}'| Parameter | Type | Required | Description |
|---|---|---|---|
file | binary | One of file/mediaUrl/mediaBase64 | Audio file (multipart upload) |
mediaUrl | string | One of file/mediaUrl/mediaBase64 | URL to audio file |
mediaBase64 | string | One of file/mediaUrl/mediaBase64 | Base64-encoded audio |
language | string | No | Language hint, e.g. en, zh |
model | string | No | Override the default transcription model (must be allowlisted) |
response_format | string | No | json (default), text, verbose_json, srt, vtt |
Response
response_format: "json" (the default):
{
"model": "google/gemini-3.5-flash",
"text": "Hello everyone, today we'll discuss the new API design."
}response_format: "text" returns the transcript as a plain text/plain body,
with no JSON wrapper. srt and vtt likewise return the subtitle file itself,
as application/x-subrip and text/vtt — not JSON with the file inside a
string.
response_format: "verbose_json" adds the timings:
{
"model": "nova-3",
"text": "Hello everyone, today we'll discuss the new API design.",
"language": "en",
"task": "transcribe",
"duration": 6.5,
"segments": [
{ "id": 0, "start": 0.1, "end": 2.0, "text": "Hello everyone,", "speaker": 0 },
{ "id": 1, "start": 2.0, "end": 6.5, "text": "today we'll discuss the new API design." }
]
}speaker is present only when the provider labelled one, and is omitted rather
than defaulted — speaker 0 is a real person in a diarized transcript.
verbose_json, srt and vtt are rendered from time-bounded segments, and not
every transcription provider produces them. Asking one that does not returns
400 naming the provider — before the call is made and billed, rather than
after. Call GET /v1/public/audio-models to see which formats the model you are
using can actually serve.
Text-to-Speech (Synthesis)
Convert text to spoken audio. POST /v1/audio/speech is the OpenAI-compatible
spelling of the same capability, so openai.audio.speech.create(...) works
unchanged.
Endpoint
POST /v1/audio/synthesize
POST /v1/audio/speechRequest
curl https://api.router9.com/v1/audio/synthesize \
-H "Authorization: Bearer sk-r9k-your-key" \
-H "Content-Type: application/json" \
-d '{
"input": "Hello, welcome to Router9!",
"voice": "English_Trustworthy_Man"
}' \
--output speech.mp3| Parameter | Type | Required | Description |
|---|---|---|---|
input | string | Yes | Text to synthesize |
voice | string | No | A voice id from GET /v1/audio/voices |
format | string | No | mp3 (default), wav, opus, flac, pcm |
speed | number | No | Playback rate |
model | string | No | Override the default TTS model (must be allowlisted) |
Voice ids are provider-specific. OpenAI names such as alloy or nova are not
valid — call GET /v1/audio/voices for the list, or omit voice to use the
deployment's default.
Response
The audio bytes, with Content-Type matching the requested format. Because a
binary body has nowhere to carry metadata, the numbers a caller needs travel in
headers: X-Router9-Audio-Characters, X-Router9-Audio-Format,
X-Router9-Audio-Duration-Ms, and X-Router9-Upstream-Trace-Id.
Catalogs
GET /v1/audio/voices → { "voices": [...] }
GET /v1/public/audio-models → { "speech": [...], "transcription": [...], "planLimits": {...} }Both are public. Each model in /v1/public/audio-models carries a constraints
block — the character cap, the formats, the response formats it can produce — so
a client can discover a limit without having to be refused by it. planLimits is
separate and stated per tier, because those are the caps your plan adds on top of
what the vendor accepts.
Errors
Every audio endpoint answers failures in the shared media error envelope. See Errors.
Credits
Audio Skill calls consume credits from your plan's monthly credit allowance — the same allowance used for chat completions. There are no separate per-Skill quotas. See Credits & Usage and Tool Usage & Credits.