REST API|영상 자막 API

어떤 영상에도 자막을
API 호출 세 번으로

영상 URL을 보내면 단어 단위 자막이 입혀진 mp4가 돌아옵니다. Whisper가 단어마다 타이밍을 잡고, AI가 강조할 단어를 고르며, 렌더링은 저희 워커 플릿에서 돌아갑니다.

POSThttps://autostud.ai/api/v1/actions/subtitles.generate
퀵스타트

전체 흐름을 한 파일로

붙여넣고, 키만 넣고, 실행하세요. 여기에 의사코드는 없습니다.

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_` 키는 완전히 같은 경로를 지나고 소모 직전에 멈춥니다.

단계별

실제로 해야 하는 일

여섯 단계, 그중 네 개는 요청 한 번입니다.

  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`를 보내면 재시도해도 두 번째 프로젝트가 생기지 않고 첫 응답이 돌아옵니다.

    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가지 스타일 중 하나가 적용됩니다. 응답에는 단어 수, 정확한 길이, 감지된 언어가 담깁니다.

    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`를 돌려줍니다. 렌더 한 번은 길이와 무관하게 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영상 프로젝트를 만들고 식별자를 반환합니다.
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`에 하나만 넘기면 됩니다. 각 프리셋이 폰트·외곽선·강조색·애니메이션을 한꺼번에 정하므로 따로 설정할 것이 없습니다.

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

에러 코드

웹훅

폴링은 그만

렌더는 몇 분 걸립니다. 결과가 오게 하세요.

서명되어 있고, 열 줄이면 검증

`X-Autostud-Signature: t=<unix>,v1=<hex>`는 `"<timestamp>.<원본 본문>"`에 대한 HMAC-SHA256입니다. 파싱하기 전에 원본 본문으로 검증하세요.

재시도는 저희가

약 두 시간에 걸쳐 다섯 번 시도하고, 전송 레코드는 첫 시도 전에 기록됩니다. 스무 번 연속 실패한 엔드포인트는 계속 두드리지 않고 비활성화합니다.

전송 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')
})
무엇을 얻나

왜 열다섯 번이 아니라 한 번인가

다시 만들기 어려운 부분이 바로 저희가 운영하는 부분입니다.

단어 단위 타이밍

단어마다 시작과 끝이 있어 하이라이트가 음절에 붙습니다. 문장 단위 타이밍이 대부분의 자동 자막을 늦어 보이게 만듭니다.

116가지 스타일, 문자열 하나

깔끔한 방송용부터 튀는 하이라이트 스타일까지. 프리셋이 폰트·외곽선·색·애니메이션을 함께 잡고 캔버스에 맞춰 스케일합니다.

강조는 AI가 고른다

두 번째 패스가 전사를 읽고 의미를 지닌 단어를 표시합니다. 군더더기 말은 조용히 둡니다. 불리언 하나로 끌 수 있습니다.

화자 둘, 색 둘

화자 분리는 플래그 하나입니다. 인터뷰는 목소리마다 색이 달라져 돌아오므로, 소리 없이도 누가 말하는지 압니다.

대시보드와 같은 객체

API로 자막을 넣은 영상도 에디터에서 똑같이 열립니다. 단어를 손으로 고치고 다시 렌더하고, 자동화는 계속 — 두 경로가 같은 문서를 씁니다.

재시도를 전제로

멱등 키, 타입 있는 에러, 테스트 키, 서명된 웹훅, 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까지 몇 분입니다.

안전한 결제
즉시 이용
언제든 해지