GEThttps://core-api.heysadie.ai/full-call-runs/{id}/turns
id differing label reviewed callId limit cursor format success data columns key transcriberId name role turn organizationId tenantId assistantId messageIndex bankId kind heardText expectedText errorTags comment audio startSeconds endSeconds evaluation controlForTurnId fullCallRunId tieBreak reason review calibration createdBy createdAt updatedAt liveTranscriber evaluationProgress stage done total attempts turnId sttModel text error match wer notes identicalToProduction audioSeconds identical nextCursor metadata timestamp version path code message details fieldList a run's turns
The run's turns call by call, line by line, as a table. - `columns` lists the cells of a row in order: the candidate, then each production transcriber, then the calibration replays. Fill a cell from `attempts[column.key]`; no key means no attempt yet. - `identical` says whether the candidate's text equals production's. `label` is the judge's label and `review` a person's verdict. Filter by `differing`, `label`, `reviewed` or `callId`. Paginate with `limit` and `cursor`: send `nextCursor` back as `cursor` until it is null. With `format=csv`, one row per turn and column, up to 5000 turns. Carries `Retry-After: 5` (seconds) while the run is queued, running or analyzing, since the answer can still change. Errors: 404 RESOURCE_NOT_FOUND when the run is not in the organization.
Try it in the API ExplorerExample request
curl "https://core-api.heysadie.ai/full-call-runs/FULL_CALL_RUN_ID/turns" \
-H "Authorization: ApiKey YOUR_API_KEY"Authentication
Authenticate with an API key in the Authorization header using the ApiKey scheme. See Authentication for how keys work and where to get them.
AuthorizationstringrequiredAPI key in the ApiKey scheme: ApiKey YOUR_API_KEY. Tenant keys authorize their own tenant; organization keys can act on any tenant in the organization.
X-Tenant-Idstring (uuid)optionalRequired when authenticating with an organization key: it selects the tenant the request acts on. Omit with tenant keys.
Request
Path parameters
idstringrequiredA full-call run of the organization
Query parameters
differingstringoptionaltrue: the candidate differs from production. false: it is identical
labelstringoptionalThe judge's label: candidate_right, production_right, same_meaning or both_wrong
reviewedstringoptionaltrue: reviewed. false: not reviewed yet
callIdstringoptionalOnly turns of this call
limitstringoptionalPage size, 1 to 200, default 50. Ignored by csv
cursorstringoptional`nextCursor` of the previous page. Ignored by csv, which exports up to 5000 turns
formatstringoptionaljson (default) or csv. csv answers a `text/csv` attachment, one row per turn and column
Responses
successbooleanrequiredtrue on every 2xx
dataobjectoptionalThe result
Show 3 child properties
columnsobject[]requiredThe candidate, then the production transcribers and the calibration replays on the page, each by name. Render one cell per column from `attempts[column.key]`
Show 4 item properties
keystringrequired`<role>:<transcriberId>`, a key of each row's `attempts`
transcriberIdstringrequiredThe column's transcriber
namestringrequiredIts display name, for the header
roleenumrequiredcandidate: a transcriber under test, replayed on the clip. production: the live transcriber's stored text from the call, never replayed, at no cost. calibration: the live transcriber replayed on the clip, on a full-call run's calibration sample
"candidate""production""calibration"dataobject[]requiredCall by call, line by line
Show 5 item properties
turnobjectrequiredA tested caller line: a flag, a control sampled with one, or a line of a full-call run
Show 25 child properties
idstringrequiredTurn id
organizationIdstringrequiredThe organization that owns the turn
tenantIdstringrequiredThe tenant the call belongs to
callIdstringrequiredThe call the line is from
assistantIdstring | nullrequiredThe assistant that took the call. Null when the call names none
messageIndexstring (integer) | integerrequiredIndex of the line in the call's messages, as GET /turn-flags/calls/:callId/lines lists it
bankIdstring | nullrequiredThe bank the turn belongs to. Null while it is in no bank, and then no candidate replays it
kindenumrequiredflagged: a person flagged the line as wrong and typed what was said. control: an unflagged caller line of the same call, sampled with a flag, whose expected text is the live transcriber's own. full_call: a caller line replayed by a full-call run, listed under that run
"flagged""control""full_call"heardTextstringrequiredWhat the live transcriber wrote for the line on the call, frozen when the turn was created
expectedTextstring | nullrequiredWhat the caller said, word for word: typed for a flag, the heard text for a control. A full-call turn carries the expected text of a flag on the same line, else null
errorTagsstring[]requiredTags on what went wrong, e.g. `name` or `spelling`. Empty on controls and full-call turns
commentstring | nullrequiredThe flagger's note. Null when none
audioobjectrequiredThe line's place in the call recording. Transcribers hear it with 0.75 s more on each side, so play `startSeconds - 0.75` to `endSeconds + 0.75`, clamped to the recording, to hear what they heard
Show 2 child properties
startSecondsnumberrequiredWhere the line starts, in seconds from the recording start
endSecondsnumberrequiredWhere the line ends, in seconds from the recording start
evaluationenumrequiredpending: candidate attempts are queued and not all reported, or the turn was created in no bank. scored: every transcriber its job asked for returned an attempt (a failed attempt counts), or it joined a bank that owed it no attempt. failed: its job ended without an attempt from every transcriber it asked for. A turn taken out of a bank keeps its evaluation, and a backfill does not move a scored turn back to pending: watch `evaluationProgress` for that work
"pending""scored""failed"controlForTurnIdstring | nullrequiredOn a control, the flag it was sampled for. Deleting or moving that flag deletes or moves the control. Null otherwise
fullCallRunIdstring | nullrequiredOn a full-call turn, its run. Null otherwise
tieBreakobject | nullrequiredWhen two or more candidates match the expected text with different raw text (casing, punctuation), the one an LLM judge found fits the venue best. Null otherwise
Show 2 child properties
transcriberIdstringrequiredThe candidate whose text the judge picked
reasonstringrequiredThe judge's one-sentence reason
labelenum | nullrequiredOn a full-call turn where the candidate differs from production, its label: decided by the expected-text matches where the line has expected text, else by the LLM judge. candidate_right: the candidate has what the caller said and production does not. production_right: production has it and the candidate does not. same_meaning: they differ in a way that does not matter. both_wrong: neither has it. Null otherwise or until the analysis labels it
"candidate_right""production_right""same_meaning""both_wrong"reviewenum | nullrequiredOn a full-call turn, a person's verdict from POST /full-call-runs/:id/reviews, in the same values as `label`. It counts only on differing turns, and outranks the label in `fixed` and `introduced` only where the line has no expected text. Null until reviewed
"candidate_right""production_right""same_meaning""both_wrong"calibrationbooleanrequiredOn a full-call turn, whether production is also replayed on it to measure replay against the live text. False otherwise
createdBystring | nullrequiredWho made it, as the creating request named them in an `X-On-Behalf-Of` header. Null when it sent none
createdAtstring (date-time) | string (date) | number | nullrequiredWhen it was created, UTC
updatedAtstring (date-time) | string (date) | number | nullrequiredWhen it last changed, UTC
liveTranscriberobject | nullrequiredThe transcriber the turn's call ran on, recorded when the turn was created. Its stored text is the turn's production attempt. Null when unknown
Show 2 child properties
idstringrequiredTranscriber id, as GET /transcribers lists it
namestringrequiredThe transcriber's display name
evaluationProgressobject | nullrequiredThe newest open transcribe job holding the turn, for a progress bar. Null when no open job holds it (scored, failed or never queued), and on the POST /turn-flags response, which is written before its job is queued: read the turn again to see it
Show 3 child properties
stageenumrequiredwaiting: the job is queued or dispatched and no worker has started it. scoring: a worker is running it
"waiting""scoring"donestring (integer) | integerrequiredTranscriptions the job has finished, over every clip and transcriber it holds, not this turn's alone. 0 until the worker first reports
totalstring (integer) | integerrequiredTranscriptions the job holds in all
attemptsmap<string, object>requiredThe candidate, production and calibration attempts of the turn, keyed `<role>:<transcriberId>`. A column with no key here has no attempt yet
Show 11 map values
turnIdstringrequiredThe turn the attempt is on
transcriberIdstringrequiredThe transcriber that made the attempt
roleenumrequiredcandidate: a transcriber under test, replayed on the clip. production: the live transcriber's stored text from the call, never replayed, at no cost. calibration: the live transcriber replayed on the clip, on a full-call run's calibration sample
"candidate""production""calibration"sttModelstringrequiredProvider and model, e.g. "deepgram/nova-3". Display only
textstring | nullrequiredThe transcript. Null when the attempt failed
errorstring | nullrequiredWhy the attempt failed. Null when it succeeded. A failed attempt counts in `errors`, not `scored`
matchboolean | nullrequiredWhether the text equals the expected text after normalizing (lowercase, punctuation dropped except in-word apostrophes, whitespace collapsed; digits and number words stay distinct). Null when the turn has no expected text or the attempt failed
wernumber | nullrequiredWord error rate against the expected text: word edits divided by the expected word count, 0 for a match, can exceed 1. Null when there is no expected text or text
notesenum[]requiredOn a match, how the raw text still differs from the expected: `case`, `punctuation`, or both. Empty otherwise
"case""punctuation"identicalToProductionboolean | nullrequiredOn a candidate or calibration attempt of a full-call turn, whether its text equals production's, normalized. Null for production attempts, flagged and control turns, and failed attempts
audioSecondsnumberrequiredSeconds of audio the transcriber processed for the attempt. 0 for production attempts, which replay nothing
identicalboolean | nullrequiredThe candidate's text equals production, normalized. Null until the candidate's attempt arrives, and when it failed
labelenum | nullrequiredThe turn's label, as on the turn: from the expected-text matches where the line has expected text, else the LLM judge's. candidate_right: the candidate has what the caller said and production does not. production_right: production has it and the candidate does not. same_meaning: they differ in a way that does not matter. both_wrong: neither has it. Null when identical or not labeled yet
"candidate_right""production_right""same_meaning""both_wrong"reviewenum | nullrequiredA person's verdict, as on the turn. Null until reviewed
"candidate_right""production_right""same_meaning""both_wrong"nextCursorstring | nullrequiredSend as `cursor` for the next page. Null on the last page
metadataobjectoptionalRequest metadata
Show 3 child properties
timestampstringrequiredWhen the server answered, ISO 8601 UTC
versionstringrequiredAPI version
pathstringoptionalThe URL that was requested
400VALIDATION_ERROR: a path id, query parameter or body field broke a rule; `details` lists each `field` and its `message`. A body with a missing field or a JSON type the schema does not allow answers 400 with code INTERNAL_SERVER_ERROR and no `details` instead, so branch on the status
successbooleanrequiredfalse on every error
errorobjectoptionalWhat went wrong: a stable `code` to branch on and a human-readable `message`
Show 3 child properties
codeenumrequiredA parameter or body field broke a rule
"VALIDATION_ERROR"messagestringrequiredHuman-readable explanation. Do not parse it; branch on `code`
detailsobject[]optionalOne entry per field that failed
Show 2 item properties
fieldstringrequiredThe offending field
messagestringrequiredThe rule it broke
metadataobjectoptionalRequest metadata
Show 3 child properties
timestampstringrequiredWhen the server answered, ISO 8601 UTC
versionstringrequiredAPI version
pathstringoptionalThe URL that was requested
401UNAUTHORIZED: no valid credentials, or a dashboard token that names no organization. Send `Authorization: ApiKey <organization API key>`
successbooleanrequiredfalse on every error
errorobjectoptionalWhat went wrong: a stable `code` to branch on and a human-readable `message`
Show 2 child properties
codeenumrequiredNo valid credentials
"UNAUTHORIZED"messagestringrequiredHuman-readable explanation. Do not parse it; branch on `code`
metadataobjectoptionalRequest metadata
Show 3 child properties
timestampstringrequiredWhen the server answered, ISO 8601 UTC
versionstringrequiredAPI version
pathstringoptionalThe URL that was requested
403ORG_SCOPE_REQUIRED: transcriber testing is an organization feature. Use an organization API key without `X-Tenant-Id`, or a dashboard token scoped to the organization. A tenant API key, an organization key sent with `X-Tenant-Id` for one of its tenants, or a token carrying a tenant gets this 403. FORBIDDEN: an organization key sent `X-Tenant-Id` for a tenant outside its organization
successbooleanrequiredfalse on every error
errorobjectoptionalWhat went wrong: a stable `code` to branch on and a human-readable `message`
Show 2 child properties
codeenumrequiredORG_SCOPE_REQUIRED: the credentials carry a tenant scope. FORBIDDEN: an organization key sent `X-Tenant-Id` for a tenant outside its organization
"ORG_SCOPE_REQUIRED""FORBIDDEN"messagestringrequiredHuman-readable explanation. Do not parse it; branch on `code`
metadataobjectoptionalRequest metadata
Show 3 child properties
timestampstringrequiredWhen the server answered, ISO 8601 UTC
versionstringrequiredAPI version
pathstringoptionalThe URL that was requested
404RESOURCE_NOT_FOUND: an id in the path, query or body names nothing in the caller's organization. `message` names what, e.g. "Transcriber bank not found"
successbooleanrequiredfalse on every error
errorobjectoptionalWhat went wrong: a stable `code` to branch on and a human-readable `message`
Show 2 child properties
codeenumrequiredAn id names nothing the caller can see
"RESOURCE_NOT_FOUND"messagestringrequiredHuman-readable explanation. Do not parse it; branch on `code`
metadataobjectoptionalRequest metadata
Show 3 child properties
timestampstringrequiredWhen the server answered, ISO 8601 UTC
versionstringrequiredAPI version
pathstringoptionalThe URL that was requested
500An unexpected server error
successbooleanrequiredfalse on every error
errorobjectoptionalWhat went wrong: a stable `code` to branch on and a human-readable `message`
Show 2 child properties
codeenumrequiredAn unexpected server failure
"INTERNAL_SERVER_ERROR"messagestringrequiredHuman-readable explanation. Do not parse it; branch on `code`
metadataobjectoptionalRequest metadata
Show 3 child properties
timestampstringrequiredWhen the server answered, ISO 8601 UTC
versionstringrequiredAPI version
pathstringoptionalThe URL that was requested