API REST|API Napisów do Wideo

Dodaj napisy do każdego wideo
trzema wywołaniami API

Wyślij URL wideo, odbierz mp4 z napisami wypalonymi słowo po słowie. Whisper synchronizuje każde słowo, przebieg AI wybiera te do podkreślenia, a render idzie na naszą flotę workerów.

POSThttps://autostud.ai/api/v1/actions/subtitles.generate
Szybki start

Cała ścieżka w jednym pliku

Wklej, ustaw klucz, uruchom. Nic tu nie jest pseudokodem.

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)

Adres bazowy: https://autostud.ai/api/v1 — uwierzytelnianie przez `Authorization: Bearer sk_live_…`. Klucz `sk_test_` przechodzi dokładnie tę samą ścieżkę i zatrzymuje się przed wydaniem czegokolwiek.

Krok po kroku

Co naprawdę musisz zrobić

Sześć kroków, cztery z nich to jedno żądanie.

  1. 1

    Utwórz klucz API

    Panel, Ustawienia, Klucze API. Wybierz preset „Automation”, jeśli nie chcesz ustawiać scope’ów ręcznie: obejmuje wideo, rendery i pliki. Sekret pokazuje się raz. `sk_live_` wydaje, `sk_test_` waliduje całe żądanie i zatrzymuje się przed zapisem.

    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

    Umieść wideo pod adresem URL

    Nie ma endpointu do wysyłki pliku: API czyta URL. Twój bucket, twoje CDN, podpisany link — cokolwiek nasze serwery pobiorą. Zapis w bibliotece przestrzeni jest opcjonalny i niczego nie zmienia.

    # 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

    Utwórz projekt wideo

    `videos.create` zwraca `video_id`, do którego podpina się reszta. Wyślij `Idempotency-Key`, a ponowione żądanie zwróci pierwszą odpowiedź zamiast tworzyć drugi projekt.

    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

    Dodaj napisy

    `subtitles.generate` robi całą robotę po stronie serwera: Whisper transkrybuje z dokładnością do słowa, przebieg AI zaznacza słowa do podkreślenia, a jeden z 116 stylów zostaje nałożony. W odpowiedzi masz liczbę słów, dokładny czas i wykryty język.

    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

    Zakolejkuj render

    `renders.create` wrzuca zadanie na flotę workerów i od razu odpowiada `render_id`. Render kosztuje 20 kredytów, niezależnie od długości.

    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

    Odbierz mp4

    Subskrybuj `render.completed`, a gotowy URL przyjdzie do ciebie podpisany. Jeśli wolisz odpytywać, wylistuj rendery wideo i czytaj `render_status`, aż pokaże `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.
Dokumentacja

Wszystkie wywołania z tej strony

Scope to to, co musi mieć klucz, a nie to, co wysyłasz.

WywołanieScopeCo robi
GET /api/v1-Discovery: co potrafi ten klucz, jakie ma limity i zużycie.
POST /api/v1/actions/videos.createvideos:writeTworzy projekt wideo i zwraca jego identyfikator.
POST /api/v1/actions/subtitles.generatevideos:executeTranskrybuje, podkreśla, styluje i zapisuje ścieżkę napisów.
POST /api/v1/actions/renders.createrenders:executeKolejkuje render na flocie workerów. 20 kredytów.
GET /api/v1/renders?video_id=…renders:readRendery danego wideo, od najnowszego, ze statusem i URL-em.
POST /api/v1/webhookswebhooks:writeRejestruje endpoint https i raz zwraca jego sekret podpisujący.

Dostępne style

Podaj jeden w `style_preset`. Każdy ustawia naraz font, obrys, kolor akcentu i animację — nie ma nic więcej do konfigurowania.

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

Co warto wiedzieć przed kodowaniem

  • Limity są per klucz i wracają w nagłówkach: `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `Retry-After` przy 429.
  • `Idempotency-Key` przy każdym POST czyni ponowienie bezpiecznym przez 24 godziny; pierwsza odpowiedź wraca bez zmian.
  • Klucz `sk_test_` przechodzi uwierzytelnianie, scope’y, limity i walidację, po czym odpowiada `simulated: true` bez zapisu i bez wydatku.
  • Błędy są typowane: `invalid_request`, `insufficient_credits`, `rate_limit_exceeded`, `upstream_error` — rozgałęziaj po kodzie, nigdy po treści.

Kiedy się nie uda

Każdy błąd ma ten sam kształt: stabilny `code` do rozgałęzień, `hint` wskazujący wywołanie, które to naprawi, i `request_id` do zacytowania. Pełny słownik jest na /docs/api/errors.

KodCo oznacza
401 missing_credentialsBrak klucza w żądaniu albo klucz nieznany.
403 insufficient_scopeKluczowi brakuje scope; `details.required_scopes` go nazywa.
422 validation_failedPole jest niepoprawne; `details.issues` wylicza każde z nich.
402 insufficient_creditsZa mało kredytów na render. Doładuj albo użyj klucza testowego.
429 rate_limit_exceededZa dużo wywołań. Odczekaj `Retry-After` sekund i ponów.
502 upstream_errorDostawca, od którego zależymy, zawiódł. Ponów z backoffem.
{
  "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"
  }
}

Kody błędów

Webhooki

Przestań odpytywać

Render trwa minuty. Niech sam do ciebie przyjdzie.

Podpisane, do sprawdzenia w dziesięciu linijkach

`X-Autostud-Signature: t=<unix>,v1=<hex>` to HMAC-SHA256 z `"<timestamp>.<surowe ciało>"`. Weryfikuj na surowym ciele, zanim je sparsujesz.

Ponawiane za ciebie

Pięć prób w ciągu około dwóch godzin, a wiersz dostawy zapisuje się przed pierwszą. Endpoint, który zawiedzie dwadzieścia razy z rzędu, zostaje wyłączony, a nie zasypywany.

Deduplikuj po id dostawy

Każda próba niesie `X-Autostud-Delivery`. To samo id to to samo zdarzenie: traktuj je jak klucz główny pracy, którą uruchamiasz.

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')
})
Co dostajesz

Dlaczego to jedno wywołanie, a nie piętnaście

Trudne do odtworzenia kawałki to te, które my utrzymujemy.

Synchronizacja co do słowa

Każde słowo ma własny początek i koniec, więc podświetlenie trafia w sylabę. Synchronizacja zdaniami sprawia, że większość automatycznych napisów wydaje się spóźniona.

116 stylów, jeden string

Od czystych napisów telewizyjnych po skaczący, podświetlany look. Preset ustawia font, obrys, kolor i animację razem, w skali twojego kadru.

AI wybiera akcenty

Drugi przebieg czyta transkrypcję i zaznacza słowa niosące sens. Wypełniacze zostają spokojne. Wyłączasz to jednym booleanem.

Dwa głosy, dwa kolory

Diaryzacja to flaga. Wywiad wraca z każdym głosem w swoim kolorze, więc widz wie, kto mówi, nawet bez dźwięku.

Te same obiekty co w panelu

Wideo otytułowane przez API otwiera się w edytorze jak każde inne. Popraw słowo ręcznie, zrenderuj ponownie, automatyzuj dalej — obie drogi piszą ten sam dokument.

Zbudowane pod ponowienia

Klucze idempotencji, typowane błędy, klucze testowe, podpisane webhooki i 30-dniowy log żądań. Nudna połowa API — czyli ta, którą czuć o trzeciej w nocy.

FAQ

Pytania, które naprawdę dostajemy od programistów

Nie i jest to celowe: API przyjmuje URL. Postaw wideo tam, gdzie nasze serwery je odczytają — twój bucket, CDN, podpisany link — i podaj je w `media_url`. Pliki wgrane z panelu mają już gotowy URL.

Dziś nie. Napisy są wypalane w mp4, bo tego wymagają platformy krótkiego wideo. Lista słów z czasami zostaje zapisana na wideo, więc osobny plik to przekształcenie, które zrobisz u siebie z tego, co zwraca API.

Render to 20 kredytów, na stałe, niezależnie od długości. Transkrypcja i przebieg podkreśleń są logowane w twojej przestrzeni jak każde inne wywołanie AI, a `GET /api/v1/usage` pokazuje, ile klucz wydał w okresie.

Minuty, nie sekundy: idzie na flotę workerów, nie do żądania. Dokładnie po to jest `render.completed` — subskrybuj zamiast trzymać otwarte połączenie.

Tak. Wywołaj `subtitles.generate` ponownie z `restyle_only: true` i innym `style_preset`: użyje słów już zapisanych na wideo, więc nic nie jest transkrybowane dwa razy.

Whisper sam wykrywa język, a napisy wracają w tym, którym się mówi — niczego nie deklarujesz. Wykryty język jest w odpowiedzi, jeśli chcesz się na nim rozgałęzić.

Wypuszczaj wideo z napisami ze swojego backendu

Utwórz klucz, uruchom quickstart — pierwsze mp4 z napisami dzieli od ciebie kilka minut.

Bezpieczne płatności
Natychmiastowy dostęp
Anuluj kiedy chcesz