Fish Audio S2.1 Pro API: Pricing, Documentation
by Fish Audio
Fish Audio S2.1 Pro API provides a powerful, high-performance text-to-speech platform designed for rapid voice synthesis and cloning. It features advanced artificial intelligence models that process written text into highly natural, human-like voice outputs with extremely low latency. The interface enables developers to easily integrate professional audio capabilities, customize tonal qualities, and generate high-fidelity audio streams for diverse applications.

Models Version
Get $5 Free Credit on First Payment
No strings attached — add funds and get $5 bonus instantly
Fish Audio S2.1 Pro API Documentation
Generate natural, expressive speech from text in 83 languages, with free-form emotion markers and a library of over 2.5 million community voices. Asynchronous: submit returns a request_id; poll the status endpoint until the request is COMPLETED. Typical synthesis completes in a few seconds.
POST https://gateway.pixazo.ai/fish-audio-s2-1-pro/v1/text-to-speechAuthentication
All requests require an API key passed via header.
| Header | Type | Required | Description |
|---|---|---|---|
| Ocp-Apim-Subscription-Key | string | Yes | Your API subscription key |
Text to Speech - Fish Audio S2.1 Pro
Request Code
POST https://gateway.pixazo.ai/fish-audio-s2-1-pro/v1/text-to-speech
Content-Type: application/json
Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY
{
"text": "[whispering] When you are building something new, there is this mix of wonder and fear. [chuckling] But that is what makes it worth building.",
"reference_id": "933563129e564b19a115bedd57b7406a",
"format": "mp3",
"mp3_bitrate": 128
}import requests
url = "https://gateway.pixazo.ai/fish-audio-s2-1-pro/v1/text-to-speech"
headers = {
"Content-Type": "application/json",
"Ocp-Apim-Subscription-Key": "YOUR_SUBSCRIPTION_KEY"
}
data = {
"text": "[whispering] When you are building something new, there is this mix of wonder and fear. [chuckling] But that is what makes it worth building.",
"reference_id": "933563129e564b19a115bedd57b7406a",
"format": "mp3",
"mp3_bitrate": 128
}
resp = requests.post(url, json=data, headers=headers)
print(resp.json())const res = await fetch("https://gateway.pixazo.ai/fish-audio-s2-1-pro/v1/text-to-speech", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Ocp-Apim-Subscription-Key": "YOUR_SUBSCRIPTION_KEY"
},
body: JSON.stringify({
"text": "[whispering] When you are building something new, there is this mix of wonder and fear. [chuckling] But that is what makes it worth building.",
"reference_id": "933563129e564b19a115bedd57b7406a",
"format": "mp3",
"mp3_bitrate": 128
})
});
console.log(await res.json());curl -X POST 'https://gateway.pixazo.ai/fish-audio-s2-1-pro/v1/text-to-speech' \
-H 'Content-Type: application/json' \
-H 'Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY' \
--data-raw '{"text": "[whispering] When you are building something new, there is this mix of wonder and fear. [chuckling] But that is what makes it worth building.", "reference_id": "933563129e564b19a115bedd57b7406a", "format": "mp3", "mp3_bitrate": 128}'Output
{
"request_id": "fish-audio-s2-1-pro_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "QUEUED",
"polling_url": "https://gateway.pixazo.ai/v2/requests/status/fish-audio-s2-1-pro_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}Webhook (Optional)
Instead of polling, you can receive a Webhook callback when the request reaches a terminal state. Provide a Webhook URL via header on the submit request.
| Header | Required | Description |
|---|---|---|
| X-Webhook-URL | To enable | HTTPS URL to receive the Webhook callback. |
| X-Webhook-Mode | No | terminal (default, one callback on COMPLETED/ERROR) or sync (per-poll callbacks). |
Example: enable Webhook
curl -X POST 'https://gateway.pixazo.ai/fish-audio-s2-1-pro/v1/text-to-speech' \
-H 'Content-Type: application/json' \
-H 'Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY' \
-H 'X-Webhook-URL: https://your-server.com/webhook' \
--data-raw '{"text": "[whispering] When you are building something new, there is this mix of wonder and fear. [chuckling] But that is what makes it worth building.", "reference_id": "933563129e564b19a115bedd57b7406a", "format": "mp3", "mp3_bitrate": 128}'Callback Payload (success)
{
"request_id": "fish-audio-s2-1-pro_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "COMPLETED",
"model_id": "fish-audio-s2-1-pro",
"output": {
"media_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/fish-audio/1785407392754-66f0f615.mp3",
"media_type": "audio/mpeg"
},
"created_at": "2026-07-30T10:29:44.313Z",
"completed_at": "2026-07-30T10:29:53.391Z"
}Failure callback shape
{
"request_id": "fish-audio-s2-1-pro_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "ERROR",
"model_id": "fish-audio-s2-1-pro",
"error": "Description of the failure"
}Delivery semantics
- terminal mode: one Webhook callback when the request is COMPLETED or ERROR.
- sync mode: a Webhook callback on each status change.
- Callbacks are idempotent on
request_id— de-duplicate on it. - Respond
200within a few seconds; the Webhook endpoint must be HTTPS.
Request Parameters
| Parameter | Required | Type | Default | Allowed values / range | Description |
|---|---|---|---|---|---|
text | Yes | string | — | 1 – 5000 characters | The text to synthesize. Supports emotion and effect markers such as [whispering], [chuckling], [laughing], [sighing] and [audience laughing]. Markers are free-form and add no cost or latency. |
reference_id | No | string or array | — | 32-char hex voice id, or an array of up to 8 | The voice(s) to speak with. Pass a single string for one speaker, or an array of ids for multi-speaker dialogue (see Multi-Speaker Dialogue below). Omit to use the provider default voice. Browse voices at fish.audio; the id is the last path segment of fish.audio/m/<id>. You are responsible for holding the rights to any voice you reference. |
format | No | string | mp3 | mp3, wav | Output audio container. mp3 returns audio/mpeg; wav returns 16-bit mono PCM at 44.1 kHz. |
mp3_bitrate | No | integer | 128 | 64, 128, 192 | MP3 bitrate in kbps. Only valid when format is mp3; sending it with wav returns 400. |
latency | No | string | balanced | normal, balanced | Synthesis latency trade-off. balanced (our default) favours the lowest time-to-first-audio; normal accepts more latency in exchange for the provider's best quality. |
chunk_length | No | integer | 300 | 100 to 300 | Text chunk size used during synthesis. Smaller chunks start faster; larger chunks give steadier prosody across long passages. |
normalize | No | boolean | true | true, false | Normalize numbers, dates and abbreviations in English and Chinese text before synthesis. |
temperature | No | number | 0.7 | 0.0 to 1.0 | Controls expressiveness. Higher is more varied, lower is more consistent. |
top_p | No | number | 0.7 | 0.0 to 1.0 | Controls diversity via nucleus sampling. |
prosody | No | object | — | — | Optional prosody controls (see the two fields below). |
prosody.speed | No | number | 1.0 | 0.5 to 2.0 | Speaking rate multiplier. 2.0 is twice as fast, 0.5 is half speed. |
prosody.volume | No | number | 0 | -20 to 20 | Volume adjustment in decibels. |
Parameters not supported
Worth reading if you are porting existing Fish Audio code — some parameters are rejected outright, while others are accepted and then ignored.
Rejected with 400
| Parameter | Why | Use instead |
|---|---|---|
model | The model is fixed for this endpoint and is not caller-selectable. | — |
references | Inline zero-shot voice cloning requires a MessagePack request body, which this JSON endpoint cannot carry. | reference_id with a Fish Audio voice id |
format: "pcm" / "opus" | Not offered; mp3 and wav cover playback in every browser and player. | mp3 or wav |
Accepted but ignored
These are silently dropped — the request still returns 202, but the value has no effect on the generated audio. Only the parameters listed in the table above are forwarded.
sample_rate, opus_bitrate, max_new_tokens, repetition_penalty, min_chunk_length, condition_on_previous_chunks, early_stop_threshold, features, prosody.normalize_loudness, and any parameter not listed above |
Voice & Emotion Control
Choosing a voice
reference_id accepts two forms. Omit it entirely to use the provider default voice.
| Form | Use for | Value |
|---|---|---|
| String | A single speaker | "933563129e564b19a115bedd57b7406a" |
| Array | Multi-speaker dialogue | ["<speaker-0-id>", "<speaker-1-id>"] — up to 8 ids |
Voice ids are 32-character hexadecimal strings. Browse the Fish Audio voice library at fish.audio — the id is the last path segment of fish.audio/m/<id>.
Multi-Speaker Dialogue
Pass an array of voice ids and mark speaker changes in text with <|speaker:N|> tags. The index in the tag selects the voice at that position in the array — <|speaker:0|> uses the first id, <|speaker:1|> the second, and so on.
{
"text": "<|speaker:0|>Good morning!<|speaker:1|>Good morning! How are you?<|speaker:0|>I am great, thanks for asking!",
"reference_id": [
"933563129e564b19a115bedd57b7406a",
"d13f84b987ad4f22b56d2b47f4eb838e"
],
"format": "mp3"
}- Text before any tag is spoken by the first voice in the array.
- A tag index with no matching array entry is not valid — supply one id per speaker index you use.
- Passing two or more ids without any
<|speaker:N|>tag returns400, because every line would otherwise be rendered in the first voice. - For a single speaker, pass the id as a plain string — tags are not needed.
Emotion & effect markers
Place markers inline in text using square brackets. They are interpreted as performance direction and are not spoken aloud.
| Category | Examples |
|---|---|
| Emotions | [happy], [sad], [angry], [excited], [calm], [nervous], [confident], [sarcastic] |
| Tone | [whispering], [shouting], [soft tone], [in a hurry tone], [emphasis] |
| Audio effects | [laughing], [chuckling], [sighing], [gasping], [panting], [clear throat] |
| Special | [audience laughing], [background laughter], [break], [long-break] |
Markers are not restricted to this list — any descriptive phrase works, for example [whispers sweetly] or [laughing nervously]. Use at most three emotion markers per sentence, and place sentence-level direction at the start of the sentence. Markers add no character cost and no latency.
Example Request
{
"text": "[whispering] When you are building something new, there is this mix of wonder and fear. [chuckling] But that is what makes it worth building.",
"reference_id": "933563129e564b19a115bedd57b7406a",
"format": "mp3",
"mp3_bitrate": 128
}Example Response
{
"request_id": "fish-audio-s2-1-pro_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "QUEUED",
"polling_url": "https://gateway.pixazo.ai/v2/requests/status/fish-audio-s2-1-pro_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}Request Headers
| Header | Required | Description |
|---|---|---|
| Content-Type | Yes | application/json |
| Ocp-Apim-Subscription-Key | Yes | Your API subscription key. |
| X-Webhook-URL | No | Enable Webhook callbacks (see Webhook section). |
Response Handling
| Status Code | Meaning |
|---|---|
| 202 | Accepted — request queued; returns request_id and polling_url. |
| 400 | Bad request — invalid or missing parameters: missing text, text over 5000 characters, a malformed reference_id, mp3_bitrate sent with format: "wav", or two or more reference_id values without <|speaker:N|> tags. Also returned for references and model — see “Parameters not supported” above. |
| 401 | Unauthorized — missing or invalid subscription key. |
| 402 | Insufficient balance. |
| 403 | Forbidden. |
| 429 | Too many requests. |
| 500 | Internal server error. |
Error Responses
{
"error": "Insufficient Balance",
"message": "Your wallet does not have enough balance."
}A failed generation is reported via the status endpoint (or Webhook) with status: "ERROR" and an error message — for example Reference not found when reference_id does not name an existing voice.
Retrieving Results
Poll the status endpoint with the request_id from the submit response until status is COMPLETED (or FAILED/ERROR).
curl 'https://gateway.pixazo.ai/v2/requests/status/fish-audio-s2-1-pro_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' \
-H 'Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY'Completed response
{
"request_id": "fish-audio-s2-1-pro_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "COMPLETED",
"model_id": "fish-audio-s2-1-pro",
"output": {
"media_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/fish-audio/1785407392754-66f0f615.mp3",
"media_type": "audio/mpeg"
},
"created_at": "2026-07-30T10:29:44.313Z",
"completed_at": "2026-07-30T10:29:53.391Z"
}Response Fields
| Field | Type | Description |
|---|---|---|
| request_id | string | Unique request identifier. |
| status | string | QUEUED, PROCESSING, COMPLETED, FAILED, or ERROR. |
| model_id | string | The model that handled the request. |
| output.media_url | string | Permanent URL of the generated audio. |
| output.media_type | string | Audio MIME type (audio/mpeg for mp3, audio/wav for wav). |
| created_at | string | Request creation timestamp. |
| completed_at | string | Completion timestamp. |
| polling_url | string | Status URL for this request. |
| error | string | Error message when status is FAILED/ERROR. |
Status Values & Flow
QUEUED → PROCESSING → COMPLETED (success) or FAILED/ERROR (failure).
Pricing
Billed at $0.02 per 1,000 UTF-8 bytes of input text, rounded up to the next whole 1,000. Every request bills at least one block.
Billing is measured in UTF-8 bytes, not characters. For English and other Latin-script text the two are the same — one character is one byte — but characters outside the ASCII range take more than one byte, so the same character count costs more in those languages.
| Input | Characters | UTF-8 bytes | Blocks | Cost |
|---|---|---|---|---|
| English | 500 | 500 | 1 | $0.02 |
| English | 1,200 | 1,200 | 2 | $0.04 |
| Chinese / Japanese (3 bytes per character) | 416 | 1,248 | 2 | $0.04 |
| Maximum single request, English | 5,000 | 5,000 | 5 | $0.10 |
The 5,000-character limit on text counts characters, not bytes — and characters outside the Basic Multilingual Plane (most emoji) count as two toward it. The most expensive possible request is therefore 5,000 three-byte characters, such as Chinese or Japanese: 15,000 bytes, or $0.30. Text made of 4-byte characters hits the limit at 2,500 characters, or $0.20.
Fish Audio S2.1 Pro API Pricing
Fish Audio Speech to Text API Documentation
Transcribe audio into text with automatic language detection and optional word-level timestamps. Asynchronous: submit returns a request_id; poll the status endpoint until the request is COMPLETED. The transcript is returned as a JSON file.
POST https://gateway.pixazo.ai/fish-audio-speech-to-text/v1/speech-to-textAuthentication
All requests require an API key passed via header.
| Header | Type | Required | Description |
|---|---|---|---|
| Ocp-Apim-Subscription-Key | string | Yes | Your API subscription key |
Speech to Text - Fish Audio
Request Code
POST https://gateway.pixazo.ai/fish-audio-speech-to-text/v1/speech-to-text
Content-Type: application/json
Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY
{
"audio_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3",
"language": "en",
"ignore_timestamps": false
}import requests
url = "https://gateway.pixazo.ai/fish-audio-speech-to-text/v1/speech-to-text"
headers = {
"Content-Type": "application/json",
"Ocp-Apim-Subscription-Key": "YOUR_SUBSCRIPTION_KEY"
}
data = {
"audio_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3",
"language": "en",
"ignore_timestamps": false
}
resp = requests.post(url, json=data, headers=headers)
print(resp.json())const res = await fetch("https://gateway.pixazo.ai/fish-audio-speech-to-text/v1/speech-to-text", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Ocp-Apim-Subscription-Key": "YOUR_SUBSCRIPTION_KEY"
},
body: JSON.stringify({
"audio_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3",
"language": "en",
"ignore_timestamps": false
})
});
console.log(await res.json());curl -X POST 'https://gateway.pixazo.ai/fish-audio-speech-to-text/v1/speech-to-text' \
-H 'Content-Type: application/json' \
-H 'Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY' \
--data-raw '{"audio_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3", "language": "en", "ignore_timestamps": false}'Output
{
"request_id": "fish-audio-speech-to-text_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "QUEUED",
"polling_url": "https://gateway.pixazo.ai/v2/requests/status/fish-audio-speech-to-text_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}Webhook (Optional)
Instead of polling, you can receive a Webhook callback when the request reaches a terminal state. Provide a Webhook URL via header on the submit request.
| Header | Required | Description |
|---|---|---|
| X-Webhook-URL | To enable | HTTPS URL to receive the Webhook callback. |
| X-Webhook-Mode | No | terminal (default, one callback on COMPLETED/ERROR) or sync (per-poll callbacks). |
Example: enable Webhook
curl -X POST 'https://gateway.pixazo.ai/fish-audio-speech-to-text/v1/speech-to-text' \
-H 'Content-Type: application/json' \
-H 'Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY' \
-H 'X-Webhook-URL: https://your-server.com/webhook' \
--data-raw '{"audio_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3", "language": "en", "ignore_timestamps": false}'Callback Payload (success)
{
"request_id": "fish-audio-speech-to-text_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "COMPLETED",
"model_id": "fish-audio-speech-to-text",
"output": {
"media_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/v1/{request_id}/output.json",
"media_type": "application/json"
},
"created_at": "2026-07-30T14:49:39.898Z",
"completed_at": "2026-07-30T14:49:59.000Z"
}Failure callback shape
{
"request_id": "fish-audio-speech-to-text_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "ERROR",
"model_id": "fish-audio-speech-to-text",
"error": "Description of the failure"
}Delivery semantics
- terminal mode: one Webhook callback when the request is COMPLETED or ERROR.
- sync mode: a Webhook callback on each status change.
- Callbacks are idempotent on
request_id— de-duplicate on it. - Respond
200within a few seconds; the Webhook endpoint must be HTTPS.
Request Parameters
| Parameter | Required | Type | Default | Allowed values / range | Description |
|---|---|---|---|---|---|
audio_url | Yes | string | — | http(s) URL, file up to 25 MB | Public URL of the audio to transcribe. Common formats are supported, including mp3, wav, m4a, flac and ogg. The file is fetched by the gateway, so the URL must be reachable without authentication. |
language | No | string | — (auto-detected) | One of 57 ISO codes: af (Afrikaans), ar (Arabic), hy (Armenian), az (Azerbaijani), be (Belarusian), bs (Bosnian), bg (Bulgarian), ca (Catalan), zh (Chinese), hr (Croatian), cs (Czech), da (Danish), nl (Dutch), en (English), et (Estonian), fi (Finnish), fr (French), gl (Galician), de (German), el (Greek), he (Hebrew), hi (Hindi), hu (Hungarian), is (Icelandic), id (Indonesian), it (Italian), ja (Japanese), kn (Kannada), kk (Kazakh), ko (Korean), lv (Latvian), lt (Lithuanian), mk (Macedonian), ms (Malay), mr (Marathi), mi (Maori), ne (Nepali), no (Norwegian), fa (Persian), pl (Polish), pt (Portuguese), ro (Romanian), ru (Russian), sr (Serbian), sk (Slovak), sl (Slovenian), es (Spanish), sw (Swahili), sv (Swedish), tl (Tagalog), ta (Tamil), th (Thai), tr (Turkish), uk (Ukrainian), ur (Urdu), vi (Vietnamese), cy (Welsh) | Optional language hint. Omit it and the model detects the language automatically, returning what it found in the transcript. There is no auto option — sending a placeholder such as "auto-detected" is rejected with HTTP 400. |
ignore_timestamps | No | boolean | true | true, false | Set to false to include word-level segments with start and end times. Adds latency on audio shorter than 30 seconds. |
Audio limits
- The audio file must be at most 25 MB. Larger files are rejected before transcription starts.
audio_urlmust be anhttporhttpsURL and must be publicly reachable.- There is no fixed duration limit; cost scales with the length of the audio (see Pricing).
Transcript Format
The completed request returns output.media_url, a JSON file containing the transcript. Fetch that URL to read the result.
{
"text": "Strong consistency test. This should complete in a few seconds, not sixty.",
"language": "English",
"language_code": "en",
"duration": 5.8253125,
"segments": [
{
"text": "Strong",
"start": 0,
"end": 0.56
},
{
"text": "consistency",
"start": 0.56,
"end": 1.12
}
]
}| Field | Type | Description |
|---|---|---|
| text | string | The full transcript. |
| language | string | Detected language name, e.g. English. |
| language_code | string | Detected language code, e.g. en. |
| duration | number | Length of the transcribed audio in seconds. This is the quantity you are billed on. |
| segments | array | Word-level entries of {text, start, end} with times in seconds. Empty unless ignore_timestamps is false. |
Example Request
{
"audio_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3",
"language": "en",
"ignore_timestamps": false
}Example Response
{
"request_id": "fish-audio-speech-to-text_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "QUEUED",
"polling_url": "https://gateway.pixazo.ai/v2/requests/status/fish-audio-speech-to-text_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}Request Headers
| Header | Required | Description |
|---|---|---|
| Content-Type | Yes | application/json |
| Ocp-Apim-Subscription-Key | Yes | Your API subscription key. |
| X-Webhook-URL | No | Enable Webhook callbacks (see Webhook section). |
Response Handling
| Status Code | Meaning |
|---|---|
| 202 | Accepted — request queued; returns request_id and polling_url. |
| 400 | Bad request — missing audio_url, a non-http(s) URL, or a wrongly typed language / ignore_timestamps. |
| 401 | Unauthorized — missing or invalid subscription key. |
| 402 | Insufficient balance. |
| 429 | Too many requests. |
| 500 | Internal server error. |
An unreachable audio_url, an oversized file, or a file that is not recognisable audio is reported through the status endpoint as status: "ERROR", not as a synchronous error. Failed requests are not billed.
Retrieving Results
Poll the status endpoint with the request_id from the submit response until status is COMPLETED (or FAILED/ERROR), then fetch output.media_url for the transcript.
curl 'https://gateway.pixazo.ai/v2/requests/status/fish-audio-speech-to-text_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' \
-H 'Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY'Completed response
{
"request_id": "fish-audio-speech-to-text_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "COMPLETED",
"model_id": "fish-audio-speech-to-text",
"output": {
"media_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/v1/{request_id}/output.json",
"media_type": "application/json"
},
"created_at": "2026-07-30T14:49:39.898Z",
"completed_at": "2026-07-30T14:49:59.000Z"
}Response Fields
| Field | Type | Description |
|---|---|---|
| request_id | string | Unique request identifier. |
| status | string | QUEUED, PROCESSING, COMPLETED, FAILED, or ERROR. |
| model_id | string | The model that handled the request. |
| output.media_url | string | URL of the transcript JSON file. |
| output.media_type | string | application/json. |
| created_at | string | Request creation timestamp. |
| completed_at | string | Completion timestamp. |
| error | string | Error message when status is FAILED/ERROR. |
Status Values & Flow
QUEUED → PROCESSING → COMPLETED (success) or FAILED/ERROR (failure).
Pricing
Billed at $0.006 per minute of audio ($0.36 per audio hour), rounded up to the next whole minute. Billing is based on the length of the audio you submit, not on the size of the transcript.
| Audio length | Billed minutes | Cost |
|---|---|---|
| 6 seconds | 1 | $0.006 |
| 90 seconds | 2 | $0.012 |
| 10 minutes | 10 | $0.06 |
| 1 hour | 60 | $0.36 |
A hold is placed when the request is submitted, because the audio length is not known until transcription completes. The hold is reduced to the real cost once the duration is known, and released in full if the request fails.
Fish Audio Speech to Text API Pricing
⚡ Performance
Live usage measured on Pixazo's gateway, split by model version. Generation time is how long a generation takes end-to-end (lower is better). Success rate is the percent of generations that complete (higher is better).
〰 Uptime
Percent of generations that succeeded over the selected period, per model version.