API docs · Build
Results
Read transcripts as JSON, SRT, WebVTT or plain text, and scenes with captions, objects, palettes and shot types. What "not ready" and "unavailable" mean.
Each billable stage has its own endpoint. Results are readable as soon as that stage's status is completed, whatever the other stage is doing.
| Endpoint | Returns |
|---|---|
GET /jobs/{jobId}/transcript | The transcript as JSON, or ?format=srt, vtt or txt as a file |
GET /jobs/{jobId}/scenes | Detected scenes with captions |
GET /jobs/{jobId}/audioTracks | Per-track transcripts of a multi-track job (stored form) |
Transcript
curl "https://api.framequery.com/v1/api/jobs/$JOB_ID/transcript" \
-H "Authorization: Bearer $FRAMEQUERY_API_KEY"{
"data": {
"jobId": "0b5e6c1e-6f43-4a0e-9d4c-2f7f3c1b9a10",
"language": "en",
"speakers": ["Speaker 1", "Speaker 2"],
"text": "Morning. Did you see the forecast for tomorrow? Rain all day, apparently.",
"segments": [
{ "startTime": 40.2, "endTime": 41.0, "text": "Morning.", "speaker": "Speaker 1" },
{ "startTime": 41.6, "endTime": 44.1, "text": "Did you see the forecast for tomorrow?", "speaker": "Speaker 2" },
{ "startTime": 44.5, "endTime": 46.3, "text": "Rain all day, apparently.", "speaker": "Speaker 1" }
]
},
"requestId": "5d7e1f0a3b9c4e28"
}| Field | Notes |
|---|---|
language | Detected language code, for example en |
speakers | Every speaker label used by a segment, "Speaker 1", "Speaker 2" and so on |
text | The whole transcript: segment texts joined by single spaces |
segments[].startTime, endTime | Seconds (float) from the start of the media |
segments[].text | The words spoken in the segment |
segments[].speaker | One entry of speakers, or null when diarisation could not attribute the segment |
segments[].speakerTag | Deprecated numeric form of speaker ("Speaker 2" is 2). Use speaker |
tracks, trackIndex, trackName | Multi-track jobs; see below |
Speaker labels are consistent within a job, not across jobs: Speaker 1 in one job is not the same person as Speaker 1 in another. Word-level timestamps are not part of the beta API.
SRT, WebVTT and plain text
The server renders caption files, so every client gets identical output. They are sent as downloads (Content-Disposition: attachment).
curl "https://api.framequery.com/v1/api/jobs/$JOB_ID/transcript?format=srt" \
-H "Authorization: Bearer $FRAMEQUERY_API_KEY" -o interview.srt1
00:00:40,200 --> 00:00:41,000
Speaker 1: Morning.
2
00:00:41,600 --> 00:00:44,100
Speaker 2: Did you see the forecast for tomorrow?WEBVTT
00:00:40.200 --> 00:00:41.000
<v Speaker 1>Morning.
00:00:41.600 --> 00:00:44.100
<v Speaker 2>Did you see the forecast for tomorrow?Speaker 1: Morning.
Speaker 2: Did you see the forecast for tomorrow?Segments without a speaker have no label. On a multi-track job the file formats need track; without it the request fails with 400 INVALID_REQUEST and param: "track".
Multi-track transcripts
For a job with several audio tracks (see Multi-track audio):
- Without
track, the JSON response addstracks[]. Each entry hastrackIndex,trackName(yourlabel),status,language,speakers,text,segmentsand, when that track failed,errorCode. ?track=1returns that one track in the top-level shape, withtrackIndexandtrackNameset. A track that failed returns404 RESULTS_UNAVAILABLEwithreason: "track_failed"and itstrackIndex.
Scenes
curl "https://api.framequery.com/v1/api/jobs/$JOB_ID/scenes" \
-H "Authorization: Bearer $FRAMEQUERY_API_KEY"{
"data": {
"jobId": "0b5e6c1e-6f43-4a0e-9d4c-2f7f3c1b9a10",
"scenes": [
{
"index": 0,
"startTime": 0.0,
"endTime": 6.4,
"description": "Aerial view of a coastal town at sunrise with fishing boats moored in the harbour.",
"objects": ["town", "harbour", "fishing-boat", "sea", "hills"],
"colorPalette": ["#f2b56b", "#2f5d7c", "#c9d6df", "#8a4f3d"],
"shotType": "extreme-wide",
"shotAngle": "aerial"
},
{
"index": 1,
"startTime": 6.4,
"endTime": 11.9,
"description": "A fisherman in a yellow jacket coils rope on the deck of a small boat.",
"objects": ["fisherman", "yellow-jacket", "rope", "boat-deck"],
"colorPalette": ["#e3c13b", "#3e4a52", "#a7b3ba", "#6b4f3a"],
"shotType": "medium",
"shotAngle": "high-angle"
}
]
},
"requestId": "a2c4e6f8b0d14f39"
}| Field | Notes |
|---|---|
index | Position in the list; scenes are ordered by startTime |
startTime, endTime | Seconds (float) |
description | One sentence describing the subject, action, setting and key visual details |
objects | Up to about 10 visible objects as short lowercase labels ("red-car"). Labels, not bounding boxes |
colorPalette | Dominant colours of the frame as hex strings, most dominant first |
shotType | One of extreme-wide, wide, full, medium-wide, medium, medium-close-up, close-up, extreme-close-up, over-the-shoulder, two-shot, group-shot, pov, insert, cutaway, reaction, aerial, silhouette, static-graphic |
shotAngle | One of eye-level, low-angle, high-angle, dutch, aerial |
startTs, endTs | Deprecated aliases of startTime / endTime for SDK 0.1. They will be removed |
A video without scene cuts returns an empty scenes array. Treat unknown shotType or shotAngle values as plain strings: the vocabulary can grow.
Not ready versus unavailable
The results endpoints tell you whether to wait or to stop:
| Response | Meaning | What to do |
|---|---|---|
200 | The stage completed | Use the data |
409 RESULTS_NOT_READY | The stage is pending or running and may still complete. The body adds state, stage, stageStatus | Retry after Retry-After (15 s), or wait for the webhook |
404 RESULTS_UNAVAILABLE | The output does not exist and never will. The body adds state, stage, stageStatus, reason, and errorCode or trackIndex when relevant | Stop polling. Read reason |
404 NOT_FOUND | No such job (or track) for this key | Check the id |
{
"error": "This job has no results for the requested stage and none will be produced.",
"code": "RESULTS_UNAVAILABLE",
"docUrl": "https://framequery.com/docs/errors#RESULTS_UNAVAILABLE",
"state": "completed",
"stage": "vision",
"stageStatus": "skipped",
"reason": "audio_only_input",
"requestId": "f0e1d2c3b4a54968"
}reason | Why |
|---|---|
processing_mode | The job's processingMode excludes this stage |
audio_only_input | The input has no video, so there is no vision stage |
no_audio | The input has no audio stream, so there is no transcript |
stage_skipped | The stage was skipped (cause not recorded) |
stage_failed | The stage failed; errorCode says why |
track_failed | The requested audio track failed |
job_cancelled | The job was cancelled before this stage ran |
job_expired | The job expired before this stage ran |
job_failed | Another stage failed before this one started |
Embedded results and audio-track endpoints
GET /jobs/{jobId} embeds results under processedData (scenes, transcript, speakers, language, length) unless you pass include=none. The embedded transcript uses the stored entry form, which older clients read. New code should use the endpoints above.
GET /jobs/{jobId}/audioTracks and GET /jobs/{jobId}/audioTracks/{trackIndex} return each track's stored transcript (trackIndex, trackName, status, transcript, speakers, language, errorCode). The transcript endpoint's tracks[] and ?track= cover the same data in the documented segment shape.