API REST|API Sottotitoli Video

Sottotitola qualsiasi video
con tre chiamate API

Invia l'URL di un video e ricevi un mp4 con i sottotitoli impressi parola per parola. Whisper sincronizza ogni parola, una passata di IA sceglie quelle da evidenziare e il rendering gira sulla nostra flotta di worker.

POSThttps://autostud.ai/api/v1/actions/subtitles.generate
Avvio rapido

Tutto il percorso, in un solo file

Incolla, metti la tua chiave, esegui. Qui non c'è pseudocodice.

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 di base: https://autostud.ai/api/v1 — autenticazione con `Authorization: Bearer sk_live_…`. Una chiave `sk_test_` percorre esattamente la stessa strada e si ferma prima di spendere.

Passo per passo

Cosa devi fare davvero

Sei passaggi, quattro dei quali una sola richiesta.

  1. 1

    Creare una chiave API

    Dashboard, Impostazioni, Chiavi API. Scegli il preset «Automation» se non vuoi selezionare gli scope a mano: copre video, render e file. Il segreto viene mostrato una volta sola. `sk_live_` spende, `sk_test_` valida tutta la richiesta e si ferma prima della scrittura.

    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

    Mettere il video dietro un URL

    Non esiste un endpoint di upload: l'API legge un URL. Il tuo bucket, la tua CDN, un link firmato — qualsiasi cosa i nostri server possano scaricare. Registrarlo nella libreria dello spazio è facoltativo e non cambia nulla.

    # 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

    Creare il progetto video

    `videos.create` restituisce il `video_id` a cui si aggancia tutto il resto. Manda un `Idempotency-Key` e una richiesta ripetuta restituisce la prima risposta invece di creare un secondo progetto.

    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

    Aggiungere i sottotitoli

    `subtitles.generate` fa tutto lato server: Whisper trascrive con la sincronia parola per parola, una passata di IA marca le parole da enfatizzare e viene applicato uno degli 116 stili. Risponde con il numero di parole, la durata esatta e la lingua rilevata.

    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

    Mettere in coda il render

    `renders.create` mette il job sulla flotta di worker e risponde subito con il `render_id`. Un render costa 20 crediti, qualunque sia la durata.

    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

    Ritirare l'mp4

    Iscriviti a `render.completed` e l'URL finale ti arriva firmato. Se preferisci interrogare tu, elenca i render del video e leggi `render_status` finché non dice `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.
Riferimento

Tutte le chiamate di questa pagina

Gli scope sono ciò che la chiave deve portare, non ciò che invii.

ChiamataScopeCosa fa
GET /api/v1-Discovery: cosa può fare questa chiave, i suoi limiti e i suoi consumi.
POST /api/v1/actions/videos.createvideos:writeCrea il progetto video e ne restituisce l'identificativo.
POST /api/v1/actions/subtitles.generatevideos:executeTrascrive, enfatizza, applica lo stile e salva la traccia di sottotitoli.
POST /api/v1/actions/renders.createrenders:executeMette il render in coda sulla flotta di worker. 20 crediti.
GET /api/v1/renders?video_id=…renders:readI render di un video, dal più recente, con stato e URL.
POST /api/v1/webhookswebhooks:writeRegistra un endpoint https e ne restituisce il segreto di firma, una volta.

Stili disponibili

Passane uno in `style_preset`. Ognuno imposta insieme font, contorno, colore d'accento e animazione — non c'è altro da configurare.

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

Da sapere prima di scrivere codice

  • I limiti di frequenza sono per chiave e arrivano negli header: `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `Retry-After` su un 429.
  • `Idempotency-Key` su qualsiasi POST rende sicuro un nuovo tentativo per 24 ore; la prima risposta viene ripetuta identica.
  • Una chiave `sk_test_` esercita autenticazione, scope, limiti e validazione, poi risponde `simulated: true` senza scrivere né spendere.
  • Gli errori sono tipizzati: `invalid_request`, `insufficient_credits`, `rate_limit_exceeded`, `upstream_error` — ramifica sul codice, mai sul messaggio.

Quando fallisce

Ogni errore ha la stessa forma: un `code` stabile su cui ramificare, un `hint` che nomina la chiamata che risolve e un `request_id` da citare. Il vocabolario completo è su /docs/api/errors.

CodiceChe cosa significa
401 missing_credentialsNessuna chiave nella richiesta, oppure una che non riconosciamo.
403 insufficient_scopeAlla chiave manca uno scope; `details.required_scopes` lo nomina.
422 validation_failedUn campo non è valido; `details.issues` li elenca tutti.
402 insufficient_creditsCrediti insufficienti per il render. Ricarica, o usa una chiave di test.
429 rate_limit_exceededTroppe chiamate. Aspetta `Retry-After` secondi e riprova.
502 upstream_errorUn provider da cui dipendiamo ha fallito. Riprova con backoff.
{
  "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"
  }
}

Codici di errore

Webhook

Smetti di fare polling

Un render dura minuti. Lascia che arrivi da solo.

Firmati, verificabili in dieci righe

`X-Autostud-Signature: t=<unix>,v1=<hex>` è un HMAC-SHA256 su `"<timestamp>.<corpo grezzo>"`. Verifica sul corpo grezzo, prima di fare il parsing.

Riprovati al posto tuo

Cinque tentativi in circa due ore, con la riga di consegna scritta prima del primo. Un endpoint che fallisce venti volte di fila viene disattivato invece di essere martellato.

Deduplica sull'id di consegna

Ogni tentativo porta `X-Autostud-Delivery`. Stesso id, stesso evento: trattalo come chiave primaria del lavoro che avvii.

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')
})
Cosa ottieni

Perché è una chiamata e non quindici

I pezzi difficili da rifare sono quelli che gestiamo noi.

Sincronia parola per parola

Ogni parola ha il suo inizio e la sua fine, così l'evidenziazione cade sulla sillaba. La sincronia per frase è ciò che fa sembrare in ritardo quasi tutti i sottotitoli automatici.

116 stili, una stringa

Dal sottotitolo broadcast pulito allo stile saltellante evidenziato. Il preset imposta font, contorno, colore e animazione insieme, in scala sul tuo canvas.

L'IA sceglie gli accenti

Una seconda passata legge la trascrizione e marca le parole che portano il significato. Le parole di riempimento restano calme. Un booleano la disattiva.

Due voci, due colori

La diarizzazione è un flag. Un'intervista torna con ogni voce nel suo colore, e chi guarda capisce chi parla anche senza audio.

Gli stessi oggetti della dashboard

Un video sottotitolato via API si apre nell'editor come qualunque altro. Correggi una parola a mano, rifai il render, continua ad automatizzare: le due strade scrivono lo stesso documento.

Fatta per essere riprovata

Chiavi di idempotenza, errori tipizzati, chiavi di test, webhook firmati e un log delle richieste di 30 giorni. La metà noiosa di un'API, cioè quella che si sente alle 3 di notte.

FAQ

Le domande che gli sviluppatori ci mandano davvero

No, ed è voluto: l'API prende un URL. Ospita il video dove i nostri server possono leggerlo — il tuo bucket, una CDN, un link firmato — e passalo in `media_url`. I file caricati dalla dashboard hanno già un URL utilizzabile.

Oggi no. I sottotitoli vengono impressi nell'mp4, che è quello che serve alle piattaforme di formato corto. L'elenco delle parole con la loro sincronia resta sul video: un file separato è una trasformazione che puoi fare tu da ciò che l'API restituisce.

Un render costa 20 crediti, fissi, qualunque sia la durata. La trascrizione e la passata di enfasi vengono registrate nel tuo spazio come ogni altra chiamata IA, e `GET /api/v1/usage` dice quanto ha speso una chiave nel periodo.

Minuti, non secondi: gira su una flotta di worker, non dentro la richiesta. È esattamente per questo che esiste `render.completed` — iscriviti invece di tenere una connessione aperta.

Sì. Richiama `subtitles.generate` con `restyle_only: true` e un altro `style_preset`: riusa le parole già salvate sul video, quindi nulla viene trascritto due volte.

Whisper rileva la lingua da solo e i sottotitoli tornano in quella parlata — niente da dichiarare. La lingua rilevata è nella risposta, se vuoi ramificare.

Pubblica video sottotitolati dal tuo backend

Crea una chiave, esegui il quickstart: il primo mp4 sottotitolato è a pochi minuti.

Pagamenti sicuri
Accesso istantaneo
Cancella quando vuoi