REST API|動画字幕 API

どんな動画にも字幕を
APIコール3回で

動画のURLを送るだけで、単語単位の字幕を焼き込んだ mp4 が返ってきます。Whisper が各単語のタイミングを取り、AI が強調する語を選び、レンダリングは当社のワーカー群で走ります。

POSThttps://autostud.ai/api/v1/actions/subtitles.generate
クイックスタート

全工程を1ファイルで

貼り付けて、キーを入れて、実行するだけ。疑似コードは一行もありません。

const API = 'https://autostud.ai/api/v1'
const KEY = process.env.AUTOSTUD_API_KEY

const call = async (path, body) => {
  const response = await fetch(API + path, {
    method: body ? 'POST' : 'GET',
    headers: {
      Authorization: `Bearer ${KEY}`,
      'Content-Type': 'application/json',
    },
    body: body ? JSON.stringify(body) : undefined,
  })

  const payload = await response.json()
  if (!response.ok) throw new Error(payload.error?.message || response.statusText)
  return payload
}

// 1. A video project to hang the timeline on.
const created = await call('/actions/videos.create', {
  video_name: 'Interview clip',
  video_type_id: 'timeline',
  video_format: 'portrait',
  video_lang: 'en',
})
const video_id = created.data.video_id

// 2. Transcribe, emphasise, style — one call.
const subtitled = await call('/actions/subtitles.generate', {
  video_id,
  media_url: 'https://cdn.example.com/interview.mp4',
  style_preset: 'beast',
  words_per_group: 3,
})
console.log(subtitled.data.word_count, 'words', subtitled.data.duration_seconds, 's')

// 3. Render it.
await call('/actions/renders.create', {
  video_id,
  video_type_id: 'timeline',
  video_format: 'portrait',
})

// 4. Wait for the worker. A webhook is better; this is the short version.
let render
do {
  await new Promise((resolve) => setTimeout(resolve, 15000))
  const list = await call(`/renders?video_id=${video_id}&limit=1`)
  render = list.data[0]
} while (render && ['not_started', 'processing'].includes(render.render_status))

if (render.render_status !== 'done') throw new Error('Render failed')
console.log(render.render_url)

ベースURL: https://autostud.ai/api/v1 — 認証は `Authorization: Bearer sk_live_…`。`sk_test_` キーは同じ経路をすべて通ったうえで、消費の直前で止まります。

ステップ

実際にやることはこれだけ

6ステップ。うち4つはリクエスト1本です。

  1. 1

    APIキーを作る

    ダッシュボード → 設定 → APIキー。スコープを自分で選ばないなら「Automation」プリセットで十分です(動画・レンダー・ファイルを含みます)。シークレットの表示は一度きり。`sk_live_` は消費し、`sk_test_` はリクエスト全体を検証して書き込み前に止まります。

    export AUTOSTUD_API_KEY="sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    
    # What can this key actually do?
    curl https://autostud.ai/api/v1 \
      -H "Authorization: Bearer $AUTOSTUD_API_KEY"
  2. 2

    動画をURLに置く

    アップロード用エンドポイントはありません。APIが読むのはURLです。自社バケット、CDN、署名付きリンク — 当社サーバーが取得できれば何でも構いません。ワークスペースのライブラリへの登録は任意です。

    # The API takes a URL, never a file upload. Anything publicly
    # reachable works: your bucket, your CDN, a signed URL.
    export MEDIA_URL="https://cdn.example.com/interview.mp4"
    
    # Optional: keep a record of it in the workspace library.
    curl -X POST https://autostud.ai/api/v1/assets \
      -H "Authorization: Bearer $AUTOSTUD_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "provider_file_url": "'"$MEDIA_URL"'",
        "provider_file_name": "interview.mp4",
        "file_mime_type": "video/mp4",
        "provider_file_id": "interview-2026-08-18",
        "sync_method": "api"
      }'
  3. 3

    動画プロジェクトを作る

    `videos.create` が返す `video_id` に、以降すべてがぶら下がります。`Idempotency-Key` を付ければ、再送しても2つ目のプロジェクトは作られず最初の応答が返ります。

    curl -X POST https://autostud.ai/api/v1/actions/videos.create \
      -H "Authorization: Bearer $AUTOSTUD_API_KEY" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: interview-2026-08-18" \
      -d '{
        "video_name": "Interview clip",
        "video_type_id": "timeline",
        "video_format": "portrait",
        "video_lang": "en"
      }'
  4. 4

    字幕を付ける

    `subtitles.generate` がサーバー側で全部やります。Whisper が単語単位で文字起こしし、AI が強調語を印し、116種類のスタイルから1つを適用。応答には単語数・正確な尺・検出言語が入ります。

    export VIDEO_ID="9f0c4e2a-1d6b-4a77-9d51-6b0f2e8c3a4d"
    
    curl -X POST https://autostud.ai/api/v1/actions/subtitles.generate \
      -H "Authorization: Bearer $AUTOSTUD_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "video_id": "'"$VIDEO_ID"'",
        "media_url": "'"$MEDIA_URL"'",
        "style_preset": "beast",
        "words_per_group": 3,
        "enable_emphasis": true,
        "enable_diarization": false
      }'
  5. 5

    レンダーを投入する

    `renders.create` がワーカー群にジョブを載せ、即座に `render_id` を返します。1レンダーは長さに関係なく20クレジットです。

    curl -X POST https://autostud.ai/api/v1/actions/renders.create \
      -H "Authorization: Bearer $AUTOSTUD_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "video_id": "'"$VIDEO_ID"'",
        "video_type_id": "timeline",
        "video_format": "portrait"
      }'
  6. 6

    mp4 を受け取る

    `render.completed` を購読すれば、完成URLが署名付きで届きます。取りに行きたい場合は、その動画のレンダー一覧を取得して `render_status` が `done` になるまで読んでください。

    # Register once, then stop polling.
    curl -X POST https://autostud.ai/api/v1/webhooks \
      -H "Authorization: Bearer $AUTOSTUD_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "url": "https://your-app.com/hooks/autostud",
        "events": ["render.completed", "render.failed"],
        "description": "Subtitled videos"
      }'
    # The signing secret comes back once, in this response. Store it.
リファレンス

このページで使う全コール

スコープは「キーが持つべき権限」であって、送る値ではありません。

コールスコープ何をするか
GET /api/v1-ディスカバリー:このキーで何ができるか、制限、消費量。
POST /api/v1/actions/videos.createvideos:write動画プロジェクトを作成し、そのIDを返します。
POST /api/v1/actions/subtitles.generatevideos:execute文字起こし・強調・スタイル適用を行い、字幕トラックを保存します。
POST /api/v1/actions/renders.createrenders:executeワーカー群にレンダーを投入します。20クレジット。
GET /api/v1/renders?video_id=…renders:readある動画のレンダー一覧(新しい順)。ステータスとURL付き。
POST /api/v1/webhookswebhooks:writehttps エンドポイントを登録し、署名シークレットを一度だけ返します。

スタイルプリセット

`style_preset` に1つ渡すだけです。各プリセットがフォント・縁取り・強調色・アニメーションをまとめて決めるので、他に設定するものはありません。

makeitlookeasy
default4 · simple
makeitloud
bold3 · simple
thisoneword
impact3 · focus_on_one_word
huge
beast1 · focus_on_one_word
onewordatatime
karaoke5 · focus_on_one_word
itfillsasyousing
karaoke_fill5 · karaoke
lightsonthewords
neon4 · progressively_visible
nothingbehindthetextatall
minimal6 · simple
wordbywordtheyland
pop5 · progressively_visible
darktextonapill
pill5 · simple
twocalmlinesatthebottomoftheframe
cinematic9 · simple

実装前に知っておくこと

  • レート制限はキー単位で、ヘッダーで返ります:`X-RateLimit-Limit`、`X-RateLimit-Remaining`、429 のときは `Retry-After`。
  • POST に `Idempotency-Key` を付けると24時間は再送が安全になり、最初の応答がそのまま返ります。
  • `sk_test_` キーは認証・スコープ・制限・バリデーションまで実行し、書き込みも消費もせずに `simulated: true` を返します。
  • エラーは型付きです:`invalid_request`、`insufficient_credits`、`rate_limit_exceeded`、`upstream_error` — メッセージではなくコードで分岐してください。

失敗したとき

エラーの形はどれも同じです。分岐用の安定した `code`、直し方の呼び出しを名指しする `hint`、そして問い合わせ用の `request_id`。全コードの一覧は /docs/api/errors にあります。

コード意味
401 missing_credentialsリクエストにキーがない、または知らないキーです。
403 insufficient_scopeキーにスコープが足りません。`details.required_scopes` が示します。
422 validation_failedフィールドが不正です。`details.issues` にすべて出ます。
402 insufficient_creditsレンダーに必要なクレジットが足りません。追加するかテストキーで。
429 rate_limit_exceeded呼び出しが多すぎます。`Retry-After` 秒待って再試行してください。
502 upstream_error依存している事業者側の障害です。バックオフして再試行を。
{
  "error": {
    "type": "permission_error",
    "code": "insufficient_scope",
    "message": "This API key is missing the required scope: videos:execute.",
    "details": {
      "required_scopes": ["videos:execute"],
      "granted_scopes": ["videos:read", "videos:write"]
    },
    "hint": "`details.required_scopes` lists what is missing. Call GET /api/v1 to see what this key does hold, then re-scope it at /app/settings/api-keys.",
    "retryable": false,
    "request_id": "req_8f2c41d0a95b",
    "doc_url": "https://autostud.ai/docs/api/errors#insufficient_scope"
  }
}

エラーコード

Webhook

ポーリングをやめる

レンダーは数分かかります。向こうから来させましょう。

署名付き、検証は10行

`X-Autostud-Signature: t=<unix>,v1=<hex>` は `"<timestamp>.<生のボディ>"` に対する HMAC-SHA256 です。パースする前に、生のボディで検証してください。

再送はこちらで

約2時間のあいだに5回試行し、配信レコードは1回目の前に書き込まれます。20回連続で失敗したエンドポイントは、叩き続けずに無効化します。

配信IDで重複排除

各試行は `X-Autostud-Delivery` を持ちます。同じIDは同じイベント。処理の主キーとして扱ってください。

import crypto from 'node:crypto'

// The header is "t=<unix>,v1=<hex>" and the signed string is "<t>.<raw body>".
// Raw body: parse it AFTER verifying, never re-serialize before.
export function verify(raw_body, header, secret, tolerance = 300) {
  const parts = Object.fromEntries(
    String(header || '').split(',').map((entry) => entry.split('=').map((s) => s.trim()))
  )

  const timestamp = Number(parts.t)
  if (!Number.isFinite(timestamp)) return false
  if (Math.abs(Date.now() / 1000 - timestamp) > tolerance) return false

  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${timestamp}.${raw_body}`)
    .digest('hex')

  const received = String(parts.v1 || '')
  if (received.length !== expected.length) return false

  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received))
}

app.post('/hooks/autostud', express.raw({ type: '*/*' }), (req, res) => {
  const raw = req.body.toString('utf8')

  if (!verify(raw, req.get('X-Autostud-Signature'), process.env.AUTOSTUD_WEBHOOK_SECRET)) {
    return res.status(400).send('bad signature')
  }

  // Deliveries can repeat: deduplicate on this id before doing any work.
  const delivery_id = req.get('X-Autostud-Delivery')
  const event = JSON.parse(raw)

  if (event.event === 'render.completed') {
    console.log(event.data.render_url)
  }

  res.status(200).send('ok')
})
得られるもの

なぜ15回ではなく1回で済むのか

作り直すのが大変な部分こそ、こちらが運用している部分です。

単語単位のタイミング

各単語が自分の開始と終了を持つので、ハイライトが音節に乗ります。文単位のタイミングこそ、自動字幕が遅れて見える原因です。

116スタイル、文字列ひとつ

落ち着いた放送用から、跳ねるハイライト系まで。プリセットがフォント・縁取り・色・アニメーションをまとめて、キャンバスに合わせて調整します。

強調はAIが選ぶ

2回目のパスが文字起こしを読み、意味を担う語を印します。つなぎ言葉は静かなまま。真偽値ひとつでオフにできます。

2人の話者、2色

話者分離はフラグひとつ。インタビューは声ごとに色が分かれて返るので、音がなくても誰が話しているか分かります。

ダッシュボードと同じオブジェクト

API で字幕を付けた動画も、エディタで普通に開けます。単語を手で直して再レンダーし、そのまま自動化を続けられます。両方の経路が同じドキュメントを書きます。

再試行前提の設計

冪等キー、型付きエラー、テストキー、署名付き Webhook、30日分のリクエストログ。APIの地味な半分、つまり深夜3時に効いてくる部分です。

FAQ

開発者から実際に届く質問

できません。これは意図的で、APIはURLを受け取ります。当社サーバーが読める場所(自社バケット、CDN、署名付きリンク)に置き、`media_url` に渡してください。ダッシュボードからアップロードしたファイルには、そのまま使えるURLがあります。

今はできません。字幕は mp4 に焼き込まれます(ショート動画のプラットフォームが必要とするのはこちらです)。単語とタイミングのリストは動画に保存されるので、別ファイルはAPIの返り値から自前で生成できます。

レンダーは長さに関係なく固定20クレジットです。文字起こしと強調パスは、他のAI呼び出しと同じようにワークスペースに記録され、`GET /api/v1/usage` で期間内の消費を確認できます。

秒ではなく分単位です。リクエスト内ではなくワーカー群で走ります。だからこそ `render.completed` があります。接続を開いたままにせず、購読してください。

はい。`restyle_only: true` と別の `style_preset` で `subtitles.generate` を呼び直すと、動画に保存済みの単語を再利用するので、二重に文字起こしされません。

Whisper が言語を自動判別し、字幕は話されている言語で返ります。宣言は不要です。検出された言語は応答に含まれるので、そこで分岐できます。

自社のバックエンドから字幕付き動画を出す

キーを作ってクイックスタートを実行すれば、最初の字幕付き mp4 まで数分です。

安全な決済
すぐに利用可能
いつでも解約可能