curl --request POST \
--url https://api.fish.audio/v1/asr \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: multipart/form-data' \
--form audio='@example-file' \
--form 'language=<string>' \
--form ignore_timestamps=trueimport requests
url = "https://api.fish.audio/v1/asr"
files = { "audio": ("example-file", open("example-file", "rb")) }
payload = {
"language": "<string>",
"ignore_timestamps": "true"
}
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('audio', '<string>');
form.append('language', '<string>');
form.append('ignore_timestamps', 'true');
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
options.body = form;
fetch('https://api.fish.audio/v1/asr', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.fish.audio/v1/asr",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"audio\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"language\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"ignore_timestamps\"\r\n\r\ntrue\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: multipart/form-data"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.fish.audio/v1/asr"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"audio\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"language\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"ignore_timestamps\"\r\n\r\ntrue\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.fish.audio/v1/asr")
.header("Authorization", "Bearer <token>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"audio\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"language\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"ignore_timestamps\"\r\n\r\ntrue\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.fish.audio/v1/asr")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"audio\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"language\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"ignore_timestamps\"\r\n\r\ntrue\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"text": "<string>",
"duration": 123,
"segments": [
{
"text": "<string>",
"start": 123,
"end": 123
}
],
"language_code": "<string>",
"language": "<string>"
}{
"status": 123,
"message": "<string>",
"reason": "<string>"
}{
"status": 123,
"message": "<string>",
"reason": "<string>"
}{
"status": 123,
"message": "<string>",
"reason": "<string>"
}Speech to Text
Transcribe audio with transcribe-1 or transcribe-1-pro, with optional timestamps and emotion cues
curl --request POST \
--url https://api.fish.audio/v1/asr \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: multipart/form-data' \
--form audio='@example-file' \
--form 'language=<string>' \
--form ignore_timestamps=trueimport requests
url = "https://api.fish.audio/v1/asr"
files = { "audio": ("example-file", open("example-file", "rb")) }
payload = {
"language": "<string>",
"ignore_timestamps": "true"
}
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('audio', '<string>');
form.append('language', '<string>');
form.append('ignore_timestamps', 'true');
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
options.body = form;
fetch('https://api.fish.audio/v1/asr', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.fish.audio/v1/asr",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"audio\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"language\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"ignore_timestamps\"\r\n\r\ntrue\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: multipart/form-data"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.fish.audio/v1/asr"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"audio\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"language\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"ignore_timestamps\"\r\n\r\ntrue\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.fish.audio/v1/asr")
.header("Authorization", "Bearer <token>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"audio\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"language\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"ignore_timestamps\"\r\n\r\ntrue\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.fish.audio/v1/asr")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"audio\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"language\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"ignore_timestamps\"\r\n\r\ntrue\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"text": "<string>",
"duration": 123,
"segments": [
{
"text": "<string>",
"start": 123,
"end": 123
}
],
"language_code": "<string>",
"language": "<string>"
}{
"status": 123,
"message": "<string>",
"reason": "<string>"
}{
"status": 123,
"message": "<string>",
"reason": "<string>"
}{
"status": 123,
"message": "<string>",
"reason": "<string>"
}multipart/form-data (a file upload)
or application/msgpack. JSON with base64-encoded audio is not supported.Select a model
SendPOST https://api.fish.audio/v1/asr with Authorization: Bearer <API_KEY> and an optional model HTTP header:
| Header value | Behavior |
|---|---|
transcribe-1 | General transcription; the default if the header is omitted. |
transcribe-1-pro | Transcription of multi-speaker conversations, preserving emotion and vocal-event cues in the text. |
| Field | Required | Default | Description |
|---|---|---|---|
audio | Yes | — | Audio file upload for multipart, or raw audio bytes for MessagePack. |
language | No | Unset | Optional language hint, such as en, zh, or ja. The language is still auto-detected. |
ignore_timestamps | No | true | Set to false to request timestamped segments. Alignment adds processing time. |
curl --request POST https://api.fish.audio/v1/asr \
--header "Authorization: Bearer $FISH_API_KEY" \
--header "model: transcribe-1-pro" \
--form audio=@conversation.wav \
--form ignore_timestamps=false
Content-Type and boundary. For MessagePack, set Content-Type: application/msgpack and encode audio as binary bytes. See the Speech to Text guide for an example.
Read the response
| Field | Description |
|---|---|
text | Full transcript. Pro includes inline speaker markers such as <|speaker:0|> and can include emotion and vocal-event cues such as [高兴] (happy) or [laughter]. |
duration | Audio duration in seconds. |
segments | Array of { "text": string, "start": number, "end": number }, with timestamps in seconds. Empty when timestamps are skipped; can also be empty if alignment is unavailable or no speech is detected. |
language_code | Detected language code, such as en or ja, when available. Use this field in application logic. |
language | Detected language name, such as English, when available. Intended for display. |
Multi-speaker response format
Pro returns speaker turns inside thetext string, using <|speaker:N|> markers. The numeric label N identifies the speaker for the text that follows, up to the next marker. A repeated label means that speaker is speaking again. Labels apply within the recording; they are not names or identities shared across requests.
This illustrative response has two speakers and three turns. With ignore_timestamps=true, timestamps are skipped:
{
"text": "<|speaker:0|>你好。<|speaker:1|>[高兴]很开心认识你。<|speaker:0|>我也是。",
"duration": 6.4,
"segments": [],
"language_code": "zh",
"language": "Chinese"
}
你好。, speaker 1 saying [高兴]很开心认识你。, and speaker 0 saying 我也是。. The [高兴] cue describes the delivery of speaker 1’s speech.
With ignore_timestamps=false (as in the curl example above), the same markers remain in text. The segments array contains timed speech with text, start, and end; alignment excludes speaker, emotion, and event markers. Segments are not speaker turns and do not contain a speaker_id field.
The API returns no separate speaker list or emotion field. Parse the inline markers in text when your application needs speaker turns or emotion cues. See the speaker parsing example.
See the model capabilities and SDK examples for more detail.Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Headers
Specify which speech-to-text model to use.
transcribe-1, transcribe-1-pro Body
Audio file to be converted to text
Optional hint. The language is auto-detected regardless; the detected language is returned as language_code.
Whether to return precise timestamps in the text, this will increase the latency in audio shorter than 30 seconds
Response
Request fulfilled, document follows
Duration of the audio in seconds
Show child attributes
Show child attributes
Detected language as an ISO 639-1 code (e.g. en, ja). Omitted if no language is detected.
Detected language name (e.g. English). For display only; use language_code in code.
Was this page helpful?

