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.

Shell
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):

JSON
{
  "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.

Shell
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):

JSON
{
  "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.

Shell
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):

JSON
{
  "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.

FieldNotes
textTop level; preserves the input.
alternatives[].rankCandidate index; 0 is the preferred one.
alternatives[].textThat 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.

Shell
curl "$EDGESPEAK_BASE_URL/models"

Example output (excerpt):

JSON
{
  "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:

KeyTypeWhen absent
target_langsstring[], ordered and unique, lowercase BCP-47 tagsOmitted when no target language is selected
speaker_source"transcript", "script", or "none"Omitted; read it as "transcript"
translation_settings_revisionstringOmitted 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:

KeyTypeWhen absent
translationsObject keyed by lowercase BCP-47 tag, each value a translation cellOmitted when the segment has no translation
no_translatebooleanOmitted, 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:

FieldTypeNotes
textstringEmpty string on a failed cell
statusstring, optionalDerived snapshot: translated, reviewed, stale, or failed
source_revisionstringFingerprint of the source text this was translated from; empty means unknown
settings_revisionstringFingerprint of the translation requirements in force; empty means unknown
reviewedbooleanTrue once a person confirmed the translation
updated_atstringISO 8601; empty means unknown
error_codestring, optionalStable 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):

JSON
{
  "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.