JSON output
Stable JSON contracts for transcripts and models.
Overview
Transcription, alignment, and segmentation share EdgeSpeak's structured transcript conventions; the app export and CLI expose the same fields when the same output mode is selected. Speech synthesis, speaker, model, language-model, MCP, and Realtime endpoints use their own response contracts.
POST /v1/audio/transcriptions (verbose_json) → {task:"transcribe", duration, language?, text, segments[], usage}
POST /v1/audio/alignments → {task:"align", duration, language?, text, segments[], normalization_regions?, usage}
POST /v1/text/segmentations → {task:"segment", text, segments[]}
POST /v1/text/normalizations → {task:"normalize", model, language, mode, text, alternatives[]}
GET /v1/models → {object:"list", data[]}POST /v1/audio/transcriptions
Multipart form upload. response_format supports json, verbose_json, text, and diarized_json; verbose_json and diarized_json can request word- or segment-level timestamps via timestamp_granularities[]. Streaming uses JSON-mode SSE, does not support text or diarized_json, and is only supported on the desktop gateway; the headless service returns 400 for stream=true.
Output modes have distinct shapes: json returns {text,start,duration,language?,usage}; verbose_json returns {task:"transcribe",duration,language?,text,segments?,usage}; diarized_json returns {text,segments,usage}, with segment type:"transcript.text.segment" and string IDs such as "seg_0". Diarized speaker labels can be null. The example below shows verbose_json, not a schema for every mode. See complete per-mode request and response examples.
curl "$EDGESPEAK_BASE_URL/audio/transcriptions" \
-F file=@meeting.m4a \
-F model="EdgeSpeak/Lattice-2" \
-F response_format=verbose_json \
-F "timestamp_granularities[]=word"Example output (excerpt):
{
"task": "transcribe",
"duration": 19.69,
"language": "en",
"text": "EdgeSpeak AI is a high-performance engine ...",
"segments": [
{
"id": 0,
"start": 0.0,
"end": 6.44,
"text": "EdgeSpeak AI is a high-performance engine designed for ...",
"words": [
{ "word": "EdgeSpeak", "start": 0.22, "end": 0.64, "score": 0.991 }
]
}
],
"usage": { "type": "duration", "seconds": 19.69 }
}POST /v1/audio/alignments
Forced alignment returns word timing for supplied text. For request parameters, see alignment parameters. For complete request and response examples, see Forced alignment. Responses can include a normalized language code in language; score is confidence in [0, 1]. Text normalization may convert written forms to their spoken realization. normalization_regions describes regions and candidates, and word-level provenance contains source_start_byte, source_end_byte, and normalizations[], relative to the original UTF-8 transcript.
curl "$EDGESPEAK_BASE_URL/audio/alignments" \
-F model="EdgeSpeak/Lattice-2" \
-F file=@meeting.m4a \
-F text="EdgeSpeak is a high performance engine ..."Example output (excerpt):
{
"task": "align",
"duration": 19.6909375,
"text": "EdgeSpeak is a high performance engine ...",
"segments": [
{
"id": 0,
"start": 0.22,
"end": 19.52,
"text": "EdgeSpeak is a high performance engine ...",
"words": [
{ "word": "EdgeSpeak", "start": 0.22, "end": 1.04, "score": 0.8463 }
]
}
],
"usage": { "type": "duration", "seconds": 19.6909375 }
}POST /v1/text/segmentations
Supports semantic sentence segmentation. In the JSON request body, pass text for plain text or segments[] for timestamped inputs. speaker, start, and end are returned only when present in the input. With paragraph_threshold, each segments[] item represents a paragraph, and top-level text joins paragraphs with \n\n (a blank line). For optional parameters and paragraph-mode constraints, see sentence and paragraph segmentation.
curl "$EDGESPEAK_BASE_URL/text/segmentations" \
-H "Content-Type: application/json" \
-d '{"text": "EdgeSpeak is a high-performance engine designed for the structuring of audio and video content assets. It runs entirely on local compute, ensuring your data security."}'Example output (excerpt):
{
"task": "segment",
"text": "EdgeSpeak is a high-performance engine ... It runs entirely on local compute ...",
"segments": [
{ "text": "EdgeSpeak is a high-performance engine designed for the structuring of audio and video content assets." },
{ "text": "It runs entirely on local compute, ensuring your data security." }
]
}POST /v1/text/normalizations
Text normalization has its own response contract. Do not treat the UTF-8 byte offsets in spans[] as character indices.
| Field | Notes |
|---|---|
text | Top level; preserves the input. |
alternatives[].rank | Candidate index; 0 is the preferred one. |
alternatives[].text | That candidate’s complete spoken or written form. |
alternatives[].spans[] | Contains start_byte, end_byte, class, source, output. |
Candidate text and order depend on language, classes, and normalization rules. For complete TN/ITN request and response examples, see Text processing.
GET /v1/models
Lists available models. Each model record provides supported_endpoints, features, execution_location, and default_for. Model IDs are determined by the values returned at runtime; callers should read the response directly rather than concatenating or hardcoding them.
curl "$EDGESPEAK_BASE_URL/models"Example output (excerpt):
{
"object": "list",
"data": [
{
"id": "EdgeSpeak/Lattice-2-Flash",
"object": "model",
"created": 0,
"owned_by": "EdgeSpeak",
"supported_endpoints": ["/v1/audio/transcriptions"],
"features": [],
"execution_location": "local",
"default_for": ["/v1/audio/transcriptions"]
},
{
"id": "Qwen/Qwen3.5-4B",
"object": "model",
"created": 0,
"owned_by": "EdgeSpeak",
"supported_endpoints": ["/v1/chat/completions", "/v1/responses", "/v1/messages", "/v1/tokenize"],
"features": ["reasoning", "vision", "tool_calling"],
"execution_location": "local",
"default_for": []
}
]
}Field semantics
All transcript timing values are in seconds. Common segments[] items carry {id, start, end, text, words?}; word-level timestamps live under segments[].words, with individual word entries formatted as {word, start, end, score?}, where score is confidence in [0, 1]. Transcription and alignment typically represent usage as {"type": "duration", "seconds": …}; other APIs use their own contracts. Optional keys may be omitted, and JSON key order is not guaranteed; access values by key name.
Translations
Structured transcript exports from the desktop app carry translations next to the source text. None of these keys are written unless a result has actually been translated, so an export without translations is byte-for-byte what it was before translation existed.
Document level:
| Key | Type | When absent |
|---|---|---|
target_langs | string[], ordered and unique, lowercase BCP-47 tags | Omitted when no target language is selected |
speaker_source | "transcript", "script", or "none" | Omitted; read it as "transcript" |
translation_settings_revision | string | Omitted when no translation requirements are set |
target_langs is the only source for which languages the user selected. Do not rebuild it from the union of the per-segment translations keys: a language with nothing translated yet contributes no key, and would silently vanish.
Segment level:
| Key | Type | When absent |
|---|---|---|
translations | Object keyed by lowercase BCP-47 tag, each value a translation cell | Omitted when the segment has no translation |
no_translate | boolean | Omitted, which means false |
A language listed in target_langs can still have no entry under a given segment. Treat every cell as optional and check before reading it. Segments marked no_translate carry no translations.
Each translation cell:
| Field | Type | Notes |
|---|---|---|
text | string | Empty string on a failed cell |
status | string, optional | Derived snapshot: translated, reviewed, stale, or failed |
source_revision | string | Fingerprint of the source text this was translated from; empty means unknown |
settings_revision | string | Fingerprint of the translation requirements in force; empty means unknown |
reviewed | boolean | True once a person confirmed the translation |
updated_at | string | ISO 8601; empty means unknown |
error_code | string, optional | Stable snake_case code, such as translation_request_failed |
status is a snapshot of a value the app derives, not persistent state; as soon as the source text or translation requirements change, it becomes invalid. Recompute it from source_revision, settings_revision, and error_code against the current document instead of trusting what was written.
Example output (excerpt; revision values are opaque fingerprints):
{
"language": "en",
"target_langs": ["ja", "zh-hans"],
"speaker_source": "transcript",
"translation_settings_revision": "s3f9c1d4",
"duration": 19.69,
"num_segments": 2,
"segments": [
{
"id": "seg_000",
"text": "EdgeSpeak AI is a high-performance engine ...",
"start": 0.0,
"end": 6.44,
"translations": {
"ja": {
"text": "EdgeSpeak AI は高性能なエンジンです ...",
"status": "reviewed",
"source_revision": "r91b0c27",
"settings_revision": "s3f9c1d4",
"reviewed": true,
"updated_at": "2026-09-13T08:21:04Z"
},
"zh-hans": {
"text": "EdgeSpeak AI 是一款高性能引擎 ...",
"status": "translated",
"source_revision": "r91b0c27",
"settings_revision": "s3f9c1d4",
"reviewed": false,
"updated_at": "2026-09-13T08:21:04Z"
}
}
},
{
"id": "seg_001",
"text": "It runs entirely on your device ...",
"start": 6.44,
"end": 11.02,
"translations": {
"ja": {
"text": "",
"status": "failed",
"source_revision": "r4d8ae13",
"settings_revision": "s3f9c1d4",
"reviewed": false,
"updated_at": "2026-09-13T08:21:06Z",
"error_code": "translation_request_failed"
},
"zh-hans": {
"text": "它完全在你的设备上运行 ...",
"status": "stale",
"source_revision": "r2c07f5a",
"settings_revision": "s3f9c1d4",
"reviewed": false,
"updated_at": "2026-09-13T08:19:52Z"
}
}
}
]
}Legacy single-language shape. Exports written before multi-language translation used a document-level target_lang together with segments[].translation. Both are deprecated. The two shapes never appear in the same file, and everything written now uses the multi-language shape. Old files are migrated on read: tags are normalized to lowercase BCP-47, a segment-level tag wins over the document-level one, and each translation becomes a cell whose source_revision, settings_revision, and updated_at are empty. Those empty fingerprints are deliberate, since an old file never recorded which version of the source it was translated from, so the cell reads as needing an update rather than as current. When neither level carries a tag, the old fields are left untouched rather than assigned a guessed language.