DocsAPI reference
API reference
Every /v1 endpoint, its parameters and status codes, with links to the interactive reference.
Use this reference for REST endpoints, parameters and responses. Open the interactive reference (Swagger UI) at https://api.transcript1.com/v1/docs, or download the machine-readable OpenAPI document from https://api.transcript1.com/v1/openapi.json.
Base URL and conventions
The base URL is https://api.transcript1.com/v1.
- Request and response bodies are JSON with
snake_casefield names. - Timestamps are ISO 8601 in UTC, for example
2026-10-13T09:30:00.000Z. - Durations and transcript times are in seconds.
- Every error uses the same envelope. See Errors.
- Every response to an authenticated request carries
X-RateLimit-LimitandX-RateLimit-Remaining. See Billing and limits.
Authentication
Send a credential in the Authorization header:
curl https://api.transcript1.com/v1/account \
-H "Authorization: Bearer t1_..."- An API key starts with
t1_. Create one on the API keys page. API keys can call every endpoint. - An OAuth access token starts with
t1o_. MCP clients such as Claude and ChatGPT receive one when you connect them. OAuth tokens carry the scopestranscriptions:readandtranscriptions:write.
| Scope | Allows |
|---|---|
transcriptions:read | GET /v1/transcriptions, GET /v1/transcriptions/:id, GET /v1/transcriptions/:id/upload and GET /v1/account |
transcriptions:write | POST /v1/transcriptions, DELETE /v1/transcriptions/:id and POST /v1/transcriptions/:id/upload/complete |
A token without the required scope returns 403 insufficient_scope. A missing or invalid credential returns 401 unauthorized. For chunk uploads, authenticate PUT /v1/transcriptions/:id/upload/chunks/:index with the X-Upload-Token returned when you create the upload. See Uploads.
Endpoints
| Endpoint | What it does |
|---|---|
POST /v1/transcriptions | Create a transcription from a YouTube URL, a one-shot file upload or a chunked upload reservation |
GET /v1/transcriptions/:id | Get the status or the finished transcript, optionally rendered as text, SRT or WebVTT |
GET /v1/transcriptions | List transcriptions, newest first, without transcripts |
DELETE /v1/transcriptions/:id | Cancel a running transcription, or delete a finished one |
PUT /v1/transcriptions/:id/upload/chunks/:index | Send one chunk of a chunked upload |
GET /v1/transcriptions/:id/upload | Read upload progress so an interrupted upload can resume |
POST /v1/transcriptions/:id/upload/complete | Verify the chunks and queue the transcription |
GET /v1/account | Read your plan, minutes and limits (never charges minutes) |
Create a transcription
POST /v1/transcriptions takes one of three body forms:
-
A platform URL as JSON. The only platform is
youtube:{ "platform": "youtube", "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "source": "auto", "language": "auto", "diarize": false, "webhook_url": "https://example.com/hook" } -
A one-shot file upload as
multipart/form-data, up to 95 MB. -
A chunked upload reservation as JSON, for files up to 2 GB:
{ "upload": { "filename": "interview.m4a", "size": 48210334, "mime_type": "audio/mp4" } }
source, language, diarize and webhook_url are optional in every form. See Sources and options, Uploads and Webhooks. An account needs a verified email address and some usable minutes to create a transcription.
Query parameters
| Parameter | Value | Meaning |
|---|---|---|
wait | integer, 0 to 60, default 0 | Hold the request open for up to this many seconds until the transcription reaches a final status. |
reuse_recent | true or false, default false | Platform URLs only. Return your most recent matching transcription instead of creating and charging a new one. |
reuse_recent=true returns your team's most recent transcription of the same video (different URL forms of one video match) with the same source, language and diarize, created in the last 24 hours and not failed or canceled. The response carries "reused": true. If nothing matches, a new transcription is created and the response carries "reused": false. The flag is rejected with invalid_request for uploads and when combined with webhook_url. An Idempotency-Key replay takes precedence over it. Two simultaneous first requests can still create two transcriptions, so use the flag for sequential retries.
Idempotency-Key header
Send Idempotency-Key as a request header on POST /v1/transcriptions to make a retry safe. It is not a query parameter. The value is 1 to 255 characters:
curl -X POST "https://api.transcript1.com/v1/transcriptions" \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY" \
-H "Idempotency-Key: 6f1c2d9e-3b7a-4a55-9c1e-0d2f8a7b4c10" \
-H "Content-Type: application/json" \
-d '{"platform":"youtube","url":"https://www.youtube.com/watch?v=dQw4w9WgXcQ"}'Repeating a request with the same key and the same parameters returns the original transcription and does not charge again. The same key with different parameters returns 409 idempotency_conflict. For chunked uploads, repeating the create with the same key issues a fresh upload token.
Status codes
201means the transcription isawaiting_uploadand the response includes theuploadblock.202means the transcription is processing (queued,fetchingortranscribing).200means it reached a final status withinwait:completed,failedorcanceled. A video transcript1 has already processed can complete immediately and return200.- Errors use the codes in Errors, for example
402 insufficient_minutes,409 idempotency_conflict,413 media_too_large,422 invalid_requestand429 rate_limited.
Get a transcription
GET /v1/transcriptions/:id returns the transcription object. A completed transcription includes transcript. An unknown id, or an id that belongs to another team, returns 404 not_found.
| Parameter | Value | Meaning |
|---|---|---|
wait | integer, 0 to 60, default 0 | Hold the request open until the transcription reaches a final status or the time runs out. |
format | json (default), text, srt or vtt | Render a completed transcript instead of returning JSON. |
include | words (write it as include=words) | JSON only. Adds a words array to every segment: start, end, text, confidence and speaker. Segments from creator captions have words: null. |
timestamps | true or false, default false | format=text only. Prefixes every line with [hh:mm:ss]. |
include_deleted | true or false, default false | Also return a deleted transcription, as a read-only record with deleted_at set and no transcript. wait is ignored, and a rendered format still returns 404 not_found. |
Rendered formats return the transcript itself, not JSON:
textistext/plain: one line per segment, with aSpeaker 1:style prefix when speakers were identified.srtisapplication/x-subrip: one cue per segment.vttistext/vtt: aWEBVTTfile with one cue per segment, using<v Speaker 1>voice tags when speakers were identified.
The status code depends on the format. With format=json the response is always 200, so read status in the body. With a rendered format, a completed transcription returns the rendered body with 200. While the transcription is still queued, fetching or transcribing, you get the JSON object back with 202. A failed or canceled transcription returns its JSON object with 200. Rendered formats are only produced when the transcription is completed.
List transcriptions
GET /v1/transcriptions lists your team's transcriptions, newest first, without transcripts.
| Parameter | Value | Meaning |
|---|---|---|
limit | integer, 1 to 100, default 20 | Page size. |
cursor | string | Pass the next_cursor of the previous page to get the next one. An invalid cursor returns 422 invalid_request. |
status | awaiting_upload, queued, fetching, transcribing, completed, failed or canceled | Only transcriptions with this status. |
platform | youtube or upload | Only transcriptions from this source. |
include_deleted | true or false, default false | Also list deleted transcriptions. They have deleted_at set and no transcript. |
{
"object": "list",
"data": [ { "id": "tr_8fK2Lm0PqRsTuVwXyZaBcD", "object": "transcription", "status": "completed" } ],
"next_cursor": null
}next_cursor is null on the last page. Each item in data is a full transcription object, shortened here.
Cancel or delete a transcription
DELETE /v1/transcriptions/:id returns 204. What it does depends on the status:
- A transcription that is
awaiting_upload,queued,fetchingortranscribingis canceled and any minutes already charged for it are refunded. - A
completed,failedorcanceledtranscription is deleted together with its stored transcript. The record stays and is returned only when you passinclude_deleted=true.
Upload endpoints
Use these three endpoints for chunked uploads. See Uploads for step-by-step instructions.
PUT /v1/transcriptions/:id/upload/chunks/:indexsends one chunk asapplication/octet-stream. It is authenticated by theX-Upload-Tokenheader, not by a bearer credential. It returns{ "object": "upload_chunk", "index": 0, "size": 8388608 }.GET /v1/transcriptions/:id/uploadreturnsreceived_chunks,uploaded_bytes,total_bytes, the plannedchunksandexpires_at, so an interrupted upload can resume.POST /v1/transcriptions/:id/upload/completechecks that every planned chunk arrived, assembles the file and queues the transcription. It returns202with the transcription object, or409withupload_incompleteandmissing_chunks.
Get your account
GET /v1/account returns your plan, usable minutes and limits without charging minutes.
{
"object": "account",
"user": { "id": "5b0e6c1c-0d6f-4c1f-9b5e-8f3f4d0a7a11", "email": "[email protected]" },
"plan": { "id": "9d4e0c0a-2b8a-4f0c-8d63-6a8d3c8a1f22", "name": "Monthly" },
"minutes": {
"remaining": 1180,
"cycle": 980,
"topup": 200,
"topup_usable": true,
"resets_at": "2026-11-13T09:30:00.000Z"
},
"renews_at": "2026-11-13T09:30:00.000Z",
"limits": { "requests_per_minute": 200, "max_active_jobs": 10 }
}plan is null when the team has no plan. See Billing and limits for what each minutes field means.
The transcription object
Every endpoint that returns a transcription uses this shape. POST responses add reused, and the response that reserves a chunked upload adds upload.
{
"id": "tr_8fK2Lm0PqRsTuVwXyZaBcD",
"object": "transcription",
"status": "completed",
"source": { "platform": "youtube", "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "media_id": "dQw4w9WgXcQ" },
"media": { "title": "Example video", "author": "Example channel", "duration_seconds": 212 },
"options": { "source": "auto", "language": "auto", "diarize": false },
"transcript_source": "youtube_captions",
"caption_kind": "auto_generated",
"language": "en",
"billed_minutes": 4,
"cached": false,
"error": null,
"created_at": "2026-10-13T09:30:00.000Z",
"completed_at": "2026-10-13T09:30:04.000Z",
"deleted_at": null,
"transcript": {
"text": "Welcome back to the channel. Today we are looking at how transcripts are made.",
"speakers": [],
"segments": [
{ "start": 0, "end": 4.2, "speaker": null, "language": "en", "text": "Welcome back to the channel." },
{ "start": 4.2, "end": 9.8, "speaker": null, "language": "en", "text": "Today we are looking at how transcripts are made." }
]
}
}| Field | Meaning |
|---|---|
id | The transcription id, starting with tr_. |
status | awaiting_upload, queued, fetching, transcribing, completed, failed or canceled. The last three are final. |
source | { platform, url, media_id } for YouTube, or { "platform": "upload", "filename", "size" } for an uploaded file. |
media | Title, author and duration_seconds for YouTube, or filename, mime_type and size for uploads. null until the media has been read. |
options | The source, language and diarize you asked for. |
transcript_source | youtube_captions or speech_to_text. null until it is known. |
caption_kind | manual or auto_generated when YouTube captions were used, otherwise null. |
language | The detected or selected language, once known. |
billed_minutes | Minutes charged, rounded up from the media duration. null until charged. |
cached | true when the transcript came from an earlier transcription of the same video. It is billed the same. |
error | { "code", "message" } when status is failed, otherwise null. See Errors. |
created_at, completed_at | ISO 8601 UTC timestamps. completed_at is set when the status becomes final. |
deleted_at | ISO 8601 UTC timestamp of the deletion, or null. It is only set when you pass include_deleted=true; deleted transcriptions are hidden otherwise. |
transcript | Present on GET for a completed transcription: text, speakers (empty unless speakers were identified) and segments. |
Segment times are seconds from the start of the media.
Updated October 14, 2026