curl --request POST \
--url http://127.0.0.1:{port}/transcribe \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"file": "<string>",
"audio_base64": "<string>",
"mime_type": "<string>",
"mode_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"engine": "<string>",
"model": "<string>",
"language": "<string>",
"timestamp_granularities": []
}
'import requests
url = "http://127.0.0.1:{port}/transcribe"
payload = {
"file": "<string>",
"audio_base64": "<string>",
"mime_type": "<string>",
"mode_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"engine": "<string>",
"model": "<string>",
"language": "<string>",
"timestamp_granularities": []
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
file: '<string>',
audio_base64: '<string>',
mime_type: '<string>',
mode_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
engine: '<string>',
model: '<string>',
language: '<string>',
timestamp_granularities: []
})
};
fetch('http://127.0.0.1:{port}/transcribe', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_PORT => "62437",
CURLOPT_URL => "http://127.0.0.1:{port}/transcribe",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'file' => '<string>',
'audio_base64' => '<string>',
'mime_type' => '<string>',
'mode_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'engine' => '<string>',
'model' => '<string>',
'language' => '<string>',
'timestamp_granularities' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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 := "http://127.0.0.1:{port}/transcribe"
payload := strings.NewReader("{\n \"file\": \"<string>\",\n \"audio_base64\": \"<string>\",\n \"mime_type\": \"<string>\",\n \"mode_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"engine\": \"<string>\",\n \"model\": \"<string>\",\n \"language\": \"<string>\",\n \"timestamp_granularities\": []\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("http://127.0.0.1:{port}/transcribe")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"file\": \"<string>\",\n \"audio_base64\": \"<string>\",\n \"mime_type\": \"<string>\",\n \"mode_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"engine\": \"<string>\",\n \"model\": \"<string>\",\n \"language\": \"<string>\",\n \"timestamp_granularities\": []\n}")
.asString();require 'uri'
require 'net/http'
url = URI("http://127.0.0.1:{port}/transcribe")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"file\": \"<string>\",\n \"audio_base64\": \"<string>\",\n \"mime_type\": \"<string>\",\n \"mode_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"engine\": \"<string>\",\n \"model\": \"<string>\",\n \"language\": \"<string>\",\n \"timestamp_granularities\": []\n}"
response = http.request(request)
puts response.read_body{
"ok": true,
"text": "<string>",
"engine": "<string>",
"model": "<string>",
"language": "<string>",
"timings": {
"load_ms": 123,
"decode_ms": 123
},
"latency_ms": 123,
"raw_text": "<string>",
"segments": [
{
"id": 123,
"text": "<string>",
"start": 123,
"end": 123
}
],
"words": [
{
"word": "<string>",
"start": 123,
"end": 123
}
]
}Transcribe audio
Accepts either an absolute file path OR an audio_base64 + mime_type
pair. The engine + model can come from a saved mode_id, from explicit
engine/model/language fields, or a mix (mode supplies defaults
and per-call fields override).
curl --request POST \
--url http://127.0.0.1:{port}/transcribe \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"file": "<string>",
"audio_base64": "<string>",
"mime_type": "<string>",
"mode_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"engine": "<string>",
"model": "<string>",
"language": "<string>",
"timestamp_granularities": []
}
'import requests
url = "http://127.0.0.1:{port}/transcribe"
payload = {
"file": "<string>",
"audio_base64": "<string>",
"mime_type": "<string>",
"mode_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"engine": "<string>",
"model": "<string>",
"language": "<string>",
"timestamp_granularities": []
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
file: '<string>',
audio_base64: '<string>',
mime_type: '<string>',
mode_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
engine: '<string>',
model: '<string>',
language: '<string>',
timestamp_granularities: []
})
};
fetch('http://127.0.0.1:{port}/transcribe', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_PORT => "62437",
CURLOPT_URL => "http://127.0.0.1:{port}/transcribe",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'file' => '<string>',
'audio_base64' => '<string>',
'mime_type' => '<string>',
'mode_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'engine' => '<string>',
'model' => '<string>',
'language' => '<string>',
'timestamp_granularities' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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 := "http://127.0.0.1:{port}/transcribe"
payload := strings.NewReader("{\n \"file\": \"<string>\",\n \"audio_base64\": \"<string>\",\n \"mime_type\": \"<string>\",\n \"mode_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"engine\": \"<string>\",\n \"model\": \"<string>\",\n \"language\": \"<string>\",\n \"timestamp_granularities\": []\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("http://127.0.0.1:{port}/transcribe")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"file\": \"<string>\",\n \"audio_base64\": \"<string>\",\n \"mime_type\": \"<string>\",\n \"mode_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"engine\": \"<string>\",\n \"model\": \"<string>\",\n \"language\": \"<string>\",\n \"timestamp_granularities\": []\n}")
.asString();require 'uri'
require 'net/http'
url = URI("http://127.0.0.1:{port}/transcribe")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"file\": \"<string>\",\n \"audio_base64\": \"<string>\",\n \"mime_type\": \"<string>\",\n \"mode_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"engine\": \"<string>\",\n \"model\": \"<string>\",\n \"language\": \"<string>\",\n \"timestamp_granularities\": []\n}"
response = http.request(request)
puts response.read_body{
"ok": true,
"text": "<string>",
"engine": "<string>",
"model": "<string>",
"language": "<string>",
"timings": {
"load_ms": 123,
"decode_ms": 123
},
"latency_ms": 123,
"raw_text": "<string>",
"segments": [
{
"id": 123,
"text": "<string>",
"start": 123,
"end": 123
}
],
"words": [
{
"word": "<string>",
"start": 123,
"end": 123
}
]
}Authorizations
Token from the discovery file. Required on every endpoint except /health.
Body
Absolute filesystem path. Mutually exclusive with audio_base64. Where a platform applies the 48 MiB audio limit to a file path, a larger file is refused with INVALID_REQUEST — see Request limits in the Local API overview for what each platform enforces.
base64-encoded audio bytes. Pair with mime_type.
e.g. audio/wav, audio/m4a, audio/mpeg, audio/flac
Saved Mode used as the baseline. May be combined with engine/model/language to override per-call. When mode_id and engine name DIFFERENT cloud providers, the Mode's saved model is not carried across to the new provider: the request runs the engine's own default model. An inherited model is kept only when it really belongs to the engine you named — including under its legacy spelling, so an AssemblyAI Mode on universal re-run with engine: "assemblyai" still runs universal and is not upgraded to a different-priced model. Send an explicit model to pin one; for a BYOK provider that wins outright. HyperWhisper Cloud is different, because it selects by the Mode's accuracy tier rather than by a model id: engine: "cloud" keeps the Mode's model only when that model belongs to the tier, and otherwise runs the tier's default — an explicit model included. The default a dropped model falls back to is the same on every platform: every head reads it from cloud-stt-catalog.json, and shared-conformance/default-model-vectors.json pins the answer for all of them, so engine: "openai" with no model resolves to gpt-transcribe everywhere. The legacy engine names googlespeech and microsoftazurespeech now fold onto the same HyperWhisper Cloud accuracy tiers on every platform too, so neither of the two gaps this paragraph used to list is still open.
whisperLocal | parakeet | nemotron | qwen3Asr | appleSpeech | . nemotron and appleSpeech are macOS only. Windows and Linux reject them with ENGINE_UNAVAILABLE. The value is trimmed and matched without regard to case on every platform, and every platform accepts the same alias spellings: whisper, whisperLocal, libwhisper; parakeet; nemotron, nemotronLocal, nemotron-local, nemotron-asr; qwen3Asr, qwen3, qwen3-asr, qwen3_asr, qwen; appleSpeech, apple, apple-speech, apple-speech-analyzer, speech-analyzer. So the engine a response reports can always be fed back into the next request, on any platform.
TWO CLOUD VALUES ARE LEGACY NAMES AND ARE FOLDED, on every platform. googlespeech and microsoftazurespeech (either casing) name providers that HyperWhisper Cloud now serves as accuracy tiers, so the request runs on HyperWhisper Cloud — spending credits — with the tier geminiTranscribe or azureMaiTranscribe, and the response reports engine: "hyperwhisper". Send an explicit model to pin a model INSIDE that tier (mai-transcribe-1.5 rather than the default mai-transcribe-2); with no model, the Mode's own sub-model is kept when the tier serves it and the tier default runs otherwise. The fold replaces the Mode's provider and tier for this one call and supersedes whatever mode_id held, so the model rules under mode_id above are the HyperWhisper Cloud ones. cloud and hyperwhisper are NOT legacy names: they select HyperWhisper Cloud without changing the Mode's accuracy tier.
The model to run. Optional. It is echoed back unvalidated, and it wins over everything the Mode holds. Omit it to let the engine choose, and read mode_id above for what happens when the Mode and the engine disagree about the model. whisperLocal (and its aliases) is the exception: sent with engine and no mode_id, it needs a model (for example base.en), and a missing or blank one is refused with INVALID_REQUEST on all three platforms (macOS and Windows answer HTTP 200 with the message "A Whisper model is required."; Linux answers HTTP 400). nemotron with no model tries nemotron-asr-3.5-multilingual; on macOS, sent with engine and no mode_id, the MODEL_NOT_INSTALLED message names that model when it is not installed.
macOS only. Opt-in caption timestamps — ['segment'], ['word'], or both. Populates segments/words on the response.
segment, word Response
Transcript or business error envelope
The transcript. /transcribe never runs AI post-processing — /post-process is the endpoint for that. The deterministic text passes DO run, on all three platforms: vocabulary replacements, dictated "new line" / "new paragraph" break commands, and filler-word removal when Remove filler words is on. Filler-word removal is English-only everywhere, but each platform decides "English" the way its own dictation does: Windows and Linux read the request's / Mode's language, so the default "auto" does not remove fillers and you should send "language": "en"; macOS prefers the language the engine reported and falls back to the request's, so "auto" against an engine that reports English does remove them there.
The model that actually transcribed the audio, on all three platforms. When the request names an explicit model, that value is echoed back unvalidated. When the request sends engine (or only mode_id) and no model, the response reports the model the engine resolved to rather than an empty string, so a caller driving the API by engine can still record which model produced the text; for HyperWhisper Cloud that is the model behind the mode's accuracy tier (for example scribe_v2), because the tier is what the service dispatches on. It is still empty for the handful of providers that take no model parameter at all — read an empty value as "this engine has no model id", not as "unreported".
Show child attributes
Show child attributes
macOS only. Set when timestamp_granularities was requested.
macOS only. Present when timestamp_granularities included 'segment'.
Show child attributes
Show child attributes
macOS only. Present when timestamp_granularities included 'word'.
Show child attributes
Show child attributes
Was this page helpful?
