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=layers or GET …/layers) — raw engine output, glossary baseline, current working copy, text diffs, and wordSyncVsRaw (word timing before/after sync). Use when building a review or edit UI. Read current.revision before any segment save.
  • Thumbnail URLs (?include=thumbnailUrls) — adds short-lived download url on each entry in thumbnails.items for s3_direct jobs.

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} with text + revision. After each 200, use data.revision for the next save.
  • Many segments at once PATCH …/segments with updates[] (up to 200). One revision bump for the whole batch. Do not send parallel single-segment PATCH calls with the same revision; only the first would succeed.

Which endpoint?

GoalEndpoint
Import SRT / segment captions (BYOT)POST /v1/projects/{projectId}/text-sources/import
Browse transcripts (no full text)GET /v1/transcriptions
Export JSON / SRT / word timingsGET /v1/transcriptions/{id}
Fetch after job completesGET /v1/transcriptions/{id} using resultSummary.transcriptionId from the job
Custom editor / audit diffsGET …?include=layers or GET …/layers
Fix one segmentPATCH …/segments/{segmentId} + revision
Save many segment editsPATCH …/segments with updates[]
Apply project glossaryPOST …/glossary/preview then …/apply
Rename or move in libraryPATCH /v1/transcriptions/{id}
Push edits back to S3 direct outputsGET …/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 textSourceId for 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 by folderId only.
textstring
Full working-copy transcript text.
segmentsarray
Timed segments. Each has id, start, end, text, optional speaker, optional voiceId, and optional words ({ "word": "Hello", "start": 0.0, "end": 0.4, "score": 0.99, "speaker": "SPEAKER_00" }). Whisper sets score to 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.ta contains Tamil translated segments. Each cached translated segment has id, start, end, text, optional sourceText, optional speaker, optional voiceId, and optional source words. This cache is updated when a translation job completes or when translated segment text is patched. Re-running the same language replaces translation.<languageKey>.
translation.<languageKey>[]array, optional
Array of cached translated segments for one language, for example translation.ta, translation.es, or translation.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, optional jobId, items[] and nonAiItems[] with S3 bucket / key per image. Add ?include=thumbnailUrls for short-lived download URLs.
userEditedboolean
True when a user has edited segment text via the API or dashboard.
activeLayerstring
Working layer: glossary, edited, or raw.
revisioninteger
Optimistic-lock token for segment PATCH. Required on PATCH …/segments and PATCH …/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)

POST/v1/projects/{projectId}/text-sources/import
Sync import of captions for an existing video in connected storage. Provide exactly one of segments (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 segments linked to a video sourceKey; the API writes .srt and companion artifacts under the resolved output prefix.
  • Console / upload flow — presign a PUT with purpose: "transcript_srt", upload the file, then call import with srtKey.

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

Created transcript object (textSourceId, segments, speakers, sourceLanguage, …).

See the the transcript object for attribute details.

List transcripts

GET/v1/transcriptions
Paginated list items with preview fields and job metadata — not full text 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 transcriptionId for text and segments.

Requires permission

transcript:list

List item fields: 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

GET/v1/transcriptions/{transcriptionId}
Returns the final working transcript: glossary-applied text, manual edits, and word timings aligned to each segment's 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=srt for SubRip or format=vtt for WebVTT download (no JSON envelope).
  • Word-level timing — use segments[].words for karaoke, cut lists, or highlight UIs. Timings are synced on read when needed.
  • Custom editor bootstrap — add ?include=layers to get raw/glossary/current and diffs in one round trip instead of a separate /layers call.
  • Skip layers if you only need final text — smaller payload, faster response.

Requires permission

transcript:read

SRT responses use 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, or vtt (raw file, no JSON envelope).
includestring, optional
Comma-separated expansions. Use layers to add a layers object (same as GET …/layers) for building review/edit UIs in one request. Use thumbnailUrls to add short-lived download url on each thumbnails.items[] entry (s3_direct jobs).

Returns

Transcript object, or raw SRT/VTT when format=srt or format=vtt.

See the the transcript object for attribute details.

Retrieve transcript layers

GET/v1/transcriptions/{transcriptionId}/layers
Returns raw, 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, and diffs.currentVsRaw.
  • Word timing auditdiffs.wordSyncVsRaw lists segments where word tokens were reconciled to segment text (before/after preview strings).
  • Editor segment list — bind UI to current.segments; use rawfor "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

Object with raw, glossary, current, glossaryApplications, and diffs.

See the the transcript object for attribute details.

Edit multiple segments (batch)

PATCH/v1/transcriptions/{transcriptionId}/segments
Updates one or more segments in a single revision-checked write. Use this when the user saves many segment edits at once — do not fire parallel single-segment PATCH calls with the same revision (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 segmentId entries 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

ApproachResult
Three parallel PATCH …/segments/seg_N, all revision: 0One 200, two 409 conflict — not a batch save
One PATCH …/segments with three updates entries, revision: 0One 200, all three segments updated, revision: 1
Three sequential single-segment PATCHes, passing each response's data.revisionThree 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). Duplicate segmentId values: last entry wins.

Returns

Updated Transcript object. 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

PATCH/v1/transcriptions/{transcriptionId}/segments/{segmentId}
Updates one segment's 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 revision from your last read of the transcript (or layers current.revision). On success, revision increments by 1. Stale writes return 409 conflict — refresh and retry. For many segments at once, use PATCH …/segments (batch) instead of parallel single-segment calls.
  • Not for bulk glossary — use POST …/glossary/apply for 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

Updated Transcript object (including the new revision).

See the the transcript object for attribute details.

Preview glossary apply

POST/v1/transcriptions/{transcriptionId}/glossary/preview
Dry-run project glossary rules against a chosen layer. Nothing is persisted.

When 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, or raw depending 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, or raw.

Returns

changes, glossarySnapshotId, and base.

See the the transcript object for attribute details.

Apply glossary

POST/v1/transcriptions/{transcriptionId}/glossary/apply
Applies project glossary rules and persists the result. Returns the updated Transcript object.

When to use

  • After preview — user approved the changes list.
  • Batch re-normalization when project glossary rules change — re-apply from raw or glossary baseline via base.
  • Sets activeLayer to 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, or raw.

Returns

Updated Transcript object.

See the the transcript object for attribute details.

Revert to glossary baseline

POST/v1/transcriptions/{transcriptionId}/revert/glossary
Restores the working copy to the frozen glossary baseline, discarding manual segment edits made after glossary was applied.

When 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/apply to pick up new project rules.

Requires permission

transcript:edit

Parameters

transcriptionIdstring
Transcript identifier.

Returns

Updated Transcript object.

See the the transcript object for attribute details.

Revert to raw transcription

POST/v1/transcriptions/{transcriptionId}/revert/raw
Restores the working copy to immutable engine output — before glossary and before manual edits.

When to use

  • Full reset — start review again from raw ASR output.
  • Re-apply glossary from scratch — revert raw, then glossary/apply with base: 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

Updated Transcript object.

See the the transcript object for attribute details.

Update display name

PATCH/v1/transcriptions/{transcriptionId}
Updates the library 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

GET/v1/transcriptions/{transcriptionId}/storage
For transcripts created from an s3_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 — confirm available: true and inspect outputKeys.
  • Transcriptions not created from s3_direct jobs return available: 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

POST/v1/transcriptions/{transcriptionId}/storage/sync
Overwrites the four standard output objects in the customer bucket with the current working copy (full text, segments JSON, SRT, and VTT). Uses the project storage connection from the original s3_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 …/storage to report available: 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

DELETE/v1/transcriptions/{transcriptionId}
Permanently removes the stored transcript (text, segments, and glossary layers). The parent job record is kept; its 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.

Returns

transcriptionId, jobId, and deleted: true.

See the the transcript object for attribute details.