Transcripts
When a transcription Job completes, the platform stores a Transcript with full text and timed segments (optional per-word timestamps). You can also import captions without running ASR via POST /v1/projects/{projectId}/text-sources/import (bring your own transcript). There is no public delete endpoint. If a job fails with transcript_too_large, no transcript is created — see Plans & limits.
Note: ASR transcription jobs also generate visual frame analysis chunks for the video (used by Summarizations). BYOT imports skip video analysis — all speakers are set to SPEAKER_00, and the import does not consume transcription credits.
Two response shapes
- Default GET — export-ready working copy: project glossary applied, manual edits included, word timings reconciled to segment text. Use for clips, captions, search indexing, and downstream jobs.
- Layers (
?include=layersorGET …/layers) — raw engine output, glossary baseline, current working copy, text diffs, andwordSyncVsRaw(word timing before/after sync). Use when building a review or edit UI. Readcurrent.revisionbefore any segment save. - Thumbnail URLs (
?include=thumbnailUrls) — adds short-lived downloadurlon each entry inthumbnails.itemsfors3_directjobs.
Segment edits & revision
Segment PATCH endpoints require the current revision from your last GET (or layers.current.revision). Each successful save increments revision by 1. A stale revision returns 409 conflict — refresh the transcript and retry.
- One segment —
PATCH …/segments/{segmentId}withtext+revision. After each 200, usedata.revisionfor the next save. - Many segments at once —
PATCH …/segmentswithupdates[](up to 200). One revision bump for the whole batch. Do not send parallel single-segment PATCH calls with the samerevision; only the first would succeed.
Which endpoint?
| Goal | Endpoint |
|---|---|
| Import SRT / segment captions (BYOT) | POST /v1/projects/{projectId}/text-sources/import |
| Browse transcripts (no full text) | GET /v1/transcriptions |
| Export JSON / SRT / word timings | GET /v1/transcriptions/{id} |
| Fetch after job completes | GET /v1/transcriptions/{id} using resultSummary.transcriptionId from the job |
| Custom editor / audit diffs | GET …?include=layers or GET …/layers |
| Fix one segment | PATCH …/segments/{segmentId} + revision |
| Save many segment edits | PATCH …/segments with updates[] |
| Apply project glossary | POST …/glossary/preview then …/apply |
| Rename or move in library | PATCH /v1/transcriptions/{id} |
| Push edits back to S3 direct outputs | GET …/storage then POST …/storage/sync |
Requires a project API key with transcript:list, transcript:read, transcript:edit for modifications, and transcript:delete to remove stored transcripts. See Jobs to submit work and Jobs & transcripts workflows for end-to-end patterns. Folder organization is managed in the Perchat console; transcript objects expose read-only folderId for filtering when folders exist.
The Transcript object
- textSourceIdstring
- Canonical text source identifier (
txt_…). - transcriptionIdstring
- Alias of
textSourceIdfor transcription artifacts (txt_…). - jobIdstring
- Parent transcription job.
- workspaceIdstring
- Owning workspace.
- projectIdstring
- Owning project.
- displayNamestring | null, optional
- Library title (defaults from source filename or job reference). Set via
PATCH …/transcriptions/{id}. - folderIdstring | null, optional
- Optional folder (
tfld_…). Folders are created and assigned in the Perchat console; API consumers can read and filter byfolderIdonly. - textstring
- Full working-copy transcript text.
- segmentsarray
- Timed segments. Each has
id,start,end,text, optionalspeaker, optionalvoiceId, and optionalwords({ "word": "Hello", "start": 0.0, "end": 0.4, "score": 0.99, "speaker": "SPEAKER_00" }). Whisper setsscoreto 1.0; Deepgram returns real confidence 0–1. Max source duration is configured in platform settings (default 1 hour). Sources longer than this fail with duration_exceeded. Word-level timings are stored through the same limit — longer jobs return segments without per-word timings. - segments[].speakerstring | null, optional
- Speaker label when diarization or upstream word metadata is available, for example SPEAKER_00.
- segments[].voiceIdstring | null, optional
- Perchat voice ID assigned to this source segment when available. Dubbing can reuse this instead of auto-creating a voice.
- segments[].words[].speakerstring | null, optional
- Speaker label on a word timing entry when provided by the transcription backend.
- translationobject, optional
- Cached translated segment arrays keyed by normalized language code. For example,
translation.tacontains Tamil translated segments. Each cached translated segment hasid,start,end,text, optionalsourceText, optionalspeaker, optionalvoiceId, and optional sourcewords. This cache is updated when a translation job completes or when translated segment text is patched. Re-running the same language replacestranslation.<languageKey>. - translation.<languageKey>[]array, optional
- Array of cached translated segments for one language, for example
translation.ta,translation.es, ortranslation.ja. - translation.<languageKey>[].idstring
- Translated segment id. Usually matches the source transcription segment id.
- translation.<languageKey>[].startnumber
- Original segment start time in seconds.
- translation.<languageKey>[].endnumber
- Original segment end time in seconds.
- translation.<languageKey>[].textstring
- Translated segment text for this language.
- translation.<languageKey>[].sourceTextstring, optional
- Original source segment text used for translation.
- translation.<languageKey>[].speakerstring | null, optional
- Speaker label copied from the source segment when available.
- translation.<languageKey>[].voiceIdstring | null, optional
- Perchat voice ID copied from the source segment when available.
- translation.<languageKey>[].wordsarray, optional
- Source word timings copied from the transcript when available.
- translation.<languageKey>[].words[].speakerstring | null, optional
- Speaker label copied from the source word timing when available.
- textPreviewstring
- Short preview (also on the parent job).
- segmentCountinteger
- Number of segments.
- durationSecnumber | null, optional
- Duration from last segment end time.
- thumbnailsobject, optional
- Thumbnail metadata when a thumbnail job has completed for this transcription (at most 3 AI images per job, plus up to 5 non-AI frames). Includes
generated,thumbnailCount,nonAiThumbnailCount, optionaljobId,items[]andnonAiItems[]with S3bucket/keyper image. Add?include=thumbnailUrlsfor short-lived download URLs. - userEditedboolean
- True when a user has edited segment text via the API or dashboard.
- activeLayerstring
- Working layer:
glossary,edited, orraw. - revisioninteger
- Optimistic-lock token for segment PATCH. Required on
PATCH …/segmentsandPATCH …/segments/{segmentId}. Also increments when glossary apply or revert runs. - editedAttimestamp | null, optional
- Last edit time.
- editedBystring | null, optional
- User id of last editor (session auth only).
- createdAttimestamp
- Record creation time.
- updatedAttimestamp
- Last update time.
Import transcript (BYOT)
/v1/projects/{projectId}/text-sources/importsegments (JSON array) or srtKey (object already uploaded to the bucket). Creates a completed stub transcription job for library linkage — no Kafka worker, no ASR, no video analysis, no transcription credits. Every segment is assigned SPEAKER_00. On srtKey validation failure the object is deleted and the request returns 422.When to use
- API clients — send timed
segmentslinked to a videosourceKey; the API writes.srtand companion artifacts under the resolved output prefix. - Console / upload flow — presign a PUT with
purpose: "transcript_srt", upload the file, then call import withsrtKey.
Requires permission
transcript:edit
Parameters
- connectionIdstring
- Project storage connection that owns the video.
- bucketstring
- Bucket containing the source video.
- sourceKeystring
- Object key of the source video (must be a video file).
- outputPrefixstring, optional
- Optional output folder. Empty/omitted uses {bucket-default}/{textSourceId}/transcripts/.
- displayNamestring, optional
- Optional transcript version display name.
- sourceLanguagestring
- Required ISO language code for the imported transcript (e.g. en, ta, en-us). Stored as transcriptionMeta.sourceLanguage.
- segmentsarray, optional
- XOR with srtKey. Array of { start, end, text } (seconds). Server assigns seg_N ids and SPEAKER_00.
- srtKeystring, optional
- XOR with segments. Key of an already-uploaded .srt in the same bucket. Deleted if validation fails.
Returns
textSourceId, segments, speakers, sourceLanguage, …).See the the transcript object for attribute details.
List transcripts
/v1/transcriptionstext or segments.When to use
- Transcripts library — table views with preview, duration, source URL, and job status without loading full segment payloads.
- Search and filter — by preview text, input URL, job id, or parent job status.
- Not for export or editing — each row is metadata only; call retrieve with
transcriptionIdfortextandsegments.
Requires permission
transcript:list
transcriptionId, jobId, workspaceId, projectId, textPreview, segmentCount, durationSec, jobStatus, jobInput, jobCompletedAt, createdAt.Query parameters
- pageinteger, optional
- Default 1.
- limitinteger, optional
- Default 20, max 100.
- jobIdstring, optional
- Filter by job ID substring.
- previewstring, optional
- Filter by preview text substring.
- inputstring, optional
- Filter by source URL / input substring.
- namestring, optional
- Filter by display name or text preview substring.
- folderIdstring, optional
- Only transcripts assigned to this folder (tfld_…).
- uncategorizedOnlyboolean, optional
- When true, only transcripts with no folderId.
- statusesstring, optional
- Comma-separated parent job statuses.
- sortstring, optional
- jobId, name, preview, input, status, segments, duration, completed (default).
- sortDirstring, optional
- asc or desc. Default desc.
Returns
data array of list items (see example); metadata.pagination.See the the transcript object for attribute details.
Retrieve a transcript
/v1/transcriptions/{transcriptionId}text. This transcription is fully ready to be passed directly to the Summarizations API.When to use
- Export pipeline — default JSON is the canonical transcript for clips, summarization, or storage.
- Captions — pass
format=srtfor SubRip orformat=vttfor WebVTT download (no JSON envelope). - Word-level timing — use
segments[].wordsfor karaoke, cut lists, or highlight UIs. Timings are synced on read when needed. - Custom editor bootstrap — add
?include=layersto get raw/glossary/current and diffs in one round trip instead of a separate/layerscall. - Skip layers if you only need final text — smaller payload, faster response.
Requires permission
transcript:read
Content-Type: text/srt; VTT uses text/vtt. Both set Content-Disposition: attachment. To build a transcript editor UI, call retrieve with include=layers (or fetch /layers separately), then save segments with revision (batch or single-segment PATCH), POST …/glossary/preview, POST …/glossary/apply, and POST …/revert/glossary or …/revert/raw.Parameters
- transcriptionIdstring
- txt_ text source identifier from resultSummary or list (also returned as transcriptionId).
Query parameters
- formatstring, optional
json(default),srt, orvtt(raw file, no JSON envelope).- includestring, optional
- Comma-separated expansions. Use
layersto add alayersobject (same asGET …/layers) for building review/edit UIs in one request. UsethumbnailUrlsto add short-lived downloadurlon eachthumbnails.items[]entry (s3_directjobs).
Returns
format=srt or format=vtt.See the the transcript object for attribute details.
Retrieve transcript layers
/v1/transcriptions/{transcriptionId}/layersraw, glossary, and current layer copies plus diffs and glossary application history.When to use
- Review UI — show side-by-side raw vs corrected text using
diffs.glossaryVsRaw,diffs.currentVsGlossary, anddiffs.currentVsRaw. - Word timing audit —
diffs.wordSyncVsRawlists segments where word tokens were reconciled to segment text (before/after preview strings). - Editor segment list — bind UI to
current.segments; userawfor "reset to engine output" previews. - Equivalent to
GET …/transcriptions/{id}?include=layers— use whichever fits your fetch pattern.
Requires permission
transcript:read
Parameters
- transcriptionIdstring
- Transcript identifier.
Returns
raw, glossary, current, glossaryApplications, and diffs.See the the transcript object for attribute details.
Edit multiple segments (batch)
/v1/transcriptions/{transcriptionId}/segmentsrevision (only the first would succeed).When to use
- Batch save— custom editor "Save all" or queued edits submitted together.
- Up to 200 segments per request; duplicate
segmentIdentries use the last text wins.
Requires permission
transcript:edit
Request body:
{
"revision": 0,
"updates": [
{ "segmentId": "seg_0", "text": "deadlift form" },
{ "segmentId": "seg_1", "text": "brace your core" }
]
}Parallel single-segment PATCH vs batch
| Approach | Result |
|---|---|
Three parallel PATCH …/segments/seg_N, all revision: 0 | One 200, two 409 conflict — not a batch save |
One PATCH …/segments with three updates entries, revision: 0 | One 200, all three segments updated, revision: 1 |
Three sequential single-segment PATCHes, passing each response's data.revision | Three 200 responses — works, more round trips |
Stale revision response:
{
"data": null,
"error": {
"code": "conflict",
"message": "transcript txt_01HX2K9V3JEK4WYZN6F0XQ2W8M was modified (expected revision 0); refresh and retry",
"details": [{ "path": "revision", "issue": "stale" }]
},
"metadata": { "requestId": "req_01HX...", "responseTime": 3, "timestamp": "...", "version": "v1" }
}See Errors for envelope shape.
Parameters
- transcriptionIdstring
- Transcript identifier.
- revisioninteger
- Current revision from GET transcript or layers.
- updatesarray
- Non-empty array of
{ segmentId, text }(max 200). DuplicatesegmentIdvalues: last entry wins.
Returns
revision increments once (e.g. 0 → 1) regardless of how many entries are in updates.See the the transcript object for attribute details.
Edit a segment
/v1/transcriptions/{transcriptionId}/segments/{segmentId}text in the working copy. Word timings are re-synced to the new text. May learn glossary rules from the edit.When to use
- Human correction in a custom transcript editor after retrieve or layers load.
- Requires
revisionfrom your last read of the transcript (or layerscurrent.revision). On success,revisionincrements by 1. Stale writes return409 conflict— refresh and retry. For many segments at once, usePATCH …/segments(batch) instead of parallel single-segment calls. - Not for bulk glossary — use
POST …/glossary/applyfor project-wide rules.
Requires permission
transcript:edit
After a successful save, persist data.revision for the next edit. If you save another segment before refreshing, send the latest revision from the previous response — not the revision from the initial page load.
Stale revision → 409 conflict (same envelope as batch — see Edit multiple segments).
Parameters
- transcriptionIdstring
- Transcript identifier.
- segmentIdstring
- Segment id (e.g. seg_0).
- textstring
- New segment text.
- revisioninteger
- Revision from GET transcript or layers (current.revision). Must match the stored revision or the API returns 409.
Returns
See the the transcript object for attribute details.
Preview glossary apply
/v1/transcriptions/{transcriptionId}/glossary/previewWhen to use
- Confirm-before-apply — show the user which segments would change and which rule matched.
- After glossary updates — preview impact on existing transcripts before
glossary/apply. - Choose
base:current(default),glossary, orrawdepending on whether edits should be preserved or overwritten.
Requires permission
transcript:edit
Parameters
- transcriptionIdstring
- Transcript identifier.
- basestring, optional
- Layer to apply against:
current(default),glossary, orraw.
Returns
Apply glossary
/v1/transcriptions/{transcriptionId}/glossary/applyWhen to use
- After preview — user approved the
changeslist. - Batch re-normalization when project glossary rules change — re-apply from
raworglossarybaseline viabase. - Sets
activeLayerto glossary state; manual edits on top use segment PATCH or revert endpoints.
Requires permission
transcript:edit
Parameters
- transcriptionIdstring
- Transcript identifier.
- basestring, optional
- Same as preview —
current,glossary, orraw.
Returns
See the the transcript object for attribute details.
Revert to glossary baseline
/v1/transcriptions/{transcriptionId}/revert/glossaryWhen to use
- User wants to undo manual edits but keep glossary corrections.
- Does not re-run glossary rules — restores the stored glossary snapshot. Use
glossary/applyto pick up new project rules.
Requires permission
transcript:edit
Parameters
- transcriptionIdstring
- Transcript identifier.
Returns
See the the transcript object for attribute details.
Revert to raw transcription
/v1/transcriptions/{transcriptionId}/revert/rawWhen to use
- Full reset — start review again from raw ASR output.
- Re-apply glossary from scratch — revert raw, then
glossary/applywithbase: raw. - Destructive to manual edits and glossary state on the working copy — confirm in UI before calling.
Requires permission
transcript:edit
Parameters
- transcriptionIdstring
- Transcript identifier.
Returns
See the the transcript object for attribute details.
Update display name
/v1/transcriptions/{transcriptionId}displayName. Does not change segment text — use segment PATCH or glossary endpoints for content edits. Folder assignment is managed in the Perchat console, not via API keys.When to use
- Rename in your UI — override the auto-generated title from the source filename.
Requires permission
transcript:edit
Parameters
- transcriptionIdstring
- Transcript identifier.
- displayNamestring, optional
- New title (max 200 characters).
Returns
transcriptionId, displayName, and folderId (unchanged unless updated in the console).See the the transcript object for attribute details.
Storage sync status
/v1/transcriptions/{transcriptionId}/storages3_direct transcription job, reports whether edited outputs can be pushed back to the customer bucket and which object keys would be updated.When to use
- Before
POST …/storage/sync— confirmavailable: trueand inspectoutputKeys. - Transcriptions not created from
s3_directjobs returnavailable: false— outputs were uploaded outside a storage connection workflow.
Requires permission
transcript:read
Parameters
- transcriptionIdstring
- Transcript identifier.
Returns
available (boolean). When true: bucket, sourceKey, and outputKeys (fullTextTxt, segmentsJson, transcriptSrt, transcriptVtt).See the the transcript object for attribute details.
Sync transcript to S3
/v1/transcriptions/{transcriptionId}/storage/syncs3_direct job.When to use
- After segment edits or glossary apply — keep downstream systems on S3 in sync with the Perchat working copy.
- Requires
GET …/storageto reportavailable: true.
Requires permission
transcript:edit
Parameters
- transcriptionIdstring
- Transcript identifier.
Returns
synced: true, bucket, and keys (the object keys written).See the the transcript object for attribute details.
Delete a transcript
/v1/transcriptions/{transcriptionId}resultSummary is cleared (null).When to use
- Data retention — remove transcript payloads while keeping job audit history.
- Re-run workflow — delete a bad transcript before submitting a new transcription job for the same source.
- Irreversible — export SRT or JSON first if you need a backup.
Requires permission
transcript:delete
Parameters
- transcriptionIdstring
- Transcript identifier.