文档API接口参考
API接口参考
查阅所有/v1接口的参数和调用示例,或下载JSON、YAML格式的OpenAPI规范。
概览
https://api.transcript1.com/v1API统一使用https://api.transcript1.com/v1作为基础地址。
- 请求体和响应体采用JSON,字段名采用
snake_case。 - 时间戳统一为UTC,按ISO 8601格式返回,例如
2026-10-13T09:30:00.000Z。 - 音视频时长、转录文本中的时间都以秒计。
- 错误响应的结构一致,处理方法见错误说明。
- 通过认证的请求,响应头都会包含
X-RateLimit-Limit和X-RateLimit-Remaining。各套餐的请求上限见计费规则与用量限制。 - 设置
source=auto时,优先提取YouTube、X、TikTok、Bluesky、Dailymotion和LinkedIn上与视频原语言一致的可用字幕,没有可用字幕时再转录音频。并不是每个视频都有字幕。source=captions使用captions(仅字幕)模式,不会下载音频,也不会改用语音转文字;找不到可用字幕轨道就返回no_captions。设置source=stt或开启说话人分离时,会跳过字幕。各平台的获取限制,以及分段和逐词时间戳的支持情况,见来源支持表。
需要供程序读取的接口定义,可下载OpenAPI规范:
身份验证
curl https://api.transcript1.com/v1/account \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY"调用API时,用Authorization请求头提供凭据,格式为Authorization: Bearer <token>。
- API密钥以
t1_开头,可调用所有接口。在“API keys”页面创建即可。 - OAuth访问Token以
t1o_开头。连接Claude、ChatGPT等MCP客户端时,客户端会取得该Token,权限范围为transcriptions:read和transcriptions:write。
| 权限范围 | 可调用的接口 |
|---|---|
transcriptions:read | GET /v1/transcriptions、GET /v1/transcriptions/:id、GET /v1/transcriptions/:id/upload和GET /v1/account |
transcriptions:write | POST /v1/transcriptions、DELETE /v1/transcriptions/:id和POST /v1/transcriptions/:id/upload/complete |
- Token没有接口所需的权限时,返回
403 insufficient_scope。 - 没有提供凭据,或凭据无效时,返回
401 unauthorized。
上传分块的PUT /v1/transcriptions/:id/upload/chunks/:index接口使用X-Upload-Token认证,Token在创建上传时返回。具体流程见文件上传。
幂等性
curl -X POST https://api.transcript1.com/v1/transcriptions \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY" \
-H "Idempotency-Key: 5f1c2b0e-8d4a-4c3e-9b7a-2e6f1d0c9a8b" \
-H "Content-Type: application/json" \
-d '{"url":"https://www.youtube.com/watch?v=dQw4w9WgXcQ"}'重试POST /v1/transcriptions时,带上Idempotency-Key请求头,避免重复创建和扣费。
该值需为1到255个字符,只能放在请求头中,不能作为查询参数传入。
- 重试时保持键值和参数不变,API就会返回原来的转录,不再扣费。
- 沿用同一个键值却修改参数,会返回
409 idempotency_conflict。 - 创建分块上传时,用同一个键值重发创建请求,会获得新的上传Token。
错误
{
"error": {
"code": "insufficient_minutes",
"message": "Not enough minutes",
"retryable": false,
"action_url": "https://transcript1.com/dashboard/billing",
"minutes_needed": 20,
"minutes_remaining": 3
}
}- 请求错误:这次调用没有通过API校验或未被接受。
- 任务失败:API已经接受转录,但后续处理没有成功,任务的
status变为failed。
读取错误响应
/v1接口拒绝请求时,会在error对象中返回code、message和retryable:
- 用
code判断错误类型并编写处理逻辑。 message供用户阅读,不要依赖其中的具体措辞,文案可能调整。retryable为true时,可以稍后重试,同样的请求有可能成功。
部分错误还会在同一层级附上其他字段:
| 字段 | 对应错误码 | 说明 |
|---|---|---|
action_url | insufficient_minutes | 打开后可购买套餐或充值。 |
minutes_needed、minutes_remaining | insufficient_minutes | 分别为本次请求需要的分钟数和当前余额;所需分钟数尚未确定时为null。 |
supported_platforms | unsupported_platform | 支持的平台值列表:["youtube", "x", "tiktok", "instagram", "facebook", "bluesky", "twitch", "dailymotion", "pinterest", "linkedin", "snapchat"]。 |
missing_chunks | upload_incomplete | 服务端尚未收到的分块索引。 |
max_bytes | media_too_large | 当前允许上传的文件大小上限,单位为字节。 |
params | invalid_request | 按字段列出请求体或查询参数的校验问题。对象中的字段名对应具体错误说明。 |
请求被拒绝时的错误码
| HTTP状态码 | code | 可否重试 | 原因和处理方法 |
|---|---|---|---|
| 400、422 | invalid_request | 否 | 参数或请求体字段缺失、值无效,或选项不能组合使用,例如diarize与source: "captions",以及reuse_recent与webhook_url。请求体不是合法JSON时,也返回此错误。 |
| 422 | invalid_url | 否 | 链接需来自YouTube、X、TikTok、Instagram、Facebook、Bluesky,或来源与选项列出的其他平台。指定的platform与链接不符时,也返回此错误。 |
| 422 | unsupported_platform | 否 | platform的值不在支持范围内。 |
| 422 | unsupported_media | 否 | 文件扩展名不在支持范围内。 |
| 401 | unauthorized | 否 | 没有提供凭据,或凭据无效、过期、已撤销;上传Token无效或过期时也会出现。 |
| 403 | insufficient_scope | 否 | OAuth Token没有所需的transcriptions:read或transcriptions:write权限。 |
| 403 | email_not_verified | 否 | 邮箱还未验证,先完成验证再创建转录。 |
| 402 | insufficient_minutes | 否 | 可用分钟数为0,或不足以支付本次转录。 |
| 402 | no_active_plan | 否 | 没有有效的付费套餐,却尝试充值。此错误只由控制台的计费接口返回,转录接口不会返回。 |
| 404 | not_found | 否 | 找不到该转录,或转录属于其他团队。 |
| 409 | upload_incomplete | 否 | 还有分块未上传。补传后,再调用完成上传接口。 |
| 409 | invalid_state | 否 | 任务已不在等待上传的状态,不能继续发送分块,也不能再完成上传。 |
| 409 | idempotency_conflict | 否 | 这个Idempotency-Key已被使用,但本次参数与之前不同。 |
| 413 | media_too_large | 否 | 文件大小超过当前上限,具体限制见文件上传。 |
| 413 | invalid_request | 否 | JSON请求体超过1MB。文件过大时返回的则是media_too_large。 |
| 429 | rate_limited | 是 | 本分钟请求次数已超限,按Retry-After给出的秒数等待后再试。 |
| 429 | too_many_active_jobs | 是 | 活跃转录任务或未完成的上传数量已达上限,按Retry-After给出的秒数等待后再试。 |
| 500 | internal_error | 是 | 服务端发生错误,稍后重试。 |
| 503 | service_unavailable | 是 | transcript1暂时无法提供服务,稍后重试。 |
浏览器使用登录Cookie认证时,还必须通过来源检查。请求来自其他网站时,返回403 forbidden_origin。
通过Authorization请求头认证的API调用,不受这项来源检查影响。
所有429响应都会带上Retry-After响应头,告诉调用方需要等待多少秒。各项上限见计费规则与用量限制。
什么时候应该重试
- 只自动重试
retryable为true的错误:rate_limited、too_many_active_jobs、internal_error和service_unavailable。 - 响应包含
Retry-After时,按它指定的秒数等待;没有时,逐步增加重试间隔。 - 重试
POST /v1/transcriptions必须沿用原来的Idempotency-Key请求头。即使首个请求其实已经成功,也不会重复扣费。 - 遇到其他错误码,先修正请求,再重新提交。
请求成功后任务仍可能失败
转录任务变为failed后,返回的error对象会包含code和message。
请求返回不代表转录已经成功,后续处理仍可能失败。轮询任务或收到transcription.failedWebhook时,都应检查error。
error.code | 失败原因 | 是否重试及处理方法 |
|---|---|---|
media_unavailable | 视频不存在,或现在已经无法访问。 | 不要直接重试,先检查URL。 |
media_private | 视频设为私有。 | 不要直接重试,改用公开帖子;YouTube还可使用不公开但能凭链接访问的视频。 |
login_required | 平台要求登录后才能访问。 | 不重试,这是永久性失败。 |
no_audio | 视频没有音轨。 | 不重试,这是永久性失败。 |
age_restricted | 视频受到年龄限制。 | 不要直接重试,改为上传文件。 |
live_stream | 视频正在直播,或直播还没开始。 | 等直播结束后再提交。 |
no_captions | 选择了source为captions,但视频没有可用字幕轨道。 | 改用source: "auto"或"stt"。 |
media_too_long | 语音转文字支持的音视频时长上限为5小时。 | 不要直接重试,先拆分音视频。 |
unsupported_media | 无法读取文件,或文件没有音轨。 | 不要直接重试,换成支持的文件格式。 |
no_speech | 未检测到语音。 | 不重试。 |
unsupported_language | 音视频使用的语言不受支持。 | 不要直接重试,将language改为受支持的语言代码或"auto"。 |
insufficient_minutes | 结算本次转录前,分钟余额已用完。 | 充值后可以重试。 |
fetch_failed | 重试多次后,仍未能获取音视频。 | 可以稍后重试。 |
transcription_failed | 重试多次后,语音转文字仍未成功。 | 可以稍后重试。 |
如果转录失败或被取消,不会扣费;已经扣除的分钟数会退还。
Transcription对象
{
"id": "tr_4fHq8ZbN2xLm0PqRsTuVwX",
"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",
"author_url": "https://www.youtube.com/@examplechannel",
"thumbnail_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
"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."
}
]
}
}字段
- idstring必填
- objectstring必填
可选值
transcription - statusstring必填
可选值
awaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled - sourceobject必填
展开子字段收起子字段
With
url- platformstring必填
- urlstring必填允许为null
- media_idstring必填允许为null
With
filename- platformstring必填
可选值
upload - filenamestring必填允许为null
- sizenumber必填允许为null
- mediaobject必填允许为null
展开子字段收起子字段
- titlestring可选允许为null
- authorstring可选允许为null
- author_urlstring可选允许为null
- thumbnail_urlstring可选允许为null
- filenamestring可选
- mime_typestring可选
- sizenumber可选
- duration_secondsnumber可选允许为null
- optionsobject必填
展开子字段收起子字段
- sourcestring必填
可选值
autocaptionsstt - languagestring必填
- diarizeboolean必填
- transcript_sourcestring必填允许为null
可选值
youtube_captionsx_captionsspeech_to_text - caption_kindstring必填允许为null
可选值
manualauto_generated - languagestring必填允许为null
- billed_minutesinteger必填允许为null
- cachedboolean必填
- errorobject必填允许为null
展开子字段收起子字段
- codestring必填
- messagestring必填允许为null
- created_atstring · date-time必填允许为null
- completed_atstring · date-time必填允许为null
- deleted_atstring · date-time必填允许为null
When the transcription was deleted. Always
nullunless the request includesinclude_deleted=true. - transcriptobject可选
Included in
GETresponses for completed transcriptions.展开子字段收起子字段
- textstring必填
- speakersarray of strings必填
- segmentsarray of objects必填
展开子字段收起子字段
- startnumber必填
- endnumber必填
- speakerstring必填允许为null
- languagestring必填允许为null
- textstring必填
- wordsarray of objects可选允许为null
展开子字段收起子字段
- startnumber必填
- endnumber必填
- textstring必填
- confidencenumber可选允许为null
- speakerstring必填允许为null
Transcriptions
Create, read, list and delete transcriptions of video links and uploaded files.
Create a transcription
POST /v1/transcriptionsTranscribes an uploaded file or a YouTube, X, TikTok, Instagram, Facebook, Bluesky, Twitch, Dailymotion, Pinterest, LinkedIn, Snapchat link. Social posts must be public; only the first video is used.
Twitch accepts clips and completed VODs; Pinterest accepts native video pins; LinkedIn accepts public video posts; Snapchat accepts Spotlight. New platforms require public recorded native media without supplied account cookies; no live streams or external embeds.
platform is optional and detected from the link. Captions are YouTube/X-only. All sources use the same per-minute price.
Returns 200 for a final result, 201 when awaiting an upload and 202 while processing. Pass wait to wait up to 60 seconds for a final status.
Pass reuse_recent=true with a platform URL to reuse a transcription of the same video and options from the last 24 hours. The response includes reused: true, with no additional charge. Short links may not be matched. An Idempotency-Key replay takes precedence.
curl -X POST https://api.transcript1.com/v1/transcriptions \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://www.youtube.com/watch?v=dQw4w9WgXcQ"}'{
"id": "tr_4fHq8ZbN2xLm0PqRsTuVwX",
"object": "transcription",
"status": "queued",
"source": {
"platform": "youtube",
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"media_id": "dQw4w9WgXcQ"
},
"media": null,
"options": {
"source": "auto",
"language": "auto",
"diarize": false
},
"transcript_source": null,
"caption_kind": null,
"language": null,
"billed_minutes": null,
"cached": false,
"error": null,
"created_at": "2026-10-13T09:30:00.000Z",
"completed_at": null,
"deleted_at": null,
"reused": false
}查询参数
- waitinteger可选允许为null默认值:0
Seconds to wait for a final status before responding, up to 60. Defaults to 0.
- reuse_recentstring可选默认值:false
For platform URLs only. Cannot be combined with
webhook_url. Returns the team's most recent transcription of the same video with the samesource,languageanddiarize. It must have been created in the last 24 hours and must not befailedorcanceled. Reuses that transcription without creating or charging for a new one.可选值
truefalse
请求头
- Idempotency-Keystring可选
Returns the original transcription when you repeat a request with the same key and parameters.
请求体
With url
- platformstring可选
Optional; detected from the link. If supplied, must match the link.
可选值
youtubextiktokinstagramfacebookblueskytwitchdailymotionpinterestlinkedinsnapchat - urlstring必填
YouTube, X, TikTok, Instagram, Facebook, Bluesky, Twitch, Dailymotion, Pinterest, LinkedIn, Snapchat video link. Social posts must be public; only the first video is used. New platforms support public recorded native video without supplied account cookies, not live streams or external embeds.
- sourcestring可选
"auto" uses YouTube or X captions when available, otherwise speech-to-text. "captions" is YouTube/X-only. "stt" always uses speech-to-text.
可选值
autocaptionsstt - languagestring可选
- diarizeboolean可选
- webhook_urlstring · uri可选
With upload
- uploadobject必填
展开子字段收起子字段
- filenamestring必填
- sizeinteger必填
- mime_typestring可选
- sourcestring可选
可选值
autostt - languagestring可选
- diarizeboolean可选
- webhook_urlstring · uri可选
multipart/form-data
- filestring · binary必填
- sourcestring可选
可选值
autostt - languagestring可选
- diarizeboolean可选
- webhook_urlstring · uri可选
返回内容
200 OK— The transcription reached a final status201 Created— The transcription is awaiting a chunked upload.uploaddescribes where to send each chunk.202 Accepted— The transcription is processing
其他响应状态
400 Bad Request— The JSON request body is malformed401 Unauthorized— Missing or invalid credential402 Payment Required— Not enough minutes. Applies to every request body format.403 Forbidden— Insufficient scope, unverified email, cross-site request or a single-member team plan409 Conflict—Idempotency-Keywas reused with different parameters.413 Content Too Large— The upload or the JSON request body is too large422 Unprocessable Content— Invalid request, URL, platform or file type429 Too Many Requests— Too many requests or too many active transcriptions. Wait for the number of seconds inRetry-After.
Get a transcription
GET /v1/transcriptions/{id}Returns the transcription object. Completed transcriptions include the transcript. Use format to render it as text, SRT or WebVTT.
If you request a rendered format before completion, the response is JSON. It returns 202 while processing or 200 if the transcription failed or was canceled.
With include_deleted=true, a deleted transcription is returned as a record without a transcript. For deleted records, wait is ignored and rendered formats return 404.
curl https://api.transcript1.com/v1/transcriptions/tr_4fHq8ZbN2xLm0PqRsTuVwX \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY"{
"id": "tr_4fHq8ZbN2xLm0PqRsTuVwX",
"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",
"author_url": "https://www.youtube.com/@examplechannel",
"thumbnail_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
"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."
}
]
}
}路径参数
- idstring必填
查询参数
- waitinteger可选允许为null默认值:0
Seconds to wait for a final status before responding, up to 60. Defaults to 0.
- formatstring可选默认值:json
可选值
jsontextsrtvtt - includestring可选
可选值
words - timestampsstring可选默认值:false
可选值
truefalse - include_deletedstring可选默认值:false
Also returns deleted transcriptions as read-only records without a transcript. Their
deleted_atis set. Defaults tofalse.可选值
truefalse
返回内容
200 OK— The transcription, or the rendered transcript202 Accepted— A rendered format was requested while the transcription is still processing
其他响应状态
401 Unauthorized— Missing or invalid credential403 Forbidden— Insufficient scope or a single-member team plan404 Not Found— Transcription not found422 Unprocessable Content— Invalid query parameters429 Too Many Requests— Too many requests. Wait for the number of seconds inRetry-After.
List transcriptions
GET /v1/transcriptionsLists your team's transcriptions, newest first, without transcripts. Pass next_cursor as cursor to get the next page.
Deleted transcriptions are hidden unless you pass include_deleted=true.
curl https://api.transcript1.com/v1/transcriptions \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY"{
"object": "list",
"data": [
{
"id": "tr_4fHq8ZbN2xLm0PqRsTuVwX",
"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",
"author_url": "https://www.youtube.com/@examplechannel",
"thumbnail_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
"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
}
],
"next_cursor": "eyJjcmVhdGVkQXQiOiIyMDI2LTEwLTEzVDA5OjMwOjAwLjAwMFoiLCJpZCI6IjViMGU2YzFjLTBkNmYtNGMxZi05YjVlLThmM2Y0ZDBhN2ExMSJ9"
}查询参数
- limitinteger可选默认值:20
- cursorstring可选
- statusstring可选
可选值
awaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled - platformstring可选
- include_deletedstring可选默认值:false
Also returns deleted transcriptions as read-only records without a transcript. Their
deleted_atis set. Defaults tofalse.可选值
truefalse
返回内容
200 OK— A page of transcriptions
其他响应状态
401 Unauthorized— Missing or invalid credential403 Forbidden— Insufficient scope or a single-member team plan422 Unprocessable Content— Invalid query parameters or cursor429 Too Many Requests— Too many requests. Wait for the number of seconds inRetry-After.
Cancel or delete a transcription
DELETE /v1/transcriptions/{id}Cancels an active transcription or one awaiting an upload. Any charged minutes are refunded.
Deletes a completed, failed or canceled transcription together with its stored transcript.
curl -X DELETE https://api.transcript1.com/v1/transcriptions/tr_4fHq8ZbN2xLm0PqRsTuVwX \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY"不返回响应体
路径参数
- idstring必填
返回内容
204 No Content— Canceled or deleted
其他响应状态
401 Unauthorized— Missing or invalid credential403 Forbidden— Insufficient scope, cross-site request or a single-member team plan404 Not Found— Transcription not found429 Too Many Requests— Too many requests. Wait for the number of seconds inRetry-After.
Uploads
Send a large file in chunks. Start with Create a transcription using an upload body. Send each chunk, then complete the upload.
Upload one chunk
PUT /v1/transcriptions/{id}/upload/chunks/{index}Sends one chunk of a chunked upload as application/octet-stream.
Authenticate with the X-Upload-Token from the create response. This endpoint does not use a bearer credential.
The body must match the planned chunk size exactly. Sending a chunk again replaces it.
curl -X PUT https://api.transcript1.com/v1/transcriptions/tr_4fHq8ZbN2xLm0PqRsTuVwX/upload/chunks/0 \
-H "X-Upload-Token: t1u_Zk3vYb8Nw1ZrT5xLpD0aHcE7sUj9GfMiO2yXtVnR4Bw" \
-H "Content-Type: application/octet-stream" \
--data-binary @chunk-0.bin{
"object": "upload_chunk",
"index": 0,
"size": 838860
}路径参数
- idstring必填
- indexinteger可选允许为null
Zero-based chunk number from the upload plan
请求头
- X-Upload-Tokenstring必填
请求体
- (原始请求体)string · binary必填
返回内容
200 OK— The chunk was stored
其他响应状态
401 Unauthorized— Missing, invalid or expired upload token404 Not Found— Transcription not found409 Conflict— The transcription is no longer awaiting an upload422 Unprocessable Content— Index outside the chunk plan or wrong body size
Get upload progress
GET /v1/transcriptions/{id}/uploadLists the received chunks of a chunked upload so an interrupted upload can resume.
curl https://api.transcript1.com/v1/transcriptions/tr_4fHq8ZbN2xLm0PqRsTuVwX/upload \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY"{
"object": "upload",
"status": "awaiting_upload",
"total_bytes": 48210334,
"uploaded_bytes": 4194300,
"received_chunks": [
0,
1,
2,
3,
4
],
"chunks": [
{
"index": 0,
"offset": 0,
"size": 838860
},
{
"index": 1,
"offset": 838860,
"size": 838860
},
{
"index": 2,
"offset": 1677720,
"size": 838860
},
{
"index": 3,
"offset": 2516580,
"size": 838860
},
{
"index": 4,
"offset": 3355440,
"size": 838860
},
{
"index": 5,
"offset": 4194300,
"size": 8388608
},
{
"index": 6,
"offset": 12582908,
"size": 8388608
},
{
"index": 7,
"offset": 20971516,
"size": 8388608
},
{
"index": 8,
"offset": 29360124,
"size": 8388608
},
{
"index": 9,
"offset": 37748732,
"size": 8388608
},
{
"index": 10,
"offset": 46137340,
"size": 2072994
}
],
"expires_at": "2026-10-13T10:30:00.000Z"
}路径参数
- idstring必填
返回内容
200 OK— Upload progress
其他响应状态
401 Unauthorized— Missing or invalid credential403 Forbidden— Insufficient scope or a single-member team plan404 Not Found— Transcription or upload not found429 Too Many Requests— Too many requests. Wait for the number of seconds inRetry-After.
Complete a chunked upload
POST /v1/transcriptions/{id}/upload/completeChecks that every planned chunk arrived with the planned size. Then assembles the file and queues the transcription.
curl -X POST https://api.transcript1.com/v1/transcriptions/tr_4fHq8ZbN2xLm0PqRsTuVwX/upload/complete \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY"{
"id": "tr_4fHq8ZbN2xLm0PqRsTuVwX",
"object": "transcription",
"status": "queued",
"source": {
"platform": "upload",
"filename": "interview.m4a",
"size": 48210334
},
"media": {
"filename": "interview.m4a",
"mime_type": "audio/mp4",
"size": 48210334
},
"options": {
"source": "auto",
"language": "auto",
"diarize": false
},
"transcript_source": null,
"caption_kind": null,
"language": null,
"billed_minutes": null,
"cached": false,
"error": null,
"created_at": "2026-10-13T09:30:00.000Z",
"completed_at": null,
"deleted_at": null
}路径参数
- idstring必填
返回内容
202 Accepted— The transcription is queued
其他响应状态
401 Unauthorized— Missing or invalid credential402 Payment Required— Not enough minutes to queue the transcription. The upload stays awaiting completion.403 Forbidden— Insufficient scope, cross-site request or a single-member team plan404 Not Found— Transcription or upload not found409 Conflict—upload_incompletemeans chunks are missing.missing_chunkslists them.invalid_statemeans the transcription is not awaiting an upload.429 Too Many Requests— Too many requests or too many active transcriptions. Wait for the number of seconds inRetry-After.
Account
Your plan, remaining minutes and rate limits.
Get your account
GET /v1/accountReturns the authenticated user, current plan and remaining transcription minutes.
curl https://api.transcript1.com/v1/account \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY"{
"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
}
}返回内容
200 OK— The authenticated user's account
其他响应状态
401 Unauthorized— Missing or invalid credential403 Forbidden— Insufficient scope or a single-member team plan404 Not Found— No account found429 Too Many Requests— Too many requests. Wait for the number of seconds inRetry-After.
Account对象
{
"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
}
}字段
- objectstring必填
可选值
account - userobject必填
展开子字段收起子字段
- idstring必填
- emailstring必填
- planobject必填允许为null
展开子字段收起子字段
- idstring必填
- namestring必填
- minutesobject必填
展开子字段收起子字段
- remainingnumber必填
- cyclenumber必填
- topupnumber必填
- topup_usableboolean必填
- resets_atstring · date-time必填允许为null
- renews_atstring · date-time必填允许为null
- limitsobject必填
展开子字段收起子字段
- requests_per_minutenumber必填
- max_active_jobsnumber必填
Webhook
import { Buffer } from 'node:buffer';
import crypto from 'node:crypto';
// header: X-Transcript1-Signature, rawBody: the request body exactly as received,
// secret: your full signing secret including the whsec_ prefix.
export const verifySignature = (secret, header, rawBody, nowSeconds = Math.floor(Date.now() / 1000)) => {
const fields = Object.fromEntries(header.split(',').map(part => part.trim().split('=')));
const t = Number(fields.t);
if (!Number.isInteger(t) || !fields.v1 || Math.abs(nowSeconds - t) > 300) {
return false;
}
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
return fields.v1.length === expected.length
&& crypto.timingSafeEqual(Buffer.from(fields.v1), Buffer.from(expected));
};{
"type": "transcription.completed",
"created_at": "2026-10-13T09:30:04.000Z",
"data": {
"id": "tr_8fK2Lm0PqRsTuVwXyZaBcD",
"object": "transcription",
"status": "completed",
"transcript_source": "youtube_captions",
"billed_minutes": 4,
"error": null
}
}创建转录时指定webhook_url,就能在转录完成或失败时收到通知。transcript1会向该地址发送带签名的POST请求。
只有REST API支持Webhook,MCP服务器不提供Webhook参数。
配置接收通知的地址
调用POST /v1/transcriptions时,按上传方式传入webhook_url:
- 提交受支持的视频链接或创建分块上传时,放进JSON请求体。
- 用单次请求上传文件时,放进表单字段。
接收地址需满足以下条件:
- 使用HTTPS协议。
- URL中不能包含用户名或密码。
- 解析后的地址必须是公网地址。
私有地址、环回地址、链路本地地址以及其他非公网地址,都会导致422 invalid_request。创建转录时会检查地址,每次发送通知前也会重新检查。
不要同时设置webhook_url和reuse_recent=true,两者不能合用。
哪些状态会触发通知
type | 触发条件 |
|---|---|
transcription.completed | 转录状态变为completed。 |
transcription.failed | 转录状态变为failed,错误码code和错误说明message在data.error中返回。 |
取消转录不会触发Webhook。
通知中包含什么
Webhook请求体采用JSON:
created_at记录事件的创建时间。data包含转录对象,但不含transcript字段。
收到通知后,从data中取出id,再调用GET /v1/transcriptions/:id获取转录文本。
每次请求还会携带以下请求头:
Content-Type: application/jsonUser-Agent: transcript1-webhooks/1.0X-Transcript1-Signature,用于下文的签名校验。
校验通知签名
每次通知的X-Transcript1-Signature请求头都采用t=<unix seconds>,v1=<hex digest>格式:
t表示签名时的Unix时间戳,单位为秒。v1是用HMAC-SHA256计算后转成十六进制的签名。待签名内容为"<t>.<raw body>":将t的值、英文句点和原始请求体依次拼接。计算时使用完整的签名密钥,包括whsec_前缀。
务必先用收到的原始请求体字节校验签名,再解析JSON。不要先解析再序列化:空白字符或字段顺序一旦改变,签名就无法匹配。
- 比较签名时使用恒定时间比较。
- 检查
t与当前时间的差值,超出允许范围就拒绝请求。示例允许相差5分钟。 - Express中要读取请求体原文,不要先交给JSON解析器。
- Flask中用
request.get_data(as_text=True)读取,再作为raw_body传入。
管理团队签名密钥
签名密钥属于团队,以whsec_开头。团队创建的所有转录,都使用这份密钥签署Webhook。
到“Webhooks”页面可以查看或轮换密钥。
轮换后旧密钥立即被替换,之后发送的Webhook全部使用新密钥。
发送失败后如何重试
- 返回任意
2xx状态码,就视为接收成功。 - 返回其他状态码、连接出错,或超过10秒还未响应,都算本次发送失败。
- 失败后按指数退避重试,总共最多尝试6次。重试前分别等待2、4、8、16和32分钟,最后1次大约在首次发送的1小时后。
- 请直接填写最终URL。transcript1不会跟随重定向,收到
3xx同样算发送失败。 - 同一条通知可能重复送达,例如服务器超过超时时间才响应。请按
data.id和type识别并忽略重复通知。