Tài liệuTài liệu API
Tài liệu API
Tra cứu toàn bộ endpoint /v1, tham số và ví dụ gọi API. Có đặc tả OpenAPI để tải về dưới dạng JSON hoặc YAML.
Tổng quan
https://api.transcript1.com/v1Dùng https://api.transcript1.com/v1 làm URL gốc cho các endpoint bên dưới.
- Gửi và nhận body JSON. Tên trường giữ dạng
snake_case. - Thời điểm dùng chuẩn ISO 8601 theo UTC, chẳng hạn
2026-10-13T09:30:00.000Z. - Thời lượng và các mốc thời gian trong transcript đều tính bằng giây.
- Response lỗi có chung cấu trúc; xem cách đọc lỗi.
- Request đã xác thực luôn nhận hai header
X-RateLimit-LimitvàX-RateLimit-Remainingtrong response. Xem hạn mức request. - Với
source=auto, hệ thống tìm phụ đề phù hợp bằng ngôn ngữ gốc trên YouTube, X, TikTok, Bluesky, Dailymotion và LinkedIn trước; nếu không có thì dùng speech-to-text. Không phải video nào cũng có phụ đề. Chế độcaptions(chỉ phụ đề), đặt bằngsource=captions, không tải audio hay chuyển sang STT; không có track phù hợp thì báono_captions. Chọnsource=stthoặc bật nhận diện người nói sẽ bỏ qua phụ đề. Xem khả năng của từng nguồn để biết giới hạn khi lấy phụ đề và nguồn nào có mốc thời gian theo đoạn hay từng từ.
Bạn có thể tải đặc tả OpenAPI để dùng trong công cụ của mình:
Xác thực
curl https://api.transcript1.com/v1/account \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY"Để xác thực, thêm khóa API hoặc token vào header theo dạng Authorization: Bearer <token>.
- Tạo khóa API ở “API keys”. Khóa có tiền tố
t1_và gọi được mọi endpoint. - Khi bạn kết nối client MCP như Claude hoặc ChatGPT, client nhận OAuth access token có tiền tố
t1o_. Token dùng hai scopetranscriptions:readvàtranscriptions:writedưới đây.
| Scope | Endpoint được phép gọi |
|---|---|
transcriptions:read | GET /v1/transcriptions, GET /v1/transcriptions/:id, GET /v1/transcriptions/:id/upload và GET /v1/account |
transcriptions:write | POST /v1/transcriptions, DELETE /v1/transcriptions/:id và POST /v1/transcriptions/:id/upload/complete |
- Nếu token thiếu scope cho thao tác, API trả
403 insufficient_scope. - Nếu không gửi khóa/token hoặc giá trị không hợp lệ, API trả
401 unauthorized.
Riêng request gửi chunk PUT /v1/transcriptions/:id/upload/chunks/:index, dùng header X-Upload-Token để xác thực. API cấp token này khi tạo phiên tải lên. Xem Tải file lên.
Idempotency
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"}'Kèm Idempotency-Key khi gọi POST /v1/transcriptions để có thể gửi lại request mà không tạo thêm job hay lần tính phí.
Key cần dài từ 1 đến 255 ký tự. Đặt trong header, không đặt vào query.
- Giữ nguyên key và các tham số: API trả lại job ban đầu, không tính thêm phí.
- Giữ key nhưng đổi tham số: API trả
409 idempotency_conflict. - Với file chia thành chunk, gửi lại request tạo phiên bằng cùng key sẽ được cấp token tải lên mới.
Lỗi API
{
"error": {
"code": "insufficient_minutes",
"message": "Not enough minutes",
"retryable": false,
"action_url": "https://transcript1.com/dashboard/billing",
"minutes_needed": 20,
"minutes_remaining": 3
}
}- Nếu API từ chối ngay lệnh gọi, bạn nhận lỗi request.
- Nếu API đã nhận nhưng xử lý không thành công, đó là lỗi job. Job có
statuslàfailed.
Đọc response lỗi
Response lỗi request từ /v1 luôn chứa object error gồm code, message và retryable.
- Dựa vào
codeđể quyết định cách xử lý. - Dùng
messageđể báo cho người dùng, không dùng câu chữ này làm điều kiện trong code vì nội dung có thể thay đổi. - Nếu
retryablelàtrue, request có thể thành công khi thử lại sau.
Tùy mã lỗi, bạn có thể nhận thêm các trường sau bên cạnh retryable:
| Trường | Mã lỗi tương ứng | Cách đọc |
|---|---|---|
action_url | insufficient_minutes | Link mua gói hoặc nạp thêm phút. |
minutes_needed, minutes_remaining | insufficient_minutes | Số phút cần cho request và số phút bạn còn dùng được. minutes_needed là null nếu chưa xác định được thời lượng. |
supported_platforms | unsupported_platform | Danh sách giá trị hợp lệ: ["youtube", "x", "tiktok", "instagram", "facebook", "bluesky", "twitch", "dailymotion", "pinterest", "linkedin", "snapchat"]. |
missing_chunks | upload_incomplete | Index các chunk server chưa nhận được. |
max_bytes | media_too_large | Dung lượng file tối đa tài khoản được gửi, tính bằng byte. |
params | invalid_request | Khi body hoặc query không hợp lệ, object này liệt kê từng trường và lỗi cần sửa. |
Request bị từ chối
| Mã HTTP | code | Có thể thử lại | Nguyên nhân và cách xử lý |
|---|---|---|---|
| 400, 422 | invalid_request | Không | Tham số hoặc trường trong body bị thiếu hay không hợp lệ. Ví dụ: dùng diarize cùng source: "captions", dùng reuse_recent cùng webhook_url, hoặc gửi body JSON sai cú pháp. |
| 422 | invalid_url | Không | Link không đúng dạng hỗ trợ, hoặc platform không khớp với link. Dùng YouTube, X, TikTok, Instagram, Facebook, Bluesky hay nền tảng khác trong danh sách nguồn. |
| 422 | unsupported_platform | Không | platform không được hỗ trợ. |
| 422 | unsupported_media | Không | Đuôi file tải lên không nằm trong danh sách hỗ trợ. |
| 401 | unauthorized | Không | Thiếu khóa hoặc token xác thực, hoặc khóa/token không hợp lệ, đã hết hạn hay bị thu hồi. Token tải lên sai hoặc hết hạn cũng nhận mã này. |
| 403 | insufficient_scope | Không | Token OAuth thiếu quyền transcriptions:read hoặc transcriptions:write cần cho thao tác. |
| 403 | email_not_verified | Không | Cần xác minh email rồi mới tạo job. |
| 402 | insufficient_minutes | Không | Bạn còn 0 phút, hoặc số phút dùng được không đủ cho job. |
| 402 | no_active_plan | Không | Bạn nạp thêm phút khi chưa có gói trả phí còn hiệu lực. Mã này đến từ endpoint thanh toán của bảng điều khiển, không phải endpoint tạo transcript. |
| 404 | not_found | Không | Không tìm thấy job, hoặc job thuộc team khác. |
| 409 | upload_incomplete | Không | Chưa gửi đủ chunk. Gửi phần còn thiếu rồi gọi hoàn tất lần nữa. |
| 409 | invalid_state | Không | Job không còn ở trạng thái chờ tải lên. Không thể gửi chunk hay gọi hoàn tất nữa. |
| 409 | idempotency_conflict | Không | Bạn đã dùng Idempotency-Key này cho bộ tham số khác. |
| 413 | media_too_large | Không | Dung lượng file vượt giới hạn của tài khoản. Xem Tải file lên. |
| 413 | invalid_request | Không | Body JSON vượt 1 MB. Với file quá lớn, mã lỗi là media_too_large. |
| 429 | rate_limited | Có | Vượt số request mỗi phút. Chờ số giây ghi trong Retry-After. |
| 429 | too_many_active_jobs | Có | Đã chạm giới hạn job đang chạy hoặc phiên tải lên chưa hoàn tất. Chờ theo Retry-After. |
| 500 | internal_error | Có | Lỗi phía transcript1. Chờ một lát rồi thử lại. |
| 503 | service_unavailable | Có | transcript1 tạm thời chưa phục vụ được request. Chờ một lát rồi thử lại. |
Với request trình duyệt dùng cookie đăng nhập, API còn kiểm tra origin. Gọi từ website khác sẽ nhận 403 forbidden_origin.
Kiểm tra origin không áp dụng cho lệnh gọi API có header Authorization.
Response 429 luôn có Retry-After cho biết số giây cần chờ. Tra cứu hạn mức cụ thể trong Thanh toán và giới hạn.
Khi nào nên gửi lại request?
- Chỉ tự thử lại nếu
retryablelàtrue:rate_limited,too_many_active_jobs,internal_errorhoặcservice_unavailable. - Có
Retry-Afterthì chờ đúng thời gian đó. Không có thì tăng dần thời gian chờ giữa các lần. - Gửi lại
POST /v1/transcriptionsvới nguyên headerIdempotency-Keyđã dùng. Nếu request đầu đã thành công, bạn sẽ không bị tính phí lần nữa. - Với mã khác, sửa request trước khi gửi lại; không lặp lại nguyên trạng.
Job lỗi trong lúc xử lý
Job có status là failed sẽ chứa object error gồm code và message.
Lỗi có thể xuất hiện sau khi bạn đã nhận response tạo job. Vì vậy, kiểm tra error khi poll trạng thái hoặc nhận webhook transcription.failed.
error.code | Nguyên nhân | Nên làm gì? |
|---|---|---|
media_unavailable | Video không tồn tại hoặc đã không còn truy cập được. | Không thử lại nguyên link; kiểm tra URL. |
media_private | Video đang để riêng tư. | Dùng bài đăng công khai, hoặc video YouTube công khai hay không công khai (unlisted). |
login_required | Phải đăng nhập mới xem được nội dung. | Không thử lại. Đây là lỗi cố định, hệ thống không tự thử lại. |
no_audio | Video không có track audio. | Không thử lại. Đây là lỗi cố định, hệ thống không tự thử lại. |
age_restricted | Video có giới hạn độ tuổi. | Không thử lại bằng link; tải file lên thay thế. |
live_stream | Buổi phát đang trực tiếp hoặc chưa bắt đầu. | Chờ buổi phát kết thúc rồi thử lại. |
no_captions | Bạn chọn source là captions nhưng video không có track phụ đề phù hợp. | Đổi sang source: "auto" hoặc "stt". |
media_too_long | Bản ghi vượt giới hạn 5 giờ của speech-to-text. | Chia nhỏ bản ghi trước khi gửi lại. |
unsupported_media | File không đọc được hoặc thiếu track audio. | Gửi lại bằng định dạng file được hỗ trợ. |
no_speech | Không phát hiện giọng nói. | Không thử lại. |
unsupported_language | Bản ghi dùng ngôn ngữ chưa được hỗ trợ. | Không thử lại nguyên request; đặt language thành mã được hỗ trợ hoặc "auto". |
insufficient_minutes | Đến lúc tính phí cho job, tài khoản không còn đủ phút. | Nạp thêm phút rồi thử lại. |
fetch_failed | Hệ thống đã thử nhiều lần nhưng vẫn không tải được audio hoặc video. | Có thể thử lại sau. |
transcription_failed | Đã thử nhiều lần nhưng speech-to-text vẫn gặp lỗi. | Có thể thử lại sau. |
Nếu job thất bại hoặc bạn hủy, bạn không mất phí. Phút đã trừ cho job đó sẽ được hoàn lại.
Đối tượng 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."
}
]
}
}Các trường
- idstringbắt buộc
- objectstringbắt buộc
Giá trị hợp lệ
transcription - statusstringbắt buộc
Giá trị hợp lệ
awaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled - sourceobjectbắt buộc
Xem trường conẨn trường con
With
url- platformstringbắt buộc
- urlstringbắt buộccho phép null
- media_idstringbắt buộccho phép null
With
filename- platformstringbắt buộc
Giá trị hợp lệ
upload - filenamestringbắt buộccho phép null
- sizenumberbắt buộccho phép null
- mediaobjectbắt buộccho phép null
Xem trường conẨn trường con
- titlestringtùy chọncho phép null
- authorstringtùy chọncho phép null
- author_urlstringtùy chọncho phép null
- thumbnail_urlstringtùy chọncho phép null
- filenamestringtùy chọn
- mime_typestringtùy chọn
- sizenumbertùy chọn
- duration_secondsnumbertùy chọncho phép null
- optionsobjectbắt buộc
Xem trường conẨn trường con
- sourcestringbắt buộc
Giá trị hợp lệ
autocaptionsstt - languagestringbắt buộc
- diarizebooleanbắt buộc
- transcript_sourcestringbắt buộccho phép null
Giá trị hợp lệ
youtube_captionsx_captionsspeech_to_text - caption_kindstringbắt buộccho phép null
Giá trị hợp lệ
manualauto_generated - languagestringbắt buộccho phép null
- billed_minutesintegerbắt buộccho phép null
- cachedbooleanbắt buộc
- errorobjectbắt buộccho phép null
Xem trường conẨn trường con
- codestringbắt buộc
- messagestringbắt buộccho phép null
- created_atstring · date-timebắt buộccho phép null
- completed_atstring · date-timebắt buộccho phép null
- deleted_atstring · date-timebắt buộccho phép null
When the transcription was deleted. Always
nullunless the request includesinclude_deleted=true. - transcriptobjecttùy chọn
Included in
GETresponses for completed transcriptions.Xem trường conẨn trường con
- textstringbắt buộc
- speakersarray of stringsbắt buộc
- segmentsarray of objectsbắt buộc
Xem trường conẨn trường con
- startnumberbắt buộc
- endnumberbắt buộc
- speakerstringbắt buộccho phép null
- languagestringbắt buộccho phép null
- textstringbắt buộc
- wordsarray of objectstùy chọncho phép null
Xem trường conẨn trường con
- startnumberbắt buộc
- endnumberbắt buộc
- textstringbắt buộc
- confidencenumbertùy chọncho phép null
- speakerstringbắt buộccho phép 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
}Query
- waitintegertùy chọncho phép nullMặc định: 0
Seconds to wait for a final status before responding, up to 60. Defaults to 0.
- reuse_recentstringtùy chọnMặc định: 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.Giá trị hợp lệ
truefalse
Headers
- Idempotency-Keystringtùy chọn
Returns the original transcription when you repeat a request with the same key and parameters.
Body
With url
- platformstringtùy chọn
Optional; detected from the link. If supplied, must match the link.
Giá trị hợp lệ
youtubextiktokinstagramfacebookblueskytwitchdailymotionpinterestlinkedinsnapchat - urlstringbắt buộc
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.
- sourcestringtùy chọn
"auto" uses YouTube or X captions when available, otherwise speech-to-text. "captions" is YouTube/X-only. "stt" always uses speech-to-text.
Giá trị hợp lệ
autocaptionsstt - languagestringtùy chọn
- diarizebooleantùy chọn
- webhook_urlstring · uritùy chọn
With upload
- uploadobjectbắt buộc
Xem trường conẨn trường con
- filenamestringbắt buộc
- sizeintegerbắt buộc
- mime_typestringtùy chọn
- sourcestringtùy chọn
Giá trị hợp lệ
autostt - languagestringtùy chọn
- diarizebooleantùy chọn
- webhook_urlstring · uritùy chọn
multipart/form-data
- filestring · binarybắt buộc
- sourcestringtùy chọn
Giá trị hợp lệ
autostt - languagestringtùy chọn
- diarizebooleantùy chọn
- webhook_urlstring · uritùy chọn
Trả về
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
Mã trạng thái khác
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."
}
]
}
}Path
- idstringbắt buộc
Query
- waitintegertùy chọncho phép nullMặc định: 0
Seconds to wait for a final status before responding, up to 60. Defaults to 0.
- formatstringtùy chọnMặc định: json
Giá trị hợp lệ
jsontextsrtvtt - includestringtùy chọn
Giá trị hợp lệ
words - timestampsstringtùy chọnMặc định: false
Giá trị hợp lệ
truefalse - include_deletedstringtùy chọnMặc định: false
Also returns deleted transcriptions as read-only records without a transcript. Their
deleted_atis set. Defaults tofalse.Giá trị hợp lệ
truefalse
Trả về
200 OK— The transcription, or the rendered transcript202 Accepted— A rendered format was requested while the transcription is still processing
Mã trạng thái khác
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"
}Query
- limitintegertùy chọnMặc định: 20
- cursorstringtùy chọn
- statusstringtùy chọn
Giá trị hợp lệ
awaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled - platformstringtùy chọn
- include_deletedstringtùy chọnMặc định: false
Also returns deleted transcriptions as read-only records without a transcript. Their
deleted_atis set. Defaults tofalse.Giá trị hợp lệ
truefalse
Trả về
200 OK— A page of transcriptions
Mã trạng thái khác
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"Không có nội dung response
Path
- idstringbắt buộc
Trả về
204 No Content— Canceled or deleted
Mã trạng thái khác
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
}Path
- idstringbắt buộc
- indexintegertùy chọncho phép null
Zero-based chunk number from the upload plan
Headers
- X-Upload-Tokenstringbắt buộc
Body
- (raw body)string · binarybắt buộc
Trả về
200 OK— The chunk was stored
Mã trạng thái khác
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"
}Path
- idstringbắt buộc
Trả về
200 OK— Upload progress
Mã trạng thái khác
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
}Path
- idstringbắt buộc
Trả về
202 Accepted— The transcription is queued
Mã trạng thái khác
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
}
}Trả về
200 OK— The authenticated user's account
Mã trạng thái khác
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.
Đối tượng 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
}
}Các trường
- objectstringbắt buộc
Giá trị hợp lệ
account - userobjectbắt buộc
Xem trường conẨn trường con
- idstringbắt buộc
- emailstringbắt buộc
- planobjectbắt buộccho phép null
Xem trường conẨn trường con
- idstringbắt buộc
- namestringbắt buộc
- minutesobjectbắt buộc
Xem trường conẨn trường con
- remainingnumberbắt buộc
- cyclenumberbắt buộc
- topupnumberbắt buộc
- topup_usablebooleanbắt buộc
- resets_atstring · date-timebắt buộccho phép null
- renews_atstring · date-timebắt buộccho phép null
- limitsobjectbắt buộc
Xem trường conẨn trường con
- requests_per_minutenumberbắt buộc
- max_active_jobsnumberbắt buộc
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
}
}Thêm webhook_url khi tạo job để nhận thông báo tại URL của bạn. transcript1 gửi request POST có chữ ký khi job hoàn tất hoặc thất bại.
Bạn chỉ dùng được webhook qua REST API. Các tool của MCP server không nhận tham số webhook.
Khai báo URL nhận webhook
Vị trí đặt webhook_url trong POST /v1/transcriptions tùy cách gửi:
- Gửi link video hoặc tạo phiên tải lên theo chunk: đặt trong body JSON.
- Gửi file bằng một request: đặt trong trường form.
Chọn URL đáp ứng đủ các điều kiện sau:
- Có giao thức HTTPS.
- Không kèm tên đăng nhập hoặc mật khẩu.
- Phân giải ra địa chỉ IP công khai.
Địa chỉ private, loopback, link-local hoặc địa chỉ không công khai khác sẽ nhận 422 invalid_request. transcript1 kiểm tra địa chỉ lúc tạo job và trước mỗi lần gửi webhook.
Không gửi webhook_url cùng reuse_recent=true.
Khi nào nhận được webhook?
type | Điều kiện gửi |
|---|---|
transcription.completed | Job chuyển sang completed. |
transcription.failed | Job chuyển sang failed. Đọc code và message trong data.error để biết lỗi. |
Nếu job bị hủy, transcript1 không gửi webhook.
Nội dung request
Trong body JSON nhận được:
- Đọc
created_atđể biết thời điểm tạo sự kiện. datachứa object transcription, không kèm trườngtranscript.
Lấy id từ data, rồi gọi GET /v1/transcriptions/:id để đọc transcript.
Các header đi kèm gồm:
Content-Type: application/jsonUser-Agent: transcript1-webhooks/1.0X-Transcript1-Signatuređể kiểm tra chữ ký theo hướng dẫn dưới đây.
Kiểm tra chữ ký webhook
Mỗi request có header X-Transcript1-Signature theo dạng t=<unix seconds>,v1=<hex digest>.
tghi thời điểm ký request theo Unix time, tính bằng giây.- Để tính
v1, ghép giá trịt, dấu chấm và body nguyên gốc thành chuỗi"<t>.<raw body>". Tính HMAC-SHA256 bằng toàn bộ secret ký webhook, giữ cả tiền tốwhsec_, rồi chuyển digest sang hex.
Kiểm tra chữ ký trên đúng các byte body nhận được trước khi parse JSON. Parse rồi serialize lại có thể đổi khoảng trắng hoặc thứ tự key, khiến chữ ký không khớp.
- Dùng hàm so sánh constant-time.
- Kiểm tra
tvà từ chối request quá lệch so với giờ hiện tại. Các ví dụ chấp nhận độ lệch tối đa 5 phút. - Nếu dùng Express, đọc body dưới dạng raw text; không parse JSON trước bước kiểm tra.
- Nếu dùng Flask, lấy body bằng
request.get_data(as_text=True)và truyền vàoraw_body.
Secret dùng để ký webhook
Mỗi team có một secret bắt đầu bằng whsec_, dùng chung để ký webhook cho mọi job của team.
Bạn có thể xem hoặc đổi secret ở “Webhooks”.
Đổi secret có hiệu lực ngay. Mọi webhook gửi từ thời điểm đó đều được ký bằng secret mới.
Gửi lại và xử lý trùng lặp
- Trả mã
2xxđể xác nhận đã nhận webhook. - Mã khác, lỗi kết nối hoặc không phản hồi trong 10 giây đều tính là gửi thất bại.
- Nếu gửi thất bại, transcript1 thử lại với thời gian chờ tăng theo cấp số nhân, tối đa 6 lần tính cả lần đầu. Các khoảng chờ là 2, 4, 8, 16 và 32 phút; lần cuối cách lần đầu khoảng một giờ.
- Cung cấp URL đích cuối cùng. transcript1 không theo redirect, nên response
3xxvẫn tính là thất bại. - Cùng sự kiện có thể đến nhiều lần, chẳng hạn khi server trả lời sau timeout. Dùng cặp
data.idvàtypeđể nhận ra và bỏ qua bản trùng.