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

Base URL
https://api.transcript1.com/v1

Dù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-Limit và X-RateLimit-Remaining trong 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ằng source=captions, không tải audio hay chuyển sang STT; không có track phù hợp thì báo no_captions. Chọn source=stt hoặ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 scope transcriptions:read và transcriptions:write dưới đây.
ScopeEndpoint được phép gọi
transcriptions:readGET /v1/transcriptions, GET /v1/transcriptions/:id, GET /v1/transcriptions/:id/upload và GET /v1/account
transcriptions:writePOST /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

402 Payment Required
{
  "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ó status là 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 retryable là 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ườngMã lỗi tương ứngCách đọc
action_urlinsufficient_minutesLink mua gói hoặc nạp thêm phút.
minutes_needed, minutes_remaininginsufficient_minutesSố 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_platformsunsupported_platformDanh sách giá trị hợp lệ: ["youtube", "x", "tiktok", "instagram", "facebook", "bluesky", "twitch", "dailymotion", "pinterest", "linkedin", "snapchat"].
missing_chunksupload_incompleteIndex các chunk server chưa nhận được.
max_bytesmedia_too_largeDung lượng file tối đa tài khoản được gửi, tính bằng byte.
paramsinvalid_requestKhi 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ã HTTPcodeCó thể thử lạiNguyên nhân và cách xử lý
400, 422invalid_requestKhôngTham 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.
422invalid_urlKhôngLink 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.
422unsupported_platformKhôngplatform không được hỗ trợ.
422unsupported_mediaKhôngĐuôi file tải lên không nằm trong danh sách hỗ trợ.
401unauthorizedKhôngThiế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.
403insufficient_scopeKhôngToken OAuth thiếu quyền transcriptions:read hoặc transcriptions:write cần cho thao tác.
403email_not_verifiedKhôngCần xác minh email rồi mới tạo job.
402insufficient_minutesKhôngBạn còn 0 phút, hoặc số phút dùng được không đủ cho job.
402no_active_planKhôngBạ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.
404not_foundKhôngKhông tìm thấy job, hoặc job thuộc team khác.
409upload_incompleteKhôngChưa gửi đủ chunk. Gửi phần còn thiếu rồi gọi hoàn tất lần nữa.
409invalid_stateKhôngJob 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.
409idempotency_conflictKhôngBạn đã dùng Idempotency-Key này cho bộ tham số khác.
413media_too_largeKhôngDung lượng file vượt giới hạn của tài khoản. Xem Tải file lên.
413invalid_requestKhôngBody JSON vượt 1 MB. Với file quá lớn, mã lỗi là media_too_large.
429rate_limitedCóVượt số request mỗi phút. Chờ số giây ghi trong Retry-After.
429too_many_active_jobsCóĐã 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.
500internal_errorCóLỗi phía transcript1. Chờ một lát rồi thử lại.
503service_unavailableCó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 retryable là true: rate_limited, too_many_active_jobs, internal_error hoặc service_unavailable.
  • Có Retry-After thì 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/transcriptions với nguyên header Idempotency-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.codeNguyên nhânNên làm gì?
media_unavailableVideo 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_privateVideo đ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_requiredPhả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_audioVideo 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_restrictedVideo có giới hạn độ tuổi.Không thử lại bằng link; tải file lên thay thế.
live_streamBuổ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_captionsBạ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_longBả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_mediaFile không đọc được hoặc thiếu track audio.Gửi lại bằng định dạng file được hỗ trợ.
no_speechKhông phát hiện giọng nói.Không thử lại.
unsupported_languageBả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_failedHệ 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

Đố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
    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
    • 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
    • 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
    • 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 null unless the request includes include_deleted=true.

  • transcriptobjecttùy chọn

    Included in GET responses for completed transcriptions.

    Xem trường con
    • textstringbắt buộc
    • speakersarray of stringsbắt buộc
    • segmentsarray of objectsbắt buộc
      Xem 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
        • 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/transcriptions

Transcribes 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 same source, language and diarize. It must have been created in the last 24 hours and must not be failed or canceled. 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
    • 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 status
  • 201 Created — The transcription is awaiting a chunked upload. upload describes 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 malformed
  • 401 Unauthorized — Missing or invalid credential
  • 402 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 plan
  • 409 Conflict — Idempotency-Key was reused with different parameters.
  • 413 Content Too Large — The upload or the JSON request body is too large
  • 422 Unprocessable Content — Invalid request, URL, platform or file type
  • 429 Too Many Requests — Too many requests or too many active transcriptions. Wait for the number of seconds in Retry-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_at is set. Defaults to false.

    Giá trị hợp lệtruefalse

Trả về

  • 200 OK — The transcription, or the rendered transcript
  • 202 Accepted — A rendered format was requested while the transcription is still processing

Mã trạng thái khác

  • 401 Unauthorized — Missing or invalid credential
  • 403 Forbidden — Insufficient scope or a single-member team plan
  • 404 Not Found — Transcription not found
  • 422 Unprocessable Content — Invalid query parameters
  • 429 Too Many Requests — Too many requests. Wait for the number of seconds in Retry-After.

List transcriptions

GET /v1/transcriptions

Lists 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_at is set. Defaults to false.

    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 credential
  • 403 Forbidden — Insufficient scope or a single-member team plan
  • 422 Unprocessable Content — Invalid query parameters or cursor
  • 429 Too Many Requests — Too many requests. Wait for the number of seconds in Retry-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 credential
  • 403 Forbidden — Insufficient scope, cross-site request or a single-member team plan
  • 404 Not Found — Transcription not found
  • 429 Too Many Requests — Too many requests. Wait for the number of seconds in Retry-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 token
  • 404 Not Found — Transcription not found
  • 409 Conflict — The transcription is no longer awaiting an upload
  • 422 Unprocessable Content — Index outside the chunk plan or wrong body size

Get upload progress

GET /v1/transcriptions/{id}/upload

Lists 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 credential
  • 403 Forbidden — Insufficient scope or a single-member team plan
  • 404 Not Found — Transcription or upload not found
  • 429 Too Many Requests — Too many requests. Wait for the number of seconds in Retry-After.

Complete a chunked upload

POST /v1/transcriptions/{id}/upload/complete

Checks 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 credential
  • 402 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 plan
  • 404 Not Found — Transcription or upload not found
  • 409 Conflict — upload_incomplete means chunks are missing. missing_chunks lists them. invalid_state means 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 in Retry-After.

Account

Your plan, remaining minutes and rate limits.

Get your account

GET /v1/account

Returns 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 credential
  • 403 Forbidden — Insufficient scope or a single-member team plan
  • 404 Not Found — No account found
  • 429 Too Many Requests — Too many requests. Wait for the number of seconds in Retry-After.

Đối tượng Account

Đố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
    • idstringbắt buộc
    • emailstringbắt buộc
  • planobjectbắt buộccho phép null
    Xem trường con
    • idstringbắt buộc
    • namestringbắt buộc
  • minutesobjectbắt buộc
    Xem 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
    • 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));
};
transcription.completed
{
  "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.completedJob chuyển sang completed.
transcription.failedJob 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.
  • data chứa object transcription, không kèm trường transcript.

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/json
  • User-Agent: transcript1-webhooks/1.0
  • X-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>.

  • t ghi 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 t và 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ào raw_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 3xx vẫ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.id và type để nhận ra và bỏ qua bản trùng.