本記事は Video Transcriber AI の開発者本人が、自作の Transcript API(
https://videotranscriber.ai/openapi/v1)の使い方をコード付きで解説する技術記事です。2026年9月執筆時点の仕様に基づいています。最新の詳細は公式ドキュメントを参照してください。
YouTube・TikTok・Instagram の動画を文字起こししてブログ記事や字幕、要約に変換する作業は、地味に時間を食います。自前で Whisper をホストすれば GPU代とインフラ運用が重くのしかかるし、既存のSaaSはファイルアップロード前提でURLをそのまま渡せなかったり、非同期タスクの設計が雑で運用がつらかったりする。
そこで個人開発で作ったのが Video Transcriber AI です。今回はその中核である Transcript API を、実装者目線で一通り触っていきます。自分のプロダクトに「動画→テキスト」の機能を組み込みたい人や、n8n・Zapier的な自動化パイプラインに載せたい人向けの実装ガイドです。
REST + JSON、UTF-8、タイムスタンプは UTC / ISO 8601
非同期タスク方式:タスクを作成 → ポーリング → 結果取得、の3ステップ
対応言語200以上、YouTube / TikTok / Instagram / Facebook / X / Bilibili などのURLをそのまま渡せる(ファイルアップロードはOpenAPI経由では非対応。パブリックURLが必須)
ベースURLはこちら:
https://videotranscriber.ai/openapi/v1
1. POST /transcriptions → タスク作成、request_id を受け取る
2. GET /transcriptions/{id} → retry_after 間隔でポーリング
3. GET /transcriptions/{id}/result → 完了したら構造化データを取得
動画の処理は時間がかかるので、作成APIはすぐレスポンスを返し、実処理はバックグラウンドで進みます。request_id を保存して、タスクが終了状態になるまでポーリングする設計です。
Bearer トークン方式です。Cookieやログイントークンでは認証できません。
Authorization: Bearer $VT_API_KEY
ヘッダー 必須 説明 Authorization Yes Bearer APIキー Content-Type POST時 application/json Idempotency-Key POST時 1回の論理的な作成操作を表す固定文字列 X-Request-ID No トレース用ID。省略時はサーバー側で発行
APIキーはブラウザ側コード・公開リポジトリ・ログ・サポートへの問い合わせ本文などに絶対に貼らないでください。サーバーサイドの環境変数などで管理するのが前提です。
動画処理はミニマムでも数十秒〜数分かかるタスクなので、クライアント側のリトライでタスクが重複作成される(=課金対象のタスクが二重に走る)事故が起きやすいです。これを防ぐのが Idempotency-Key。
リクエスト 結果 同じキー・同じボディ 元のタスクをHTTP 200で返す(重複作成されない) 同じキー・異なるボディ HTTP 409 idempotency_conflict
自動化パイプラインに組み込むときは、動画URL+ジョブIDなどから一意な Idempotency-Key を生成しておくと安全です。
ソース種別 対応例 プラットフォームURL YouTube, TikTok, Instagram, Facebook, X, Bilibili クラウドリンク Google Drive, Dropbox 直接ファイルURL MP3, MP4, M4A, WAV, WebM, MOV, AVI, OGG, AAC
ポイントは、URLがログイン不要・セッション不要・プライベートネットワーク経由でない、誰でもアクセスできる状態である必要があること。社内限定のGoogle Driveリンクなどは弾かれます。
課金は動画の長さ(切り上げ分単位)で計算されます。
billable_minutes = ceil(duration_seconds / 60)
機能 内容 クォータ消費 Transcribe フルテキスト・言語検出・タイムスタンプ付きセグメント・話者分離(任意) 1クォータ / 1分 プラットフォームURL対応(YouTube等) 各種プラットフォームURLから直接処理 期間限定無料 Speaker Diarization 話者分離 期間限定無料 Language Detection 言語自動検出 期間限定無料 Timestamps タイムスタンプ付きセグメント 期間限定無料 Subtitle(SRT/VTT) 字幕ファイルの署名付きダウンロードURL生成 期間限定無料 Chapters 章立て(タイトル・要約付き) 1クォータ / 1分 Translation 翻訳テキスト・整列済みセグメント 1クォータ / 1分
※ 「期間限定無料」の機能は今後変わる可能性があります。最新の料金はPricingページで確認してください。
POST /transcriptions にリクエストボディを送ります。
フィールド 型 必須 説明 source_url string Yes 動画・音声のパブリックURL language string No ソース言語コード。省略時は自動検出 speaker_diarization boolean No 話者分離を有効化 features.chapters boolean No チャプター生成を有効化 features.translation object No 翻訳を有効化(target_language を指定)
curl --request POST "https://videotranscriber.ai/openapi/v1/transcriptions" \
--header "Authorization: Bearer $VT_API_KEY" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: transcribe-order-0001" \
--data '{
"source_url": "https://www.youtube.com/watch?v=xxxxxxxxxxx",
"language": "auto",
"speaker_diarization": true,
"features": {
"chapters": true,
"translation": {"target_language": "ja"}
}
}'
import requests
API_KEY = "YOUR_VT_API_KEY"
BASE_URL = "https://videotranscriber.ai/openapi/v1"
def create_transcription(source_url: str, idempotency_key: str) -> dict:
resp = requests.post(
f"{BASE_URL}/transcriptions",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
"Idempotency-Key": idempotency_key,
},
json={
"source_url": source_url,
"language": "auto",
"speaker_diarization": True,
"features": {
"chapters": True,
"translation": {"target_language": "ja"},
},
},
timeout=30,
)
resp.raise_for_status()
return resp.json()
task = create_transcription(
"https://www.youtube.com/watch?v=xxxxxxxxxxx",
idempotency_key="transcribe-order-0001",
)
print(task)
# {'request_id': 'tr_01JEXAMPLE', 'status': 'queued',
# 'poll_url': '/transcriptions/tr_01JEXAMPLE', 'retry_after': 5}
ステータス 意味 queued 処理待ち processing 処理中 succeeded 全機能が成功 partial_succeeded 一部の機能のみ成功 failed 失敗 cancelled キャンセル済み
ポーリングは retry_after(レスポンスボディ)または Retry-After(レスポンスヘッダー)に従います。固定間隔でタイトループするのは避けましょう。
import time
def wait_for_result(request_id: str, max_wait: int = 600) -> dict:
elapsed = 0
while elapsed < max_wait:
resp = requests.get(
f"{BASE_URL}/transcriptions/{request_id}",
headers={"Authorization": f"Bearer {API_KEY}"},
timeout=30,
)
data = resp.json()
if data["status"] in ("succeeded", "partial_succeeded", "failed", "cancelled"):
return data
wait = data.get("retry_after", 5)
time.sleep(wait)
elapsed += wait
raise TimeoutError(f"transcription {request_id} timed out")
result_meta = wait_for_result(task["request_id"])
GET /transcriptions/{request_id}/result で構造化データを取得します。リクエストしなかった機能は null で返り、一部機能だけ成功した場合(partial_succeeded)でも成功した分だけ取得できます。
def get_result(request_id: str) -> dict:
resp = requests.get(
f"{BASE_URL}/transcriptions/{request_id}/result",
headers={"Authorization": f"Bearer {API_KEY}"},
timeout=30,
)
resp.raise_for_status()
return resp.json()
result = get_result(task["request_id"])
レスポンスに含まれる主なスキーマ:
スキーマ 内容 Transcript 検出言語、全文テキスト、動画の長さ、タイムスタンプ付きセグメント、話者ラベル(任意) Chapters 開始・終了時刻、タイトル、要約を持つ章立て Translation ソース/ターゲット言語、翻訳テキスト、整列済みセグメント
speaker フィールドは話者分離が無効な場合、または信頼できる話者ラベルが取得できなかった場合に null になります。
イメージとしてはこんな形です(フィールド構成の例):
{
"request_id": "tr_01JEXAMPLE",
"status": "succeeded",
"transcript": {
"language": "en",
"duration": 612.4,
"full_text": "...",
"segments": [
{"start": 0.0, "end": 4.2, "text": "...", "speaker": "speaker_1"}
]
},
"chapters": [
{"start": 0.0, "end": 120.0, "title": "Introduction", "summary": "..."}
],
"translation": {
"source_language": "en",
"target_language": "ja",
"text": "...",
"segments": [{"start": 0.0, "end": 4.2, "text": "..."}]
},
"subtitles": {
"srt_url": "https://.../signed-url.srt",
"vtt_url": "https://.../signed-url.vtt"
}
}
字幕(SRT/VTT)は署名付きURLとして返り、有効期限は最大1時間です。ダウンロードしたら早めに保存しておきましょう。
エラーはHTTPステータスコードと、変わらない英語の error.code で判定します。error.message は人間向けの文言なので、条件分岐には使わないのが安全です。
{
"error": {
"code": "invalid_request",
"message": "The request body is invalid.",
"retryable": false
},
"request_id": "req_01JEXAMPLE"
}
HTTPステータス 意味 400 リクエスト不正・非対応の入力 401 APIキーが無効・未指定 409 冪等性キーの競合 429 レート・クォータ制限超過 500 / 503 一時的なサーバー/プロバイダ障害
以下のレスポンスヘッダーを見てリトライ間隔を調整します。
X-RateLimit-Limit
X-RateLimit-Remaining
X-RateLimit-Reset
Retry-After
意図的にリトライする場合は、新しい Idempotency-Key を使うのが原則です。元のキーを使い回すと、常に最初のタスクが返ってくるだけになります。
リソース 保持期間 結果データ 生成から30日間 署名付きダウンロードURL 最大1時間、非公開 タスク記録 作成月+翌暦月(UTC基準)
サポートに問い合わせる際は、transcription ID と X-Request-ID を伝えればOKです。APIキー全体・Authorization ヘッダー・認証情報付きの動画URL・署名付き結果URLは、サポートにも決して送らないでください。
Transcript APIは「API Quota」というプリペイド式クレジットで動きます。クレジットパックをまとめ買いして、実際に処理した動画・音声の長さ分だけ消費する仕組みです。サブスクリプションや自動更新はなく、購入したクレジットは失効しません。必要な分だけ買って、自分のペースで使えます(2026年9月執筆時点。最新の料金体系は公式ページをご確認ください)。
動画の内容をブログ記事化する自動パイプライン(文字起こし→要約→記事化)
ポッドキャスト/インタビューの自動文字起こし+ show notes 生成
多言語字幕の自動生成(SRT/VTT + 翻訳)
社内ミーティング動画の自動要約前処理
n8n・Zapierなどのノーコード自動化フローへの組み込み
Q. Transcript APIは無料で使えますか? 話者分離・言語検出・タイムスタンプ・字幕生成など一部の機能は現在期間限定で無料です。基本の文字起こし・チャプター生成・翻訳はクォータを消費します。
Q. ローカルの動画ファイルをそのままアップロードできますか? OpenAPI経由ではファイルアップロードに対応していません。パブリックにアクセス可能なURLを渡す必要があります。
Q. 対応言語は何ヶ国語ですか? 200以上の言語に対応しています。
Q. リクエストしたらすぐ結果が返ってきますか? いいえ、非同期タスク方式です。タスク作成後、poll_url を retry_after の間隔でポーリングし、succeeded などの終了ステータスになってから結果を取得します。
Transcript API は「動画URLを渡す → ポーリングする → 構造化データを受け取る」というシンプルな3ステップで、YouTubeやTikTokなどの動画を文字起こし・字幕化・翻訳できるAPIです。個人開発のプロダクトや自動化パイプラインに「動画→テキスト」の機能を足したい人は、ぜひ触ってみてください。
公式ドキュメント:https://videotranscriber.ai/code-docs
料金ページ:https://videotranscriber.ai/pricing
プロダクトページ(Solomaker):(ここに自分のsolomaker.dev製品ページへのリンクを入れる)
コメントはまだありません
読み込み中...