ドキュメントREST APIリファレンス

REST APIリファレンス

/v1の全エンドポイントのパラメーターと実装例を確認できます。OpenAPI仕様はJSON・YAMLでダウンロードできます。

はじめに

ベースURL
https://api.transcript1.com/v1

APIのベースURLは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の元の言語の字幕を優先します。動画によっては字幕がないため、使える字幕がなければ音声認識(STT)に切り替えます。source=captionsを指定した場合は、captions(字幕のみ)で処理します。音声のダウンロードやSTTへの切り替えは行わず、使える字幕がなければno_captionsを返します。source=sttを指定するか話者分離を有効にすると、字幕を使わず音声を処理します。取得時の制限や、セグメント・単語ごとのタイムスタンプの違いは対応ソース一覧を参照してください。

ツールから読み込めるOpenAPI仕様を、次の形式で公開しています。

認証

curl https://api.transcript1.com/v1/account \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY"

認証情報はAuthorization: Bearer <token>の形式で、Authorizationヘッダーに指定します。

  • APIキーはt1_で始まり、全エンドポイントで使えます。「API keys」から作成してください。
  • OAuthアクセストークンはt1o_で始まります。ClaudeやChatGPTなどのMCPクライアントを接続したときに発行します。利用できる操作はtranscriptions:readとtranscriptions:writeのスコープで決まります。
スコープ呼び出せるエンドポイント
transcriptions:readGET /v1/transcriptions、GET /v1/transcriptions/:id、GET /v1/transcriptions/:id/upload、GET /v1/account
transcriptions:writePOST /v1/transcriptions、DELETE /v1/transcriptions/:id、POST /v1/transcriptions/:id/upload/complete
  • 必要なスコープがトークンになければ、APIは403 insufficient_scopeを返します。
  • 認証情報を送らなかった場合や無効な場合は、401 unauthorizedが返ります。

チャンク送信用のPUT /v1/transcriptions/:id/upload/chunks/:indexだけは、X-Upload-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文字で指定します。クエリパラメーターには入れず、リクエストヘッダーで送ってください。

  • キーとパラメーターが同じなら、最初に作成した文字起こしを返します。追加の課金はありません。
  • 同じキーでパラメーターを変えて送ると、409 idempotency_conflictになります。
  • チャンクアップロードの作成を同じキーでやり直すと、アップロードトークンを新しく発行します。

エラー

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
  }
}
  • リクエストエラーは、APIがリクエストを受け付けられなかった場合に返します。
  • ジョブの失敗は、受け付けたあとの文字起こし処理で起きます。この場合、statusはfailedです。

共通のエラー形式

/v1のリクエストエラーは、errorオブジェクトで返します。必ずcode、message、retryableを含みます。

  • 処理の分岐にはcodeを使ってください。
  • ユーザーへの説明にはmessageを使います。文言は変更することがあるため、分岐条件には使わないでください。
  • retryableがtrueなら、時間を置いて同じリクエストを送ると成功する可能性があります。

エラーによっては、retryableと同じ階層に補足フィールドが付きます。

フィールド対象コード内容
action_urlinsufficient_minutesプランの契約や分数の追加購入ができるページです。
minutes_needed、minutes_remaininginsufficient_minutes必要な分数と、現在使える分数です。必要な分数が未確定ならnullです。
supported_platformsunsupported_platform対応プラットフォームの一覧です:["youtube", "x", "tiktok", "instagram", "facebook", "bluesky", "twitch", "dailymotion", "pinterest", "linkedin", "snapchat"]。
missing_chunksupload_incomplete未受信のチャンクのインデックスです。
max_bytesmedia_too_largeアップロードできるファイルの上限をバイト単位で示します。
paramsinvalid_requestボディやクエリの入力チェックで返します。フィールド名をキーに、それぞれの問題点を示すオブジェクトです。

リクエストエラー

HTTPステータスcodeそのまま再試行原因と対処
400、422invalid_request不可パラメーターやボディの項目に不足・誤りがあります。diarizeとsource: "captions"、reuse_recentとwebhook_urlの併用も該当します。ボディが正しいJSONでない場合も返します。
422invalid_url不可リンクが正しくありません。YouTube、X、TikTok、Instagram、Facebook、Bluesky、または対応ソースとオプションにあるプラットフォームのリンクを指定してください。platformとリンクの不一致も該当します。
422unsupported_platform不可指定したplatformには対応していません。
422unsupported_media不可ファイルの拡張子が対応対象外です。
401unauthorized不可認証情報が未指定・無効・期限切れ・失効済みのいずれかです。アップロードトークンの無効・期限切れも該当します。
403insufficient_scope不可OAuthトークンに必要なtranscriptions:readかtranscriptions:writeがありません。
403email_not_verified不可メールアドレスが未認証です。認証を済ませてから文字起こしを開始してください。
402insufficient_minutes不可使える分数が0分か、処理に必要な分数に足りません。
402no_active_plan不可有料プランが有効でない状態で、分数を追加購入しようとしました。ダッシュボードの課金用エンドポイントのエラーで、文字起こしのエンドポイントでは返しません。
404not_found不可指定した文字起こしがないか、別のチームに属しています。
409upload_incomplete不可未受信のチャンクがあります。不足分を送ってから、もう一度アップロードを完了してください。
409invalid_state不可ジョブはすでにアップロード待ちではありません。チャンクの追加送信やアップロードの完了はできません。
409idempotency_conflict不可同じIdempotency-Keyを別のパラメーターで使用済みです。
413media_too_large不可ファイルサイズが上限を超えています。アップロードで制限を確認してください。
413invalid_request不可JSONボディが1MBを超えています。ファイルのサイズ超過にはmedia_too_largeを返します。
429rate_limited可1分間のリクエスト上限を超えました。Retry-Afterで指定された秒数を待ってください。
429too_many_active_jobs可処理中の文字起こしか、未完了のアップロードが上限に達しています。Retry-Afterの秒数を待ってから再試行します。
500internal_error可transcript1側のエラーです。時間を置いて再試行してください。
503service_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ヘッダーを送ります。最初のリクエストが成功していても、二重に課金しません。
  • ほかのコードが返った場合は、原因を修正してから送り直してください。

受付後に文字起こしが失敗した場合

statusがfailedになると、文字起こしオブジェクトにerrorが付きます。中にはcodeとmessageが入ります。

受付レスポンスを返したあとでも、処理に失敗することがあります。ポーリング時、またはtranscription.failedのWebhookを受け取ったときに、errorを確認してください。

error.code原因次の操作
media_unavailable動画が見つからないか、すでに視聴できません。そのまま再試行せず、URLを確認してください。
media_private動画の公開設定がプライベートです。公開投稿、または公開・限定公開のYouTube動画を指定してください。
login_required動画の取得にログインが必要です。再試行しません。待っても解消しないエラーとして扱います。
no_audio動画に音声トラックがありません。再試行しません。待っても解消しないエラーとして扱います。
age_restricted年齢制限のある動画です。リンクを再送信せず、ファイルをアップロードしてください。
live_streamライブ配信中か、まだ配信が始まっていません。配信終了後に再試行してください。
no_captionssourceにcaptionsを指定しましたが、使える字幕がありません。source: "auto"か"stt"で送り直してください。
media_too_long音声認識(STT)の上限である5時間を超えています。同じファイルを再送信せず、分割してください。
unsupported_mediaファイルを読み込めないか、音声トラックがありません。対応形式のファイルを送ってください。
no_speech発話が検出されませんでした。再試行しません。
unsupported_language録音の言語が対応対象外です。languageに対応する言語コードか"auto"を指定して送り直してください。
insufficient_minutes課金の時点で分数が不足しました。分数を追加購入してから再試行してください。
fetch_failedメディアを繰り返し取得しようとしましたが、失敗しました。時間を置いて再試行できます。
transcription_failed音声認識(STT)を繰り返し試みましたが、失敗しました。時間を置いて再試行できます。

文字起こしに失敗した場合やキャンセルした場合は課金しません。すでに分数を差し引いていた場合も、その時点で戻します。

Transcriptionオブジェクト

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

  • transcriptobject任意

    Included in GET responses 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/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
}

クエリパラメータ

  • 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 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.

    指定できる値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 status
  • 201 Created — The transcription is awaiting a chunked upload. upload describes where to send each chunk.
  • 202 Accepted — The transcription is processing

その他のHTTPステータス

  • 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."
      }
    ]
  }
}

パスパラメータ

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

    指定できる値truefalse

成功時のレスポンス

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

その他のHTTPステータス

  • 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"
}

クエリパラメータ

  • limitinteger任意デフォルト値:20
  • cursorstring任意
  • statusstring任意

    指定できる値awaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled

  • platformstring任意
  • include_deletedstring任意デフォルト値:false

    Also returns deleted transcriptions as read-only records without a transcript. Their deleted_at is set. Defaults to false.

    指定できる値truefalse

成功時のレスポンス

  • 200 OK — A page of transcriptions

その他のHTTPステータス

  • 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"

レスポンスボディはありません

パスパラメータ

  • idstring必須

成功時のレスポンス

  • 204 No Content — Canceled or deleted

その他のHTTPステータス

  • 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
}

パスパラメータ

  • idstring必須
  • indexinteger任意null可

    Zero-based chunk number from the upload plan

ヘッダー

  • X-Upload-Tokenstring必須

リクエストボディ

  • (生のボディ)string · binary必須

成功時のレスポンス

  • 200 OK — The chunk was stored

その他のHTTPステータス

  • 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"
}

パスパラメータ

  • idstring必須

成功時のレスポンス

  • 200 OK — Upload progress

その他のHTTPステータス

  • 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
}

パスパラメータ

  • idstring必須

成功時のレスポンス

  • 202 Accepted — The transcription is queued

その他のHTTPステータス

  • 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
  }
}

成功時のレスポンス

  • 200 OK — The authenticated user's account

その他のHTTPステータス

  • 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.

Accountオブジェクト

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));
};
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
  }
}

文字起こしの完了や失敗を通知で受け取るには、作成時にwebhook_urlを指定してください。transcript1が通知先へ署名付きのPOSTを送ります。

Webhookを指定できるのはREST APIだけです。MCPサーバーには、Webhookの指定項目はありません。

通知先URLを指定する

POST /v1/transcriptionsにwebhook_urlを含めます。

  • 動画リンクの送信時や、分割アップロードの作成時はJSONボディに指定します。
  • ファイルを1回でアップロードする場合は、フォームフィールドで指定します。

通知先URLには、次の条件があります。

  • HTTPSを使ってください。
  • URL内にユーザー名やパスワードを入れないでください。
  • 名前解決先は公開IPアドレスである必要があります。

プライベート、ループバック、リンクローカルなどの非公開アドレスを指定すると、422 invalid_requestになります。アドレスの確認は、文字起こしの作成時だけでなく、通知を送るたびに行います。

webhook_urlとreuse_recent=trueは併用できません。

通知するイベント

type通知の条件
transcription.completedジョブがcompletedになったときに送ります。
transcription.failedジョブがfailedになったときに送ります。data.errorにcodeとmessageを含めます。

キャンセル時のWebhookはありません。

通知の内容

通知のリクエストボディはJSONで、次の情報を含みます。

  • created_atはイベントの作成日時です。
  • dataには文字起こしオブジェクトが入ります。ただし、transcriptは含みません。

本文が必要な場合は、dataのidでGET /v1/transcriptions/:idを呼び出してください。

通知には次のヘッダーを付けます。

  • Content-Type: application/json
  • User-Agent: transcript1-webhooks/1.0
  • X-Transcript1-Signature(検証方法は次の節を参照してください)。

署名を検証する

通知のたびに、X-Transcript1-Signatureヘッダーで署名を送ります。値の形式はt=<unix seconds>,v1=<hex digest>です。

  • tは署名した時点のUnix時刻で、単位は秒です。
  • v1は"<t>.<raw body>"のHMAC-SHA256を16進数で表した値です。tの値、ドット、受信したままのボディを連結して計算します。キーには、whsec_を省略せず、署名用シークレット全体を使ってください。

署名はJSONをパースする前の、受信したバイト列で検証します。パース後にJSONへ戻すと、空白やキーの順序が変わり、署名が一致しなくなることがあります。

  • 署名の比較には、定数時間で比較する処理を使ってください。
  • tが現在時刻から大きくずれていれば拒否してください。実装例では5分以内を許容しています。
  • Expressでは、JSONとして先にパースせず、ボディを生のテキストで読み取ってください。
  • Flaskでは、request.get_data(as_text=True)の値をraw_bodyとして渡してください。

署名用シークレットの管理

署名用シークレットはチーム単位で、whsec_から始まります。そのチームの全文字起こしのWebhookに、同じシークレットで署名します。

確認や更新(ローテーション)は、ダッシュボードの「Webhooks」で行います。

更新すると、シークレットは即座に切り替わります。それ以降に送るWebhookは、新しいシークレットで署名します。

配信と再試行

  • 受信側が2xxを返せば、配信成功です。
  • 2xx以外のステータス、接続エラー、10秒以内に応答がない場合は、配信失敗として扱います。
  • 配信に失敗すると、待ち時間を延ばしながら再試行します。最初の送信を含めて最大6回です。待ち時間は2分、4分、8分、16分、32分で、最後の送信は最初から約1時間後になります。
  • 転送後の最終URLを指定してください。リダイレクトには追従しないため、3xxでも配信失敗になります。
  • タイムアウト後に受信側が応答した場合など、同じ通知を複数回送ることがあります。data.idとtypeの組み合わせで重複を無視してください。