Upload transcription
POST https://api.kittenml.com/v1/audio/transcriptions
Already have the whole recording? Drop it here. Upload one audio file as
multipart/form-data, then choose one complete response or a finite
Server-Sent Events stream.
Send a bearer API key with the asr:transcribe permission.
Request fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
file | file | Yes | — | Non-empty audio file, at most 25 MiB |
model | string | No | emokittenasr-realtime | Hosted ASR model ID |
language | string | No | Automatic detection | Optional language hint such as en |
response_format | string | No | json | json, verbose_json, text, srt, or vtt |
stream | boolean-like string | No | false | Set to true for finite SSE output |
Supported containers include WAV, FLAC, MP3, M4A, MP4, OGG, and WebM. The service decodes the file and converts it to mono audio internally.
The plain transcript tells you what was said. JSON responses can also preserve
how it was said through enriched_text, accent, and tags.
cURL
curl --fail-with-body -sS \
https://api.kittenml.com/v1/audio/transcriptions \
-H "Authorization: Bearer $KITTENML_API_KEY" \
-F "file=@speech.flac" \
-F "model=emokittenasr-realtime" \
-F "response_format=verbose_json"
In cURL, @ reads the file from disk. Relative paths start from your current
directory. You can also use an absolute path:
-F "file=@/absolute/path/to/speech.flac"
--fail-with-body makes cURL return a nonzero exit code for HTTP errors while
preserving the API error body. -sS hides progress but still prints errors.
Python with the OpenAI SDK
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["KITTENML_API_KEY"],
base_url="https://api.kittenml.com/v1",
)
with open("speech.flac", "rb") as audio:
result = client.audio.transcriptions.create(
model="emokittenasr-realtime",
file=audio,
response_format="verbose_json",
)
print(result.text)
print(result.enriched_text)
print(result.request_id)
JavaScript with the OpenAI SDK
import fs from "node:fs";
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.KITTENML_API_KEY,
baseURL: "https://api.kittenml.com/v1",
});
const result = await client.audio.transcriptions.create({
model: "emokittenasr-realtime",
file: fs.createReadStream("speech.flac"),
response_format: "verbose_json",
});
console.log(result.text);
console.log(result.enriched_text);
console.log(result.request_id);
Non-streaming responses
Leave stream unset or set it to false for one response after transcription
finishes.
response_format | Content type | Result |
|---|---|---|
json | application/json | Transcript and KittenML metadata |
verbose_json | application/json | JSON plus duration, language, and segments |
text | text/plain | Clean transcript only |
srt | application/x-subrip | Timestamped SubRip subtitles |
vtt | text/vtt | Timestamped WebVTT subtitles |
JSON
{
"text": "A cold, lucid indifference reigned in his soul.",
"enriched_text": "[low][slow]A (cold), [pause_short] (lucid) (indifference) (reigned) in his (soul).[/slow][/low]",
"accent": "General American",
"tags": [
{"type": "tag", "label": "low", "start": 0, "end": 5},
{"type": "tag", "label": "slow", "start": 5, "end": 11},
{"type": "tag", "label": "pause_short", "start": 21, "end": 34},
{"type": "tag", "label": "slow", "start": 82, "end": 89},
{"type": "tag", "label": "low", "start": 89, "end": 95},
{"type": "stress", "label": "stress", "start": 13, "end": 19},
{"type": "stress", "label": "stress", "start": 35, "end": 42},
{"type": "stress", "label": "stress", "start": 43, "end": 57},
{"type": "stress", "label": "stress", "start": 58, "end": 67},
{"type": "stress", "label": "stress", "start": 75, "end": 81}
],
"request_id": "<request-id>"
}
Verbose JSON
verbose_json adds task, language, duration, and segments:
{
"task": "transcribe",
"language": "English",
"duration": 4.275,
"text": "A cold, lucid indifference reigned in his soul.",
"enriched_text": "[low][slow]A (cold), [pause_short] (lucid) (indifference) (reigned) in his (soul).[/slow][/low]",
"accent": "General American",
"segments": [
{
"id": 0,
"start": 0.56,
"end": 4.192,
"text": "A cold, lucid indifference reigned in his soul.",
"enriched_text": "[low][slow]A (cold), [pause_short] (lucid) (indifference) (reigned) in his (soul).[/slow][/low]"
}
],
"request_id": "<request-id>"
}
The complete response also contains the same tags array shown in the JSON
example.
Text
A cold, lucid indifference reigned in his soul.
SRT
1
00:00:00,560 --> 00:00:04,192
A cold, lucid indifference reigned in his soul.
VTT
WEBVTT
00:00:00.560 --> 00:00:04.192
A cold, lucid indifference reigned in his soul.
Model wording, enrichment labels, accent, and segment boundaries can vary.
Stream an uploaded file with SSE
Set stream=true and use cURL's -N option to display events immediately:
curl --fail-with-body -sS -N \
https://api.kittenml.com/v1/audio/transcriptions \
-H "Authorization: Bearer $KITTENML_API_KEY" \
-F "file=@speech.flac" \
-F "model=emokittenasr-realtime" \
-F "stream=true"
The response uses text/event-stream:
data: {"type":"transcript.text.delta","delta":"A cold, lucid","clean_text":"A cold, lucid","enriched_text":"[low]A (cold), lucid[/low]","request_id":"<request-id>"}
data: {"type":"transcript.text.done","text":"A cold, lucid indifference reigned in his soul.","enriched_text":"[low][slow]A (cold), lucid indifference reigned in his soul.[/slow][/low]","request_id":"<request-id>"}
data: [DONE]
There may be zero or more delta events. The terminal transcript.text.done
event is authoritative and contains accent, tags, and segments. The
server closes the finite response after [DONE]. The abridged events above
omit those final metadata fields.
If transcription fails after streaming begins, the stream can emit a
structured error event before [DONE].
With stream=true, every accepted response_format value produces this same
SSE protocol. Use response_format to select an output representation only
when stream=false.
See Response formats and SSE for a longer verified example with four timestamped segments and multiple delta events.
Response fields
| Field | Meaning |
|---|---|
text | Clean transcript |
enriched_text | Transcript with delivery, pause, and emphasis markup |
accent | Best-effort accent classification; may be empty |
tags | Half-open character ranges into enriched_text |
duration | Decoded input duration in seconds (verbose_json) |
segments | Timestamped speech segments; upload start and end are seconds (verbose_json and final SSE event) |
request_id | Identifier for logs and support |
Upload STT shares the organization's ASR concurrency limit with realtime sessions.