Result format
GET /v1/jobs/{id}/result returns JSON. A shortened example for a stereo call with every option on:
{
"schema_version": "gapi_task_result.v0",
"audio_seconds": 282.7,
"speech_seconds": 230.4,
"channels": 2,
"stereo_parties": true,
"speakers": 2,
"vocabulary_terms": 4,
"vocabulary_dropped": false,
"text": "Assalomu alaykum, Metasell kompaniyasi. …",
"language": {"code": "uz", "confidence": 0.97, "speech_seconds": 230.4, "share": {"uz": 0.91, "ru": 0.09}, "posterior": {"uz": 0.97, "ru": 0.03}},
"call_outcome": {"outcome": "conversation", "reached": true, "confidence": 0.99, "probabilities": {"conversation": 0.99, "no_answer": 0.004, "operator_message": 0.003, "ivr": 0.003}, "answer_at": 11.4, "seconds": 180.0},
"segments": [
{
"index": 0,
"start": 0.42,
"end": 3.9,
"speaker": 1,
"text": "Assalomu alaykum, Metasell kompaniyasi.",
"raw_asr_text": "assalomu alaykum metasell kompaniyasi",
"formatted_text": "Assalomu alaykum, Metasell kompaniyasi.",
"pii": {"entities": [], "redacted_text": "Assalomu alaykum, Metasell kompaniyasi."},
"language": {"code": "uz", "confidence": 0.99}
}
],
"speaker_info": [
{
"index": 0,
"speech_seconds": 149.2,
"gender": {"label": "male", "confidence": 0.97},
"role": "client",
"identity": {"status": "new", "voice_id": 100, "speaker_id": "e3db…", "name": null},
"has_voiceprint": true,
"clarity": {"scored_words": 412, "low_confidence_share": 0.071, "estimated_error_share": 0.118, "speech_rate": 5.6,
"line_quality": {"snr_db": 31.5, "clipping_share": 0.0, "bandwidth_hz": 3850, "band": "telephone"}}
}
],
"voices": [
{"label": "SPEAKER_1", "speaker": 0, "voice_id": 100, "name": null, "status": "new"},
{"label": "SPEAKER_2", "speaker": 1, "voice_id": 101, "name": "Azimbek", "status": "matched", "score": 0.97}
],
"options_report": {"requested": ["gender", "speaker_roles", "speaker_identification", "pii", "language_detection", "call_outcome"], "errors": {}, "seconds": 1.8},
"timing": {"decode_seconds": 0.3, "vad_seconds": 0.4, "stt_seconds": 2.1, "total_seconds": 4.9}
}The text comes in Latin script: the model is trained on Latin-script Uzbek, and every option (punctuation, numbers, personal data) works on it. There is no Cyrillic output.
Top level
| Field | What it is |
|---|---|
audio_seconds | Length of the recording; the charge in g is worked out from it |
speech_seconds | How much of it is speech |
channels, stereo_parties | Channels in the file; true when the sides are separated by channel |
speakers | How many voices speaker separation found |
text | All text in a row |
segments | Utterances in order |
speaker_info | A summary per speaker of the recording: what the options found, and clarity whenever the speakers are known |
language | The recording's main spoken language and the share of each language, with Spoken language; see Options |
call_outcome | Whether a live conversation took place and, if not, what played instead; the second the other side answered. With Call outcome; see Options |
voice_events | Laughter, dissatisfaction and voice energy: `[{"type": "laughter" |
summary | A short summary of the call: {"text", "lines", "read_lines"}, with "Call summary"; see Options |
voices | Permanent project voice numbers, with "Recognise by voice" |
options | The settings the recording was actually run with: the project plus the request's settings. Every key from the Options page is here — stereo_channels_as_speakers, max_speakers, call_direction and fuzzy_itn (loose number normalisation, off by default) included |
tenant | The integrator's business the recording belongs to, when the job named one; see Tenants |
vocabulary_terms, vocabulary_dropped | How many vocabulary terms the job took; the second is true when the cleaning left none |
diarization_error | true when speaker separation did not work: the recording will carry no speaker numbers. When it worked, the field is there and is null |
options_report | Which options were requested, which were not computed and why |
segment_voiceprints | Which utterances have a voice print: {"dims", "format", "min_seconds", "segments": [indexes]}. The prints themselves never leave the gateway — this is the list of utterances a voice can be enrolled from with POST /v1/speakers/{id}/enroll and segment_indexes |
timing | How many seconds processing took: decode_seconds, vad_seconds, stt_seconds, format_seconds, diarization_seconds, total_seconds. We measure ourselves by these, not you |
options_report shows what was requested (requested), what could not be computed and why (errors), and how many seconds the options took (seconds). When roles were requested it also carries roles: the status, a calibrated score (the probability that the roles are assigned the right way round) and the fields described under Client and manager. Take each speaker's role from speaker_info[].role.
Alongside them sit diagnostic fields — word_timing, formatting, partial. They are there for looking into our own tickets: what they hold may change, so do not build logic on them.
Utterance
| Field | What it is |
|---|---|
index | Ordinal, from 0 |
start, end | Seconds from the start of the recording |
speaker | Speaker number of the recording, or null |
text | Final text with the options applied |
raw_asr_text | What the model heard: lower-case, no punctuation |
formatted_text | With punctuation and capitals |
words | Words with timing, with word_timestamps; see below |
speaker_share | What share of the utterance's speech speaker separation itself placed with this speaker, 0 to 1; the rest was carried over from neighbouring words. Present only where speakers were computed |
contextual_text | The text after the vocabulary, before punctuation and numbers: between raw_asr_text and formatted_text |
duration_bucket_seconds | A length bucket for our own telemetry |
emotion | Only when the request sends the removed emotion key: always {"label": null, "reason": "removed"}; see Emotions (removed) |
pii | {"entities", "redacted_text"}, with Personal data |
language | {"code", "confidence"}, with Spoken language; an utterance under a second carries {"code": null, "reason": "too_short"} |
pii labels: NAME, PHONE, ADDRESS, DATE, DOCUMENT_ID, CARD_NUMBER.
A word
{"text": "kredit", "raw": "kredit", "formatted": "kredit", "start": 12.40, "end": 12.81, "speaker": 0, "aligned": "exact", "confidence": 0.93}
{"text": "Uzum", "raw": "uzim", "formatted": "Uzum", "start": 4.12, "end": 4.51, "speaker": 1, "aligned": "term", "confidence": null}| Field | What it is |
|---|---|
text | The word after the vocabulary, before punctuation |
raw | What the model heard in its place; an inserted word has no such field |
formatted | The same with capitals and punctuation, once the utterance is formatted |
start, end | Seconds from the start of the recording |
speaker | Speaker number, where speakers were computed |
aligned | Where the word's timing came from |
confidence | The probability, from 0 to 1, that the word was transcribed correctly; null when it is not the model's own word (see below) |
aligned is worth reading: exact — the model's own frames for that very word; term — the word came from the vocabulary and is timed by the term spotter's frames, which is direct evidence that the term was applied; span — its share of the raw words that were rewritten; chunk — the bundle gave no usable words for that piece, so the whole piece shares its timing; none — inserted with no acoustic evidence, zero length.
Word confidence. confidence is the probability, from 0 to 1, that the word was transcribed correctly. It is calibrated on human-checked call recordings: of all words marked 0.8, about eight in ten are right. Only the model's own words carry one (aligned: exact). A word that the corrector or your vocabulary put in place of what was heard (span, term), one inserted with no acoustic evidence (none) and a piece with no usable words (chunk) have confidence: null, because there is no acoustic score for them. Words the corrector rewrote are right noticeably less often than the model's own, so a null is worth a look too.
What confidence measures. It measures how sure the recognizer was about what it heard, not how well the person spoke. A narrow phone line, noise, a quiet or clipping microphone, crosstalk, rare names and words switched into Russian or English all lower it, just as unclear speech does. A high share of low-confidence words on one call means that speaker's transcript is less reliable. On its own, it is not evidence of poor diction.
Speaker of the recording
| Field | What it is |
|---|---|
index | Speaker number, the same as in utterances |
speech_seconds | How long they spoke |
gender | {"label": "female" | "male" | "unknown", "confidence", "reason", "windows", "speech_seconds", "probabilities"}. With unknown, confidence is null and reason says why |
role | "client", "manager", "machine" (a voice heard only before a live person picked up: a voice menu, a network announcement), "other" (a live voice beyond the two parties) or "unknown". See Client and manager |
identity | {"status", "voice_id", "speaker_id", "name", "score", "threshold", "runner_up", "kind"} |
has_voiceprint | The speaker spoke enough for a voice print: this one can be enrolled, see Voices and speakers. The print itself never leaves the gateway |
emotion | Only with the removed emotion key: {"dominant_mood": null, "mood_share": {}, "valence": null, "arousal": null, "dominance": null, "reason": "removed"} |
language | {"code", "confidence", "seconds"}, the language over all of the speaker's speech; under two seconds of speech gives {"code": null, "reason": "insufficient_speech"} |
clarity | How sure the recognizer was of this speaker's words, beside the quality of the line they came over; see Clarity |
identity.status answers one question: was this person recognised, and if not, why not.
| Status | What happened | Is there a voice_id |
|---|---|---|
matched | The print matched a voice of the project | yes, the number of the known voice |
new | No match, but there was enough speech: the voice was registered by this recording and will be recognised from now on | yes, a new number |
unknown | No match, and under 10 seconds of speech — registering a voice on a print that short is unreliable | no |
insufficient_speech | No print could be computed at all: there is next to no speech | no |
no_enrolled_voices | The project has no voices yet, so there is nothing to compare against | no |
The difference between unknown and insufficient_speech is that the first has a print and the comparison ran — the person is simply not known and the speech is too short to register them; in the second there was nothing to compute from.
matched and unknown carry score, the closeness to the nearest voice from 0 to 1, and threshold, the point from which a match counts. If score sits just under the threshold again and again, the voice is short of prints: add another from a good recording.
With known_speakers (staff only) identity speaks of the tenant's staff lines: status is matched, not_matched, not_enrolled (the named line has no voice yet) or insufficient_speech; a match carries external_id, role, voice (which of the line's people, 1–4) and expected, threshold is 0.65, and runner_up is the other speaker of the call against the same line. Nobody but staff gets a voice_id, and has_voiceprint is absent: no print of such a recording is kept.
Beside them is runner_up, the closeness to the second most similar voice (-1 when there was nothing to compare with). A match counts only when the first beat the second by a margin: two similar voices must not win against each other by chance. matched and new also carry kind — what sort of voice this is in the project: candidate, recurring or named, see Voices and speakers.
Clarity: recognition certainty per speaker
speaker_info[].clarity is computed for every recording whose speakers are known — a stereo call with the parties on separate channels, or a mono one with speaker separation on — whatever options are on, at no extra charge.
"clarity": {
"scored_words": 412,
"low_confidence_share": 0.071,
"estimated_error_share": 0.118,
"speech_rate": 5.6,
"line_quality": {"snr_db": 31.5, "clipping_share": 0.0, "bandwidth_hz": 3850, "band": "telephone"}
}| Field | What it is |
|---|---|
scored_words | The speaker's words that carry a confidence |
low_confidence_share | The share of them below 0.5, that is, more likely wrong than right |
estimated_error_share | The mean of 1 - confidence over them: the share of them expected to be wrong |
reason | insufficient_words when there are fewer than 40 of them; both shares are then null |
speech_rate | Syllables (vowel letters) per second of the speaker's own speech |
line_quality.snr_db | How much louder the speech peaks are than the pauses between words within the speaker's turns, in dB |
line_quality.clipping_share | The share of the speaker's speech with samples at full scale: an overloaded microphone or line |
line_quality.bandwidth_hz | How high in frequency the speaker's voice reaches on this line |
line_quality.band | narrow below 3,800 Hz, telephone from 3,800 to 4,500 Hz, wide from 4,500 Hz |
Everything is measured over the speaker's own turns across the whole recording, leaving out the moments when someone else speaks at the same time. On a stereo call each party's line is their own channel. With under a second of such speech, line_quality and speech_rate are null.
Separating the line from the speaker. The shares stand next to line_quality, measured from the same speaker's audio. We do not subtract the line from them: in our measurements it explains little of them. The line property that mattered most was bandwidth: speakers on a narrow line had nearly twice the low-confidence share of the others. Across the noise levels found in ordinary calls, the noise level made no visible difference. Nearly half of the variation between speakers is shared by both people on the same call, so it belongs to the call, not the person. Compare people on the same band. Judge a person over many calls, not one, and against the other party of the same calls. A speaker who is clearly above the person they talk to, call after call, on the same kind of line, is the case worth attention.
Limits. Shares are not given under 40 scored words, and they stay noisy up to about 100: plus or minus 4 points at 40 words, 2.5 at 100. In mono recordings, speaker separation puts about one word in twenty on the wrong person; stereo recordings with one party per channel do not have this problem. Speech rate is counted from recognised words, so it reads low where recognition failed. The calibration is for Uzbek call audio and the current version of the recognizer, and it is redone whenever the recognizer changes.
Emotions (removed)
The Emotions option was removed on 10 October 2026: demand for it was low, and emotions in calls proved hard to detect reliably. The emotion key is still accepted so that integrations do not break, and it costs nothing. A request that sends it gets a stub in the old fields: {"label": null, "reason": "removed"} on every utterance, the speaker summary with null values and an empty mood_share in speaker_info[].emotion, and options_report.emotion = {"status": "removed"}. The key will be removed later; see Options.
Before the job is done
GET /v1/jobs/{id}/result answers only for a finished job; while it runs you get 409 result_not_ready. Utterances as they are finished come from GET /v1/jobs/{id}/events: see API.