Speech to Text
Transcribe audio to text with word- and segment-level timestamps, subtitle formats, streaming, and speaker diarization
The Speech to Text endpoint (POST /v1/audio/transcriptions) turns audio files into text. Two Parakeet models serve it: nvidia/parakeet-tdt-0.6b-v2 for English, nvidia/parakeet-tdt-0.6b-v3 for 25 languages including Dutch, German, French, and Spanish.
You get plain text by default, word- and segment-level timestamps on request, SRT and WebVTT subtitle formats, SSE streaming while the file processes, and speaker labels via the diarized format. Long files are split automatically on silence, so you never chunk audio yourself.
Every example reads your key from NEBUL_API_KEY; export it first. The Quick Start covers key setup.
Request
POST https://api.inference.nebul.io/v1/audio/transcriptions
The request is multipart:
| Parameter | Type | Required | Description |
|---|---|---|---|
file | File | Yes | The audio file: .flac, .m4a, .mp3, .mp4, .mpeg, .mpga, .ogg, .opus, .wav, or .webm. |
model | String | Yes | nvidia/parakeet-tdt-0.6b-v2 (English) or nvidia/parakeet-tdt-0.6b-v3 (multilingual). |
language | String | No | ISO 639-1 code, e.g. en, nl, de. Defaults to en. The v3 model also accepts auto for detection; v2 supports en only. |
response_format | String | No | json (default), text, verbose_json, srt, vtt, diarized_json. |
prompt | String | No | Text to guide the transcription, e.g. spellings of names. |
temperature | Float | No | Sampling temperature, 0 to 1. Defaults to 0.0. |
The v3 language codes: auto, bg, hr, cs, da, nl, en, et, fi, fr, de, el, hu, it, lv, lt, mt, pl, pt, ro, sk, sl, es, sv, ru, uk.
Example
Transcribe an English WAV file:
import os
import requests
response = requests.post(
"https://api.inference.nebul.io/v1/audio/transcriptions",
headers={"Authorization": f"Bearer {os.environ['NEBUL_API_KEY']}"},
files={"file": open("speech.wav", "rb")},
data={
"model": "nvidia/parakeet-tdt-0.6b-v3",
"language": "en",
"response_format": "json",
},
)
print(response.json()["text"])For six seconds of clear English speech, this returns the sentence and a usage block:
{
"text": "Hello, this is a test of the Nebel speech recognition system, it converts audio into text.",
"usage": {
"input_tokens": 5,
"output_tokens": 16,
"total_tokens": 21,
"seconds": 5,
"type": "duration"
}
}A Dutch file with language=nl transcribes Dutch text with the same call shape. Use language=auto when you don't know.
Timestamps
response_format: "verbose_json" adds word and segment timing. Only the parakeet models support it; reson8's variant returns segments without word timings, and cohere-transcribe rejects it with a 400.
response = requests.post(
"https://api.inference.nebul.io/v1/audio/transcriptions",
headers={"Authorization": f"Bearer {os.environ['NEBUL_API_KEY']}"},
files={"file": open("speech.wav", "rb")},
data={
"model": "nvidia/parakeet-tdt-0.6b-v3",
"language": "en",
"response_format": "verbose_json",
},
)
result = response.json()
print(f"Language: {result['language']}, duration: {result['duration']}s")
print(f"{len(result['words'])} words, {len(result['segments'])} segments"){
"text": "Hello, this is a test of the Nebel speech recognition system, it converts audio into text.",
"language": "en",
"duration": 5.9875,
"words": [
{
"word": "Hello,",
"start_offset": 0,
"end_offset": 6,
"start": 0.0,
"end": 0.48
},
{
"word": "this",
"start_offset": 8,
"end_offset": 10,
"start": 0.64,
"end": 0.8
}
],
"segments": [
{
"segment": "Hello, this is a test of the Nebel speech recognition system, it converts audio into text.",
"start_offset": 0,
"end_offset": 72,
"start": 0.0,
"end": 5.76
}
],
"usage": {
"input_tokens": 5,
"output_tokens": 16,
"total_tokens": 21,
"seconds": 5,
"type": "duration"
}
}| Field | Type | Description |
|---|---|---|
text | String | The full transcription. |
language | String | Detected or requested language code. |
duration | Number | Audio length in seconds. |
words[].word | String | One recognized word, punctuation attached. |
words[].start, words[].end | Number | Word timing in seconds. |
words[].start_offset, words[].end_offset | Integer | Character offsets into text. |
segments[].segment | String | The segment text. |
segments[].start, segments[].end | Number | Segment timing in seconds. |
usage | Object | Token counts plus seconds of audio processed. |
Subtitles
response_format: "srt" and "vtt" return timed subtitle text:
curl https://api.inference.nebul.io/v1/audio/transcriptions \
-H "Authorization: Bearer $NEBUL_API_KEY" \
-F "file=@speech.wav" \
-F "model=nvidia/parakeet-tdt-0.6b-v3" \
-F "response_format=srt"1
00:00:00,000 --> 00:00:05,759
Hello, this is a test of the Nebel speech recognition system, it converts audio into text.vtt returns the same timings in WebVTT shape with a WEBVTT header. Feed either straight into a video player or subtitle pipeline. Subtitle formats work on the parakeet and reson8 models; cohere-transcribe rejects them.
Streaming
POST /v1/audio/transcriptions/stream takes the same multipart request and returns transcription chunks as Server-Sent Events while the file processes:
import json
import os
import requests
response = requests.post(
"https://api.inference.nebul.io/v1/audio/transcriptions/stream",
headers={"Authorization": f"Bearer {os.environ['NEBUL_API_KEY']}"},
files={"file": open("speech.wav", "rb")},
data={"model": "nvidia/parakeet-tdt-0.6b-v3"},
stream=True,
)
for line in response.iter_lines():
if line and line.startswith(b"data: "):
payload = line[6:]
if payload == b"[DONE]":
break
chunk = json.loads(payload)
print(chunk["text"])Each data: line carries the text recognized so far and its offset in seconds; the stream ends at data: [DONE]. One file upload, incremental results.
A second endpoint, POST /v1/audio/transcriptions/stream_input, accepts a continuous audio stream instead of a complete file. Voice Activity Detection splits it on silence: chunks between 2 and 10 seconds (tunable via min_chunk_seconds and max_chunk_seconds) are transcribed as they arrive. Use it for live microphones and long-running capture.
Speaker diarization
response_format: "diarized_json" labels each segment with a speaker:
{
"task": "transcribe",
"duration": 5.9875,
"text": "A: Hello, this is a test of the Nebel speech recognition system, it converts audio into text.",
"segments": [
{
"type": "transcript.text.segment",
"id": "seg_001",
"start": 0.0,
"end": 5.76,
"text": "Hello, this is a test of the Nebel speech recognition system, it converts audio into text.",
"speaker": "A"
}
],
"usage": {
"input_tokens": 5,
"output_tokens": 16,
"total_tokens": 21,
"seconds": 5,
"type": "duration"
}
}Speakers are labeled A, B, C in speaking order. Diarization works on the parakeet and reson8 models; cohere-transcribe rejects diarized_json. The Speaker Diarization page covers the format in depth, including its limitations.
Models
Examples on this page use nvidia/parakeet-tdt-0.6b-v3, the default transcription model. The Model Catalog lists the other transcription models with their specs. Response-format support and the usage block vary by model: some models accept only json and text, and not all report token counts.
Errors
| Status | Meaning |
|---|---|
| 400 | Unsupported audio format. The error names the supported extensions: .flac, .m4a, .mp3, .mp4, .mpeg, .mpga, .ogg, .opus, .wav, .webm. |
| 429 | Rate limited. Retry with exponential backoff. |
| 500 | Transcription failed. Retry once, then contact support with the x-request-id header. |
Better in, better out
Accuracy tracks recording quality. Use 16 kHz or higher sample rates, keep speech at a healthy volume, and minimize background noise. Long files are split automatically on silence, so you never chunk audio yourself.
For generating speech instead of transcribing it, see Text to Speech.