API REST|API Sous-titres Vidéo

Sous-titrez une vidéo
en trois appels API

Envoyez l'URL d'une vidéo, récupérez un mp4 avec les sous-titres incrustés mot à mot. Whisper cale chaque mot, une passe IA choisit ceux à mettre en avant, et le rendu tourne sur notre flotte de workers.

POSThttps://autostud.ai/api/v1/actions/subtitles.generate
Démarrage

Tout le parcours, dans un seul fichier

Collez, mettez votre clé, lancez. Rien ici n'est du pseudo-code.

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 de base : https://autostud.ai/api/v1 — authentification avec `Authorization: Bearer sk_live_…`. Une clé `sk_test_` parcourt exactement le même chemin et s'arrête avant de dépenser quoi que ce soit.

Étape par étape

Ce que vous avez réellement à faire

Six étapes, dont quatre tiennent en une requête.

  1. 1

    Créer une clé API

    Dashboard, Paramètres, Clés API. Prenez le préréglage « Automation » si vous ne voulez pas choisir les scopes à la main : il couvre vidéos, rendus et fichiers. Le secret n'est affiché qu'une fois. `sk_live_` dépense, `sk_test_` valide toute la requête et s'arrête avant l'écriture.

    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

    Mettre la vidéo derrière une URL

    Il n'y a pas d'endpoint d'upload : l'API lit une URL. Votre bucket, votre CDN, un lien signé — tout ce que nos serveurs peuvent récupérer. L'enregistrer dans la bibliothèque de l'espace est facultatif et ne change rien au reste.

    # 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

    Créer le projet vidéo

    `videos.create` renvoie le `video_id` auquel tout le reste se rattache. Envoyez un `Idempotency-Key` et une requête rejouée renvoie la première réponse au lieu de créer un second projet.

    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

    Ajouter les sous-titres

    `subtitles.generate` fait tout le travail côté serveur : Whisper transcrit avec un calage au mot, une passe IA marque les mots à accentuer, et un des 116 styles est appliqué. La réponse donne le nombre de mots, la durée exacte et la langue détectée.

    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

    Lancer le rendu

    `renders.create` place le job sur la flotte de workers et répond immédiatement avec le `render_id`. Un rendu coûte 20 crédits, quelle que soit la durée de la vidéo.

    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

    Récupérer le mp4

    Abonnez-vous à `render.completed` et l'URL finale vous est poussée, signée. Si vous préférez interroger, listez les rendus de la vidéo et lisez `render_status` jusqu'à `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.
Référence

Tous les appels de cette page

Les scopes sont ce que la clé doit porter, pas ce que vous envoyez.

AppelScopeCe que ça fait
GET /api/v1-Découverte : ce que la clé peut faire, ses limites et sa consommation.
POST /api/v1/actions/videos.createvideos:writeCrée le projet vidéo et renvoie son identifiant.
POST /api/v1/actions/subtitles.generatevideos:executeTranscrit, accentue, style et enregistre la piste de sous-titres.
POST /api/v1/actions/renders.createrenders:executeMet le rendu en file sur la flotte de workers. 20 crédits.
GET /api/v1/renders?video_id=…renders:readLes rendus d'une vidéo, du plus récent au plus ancien, avec statut et URL.
POST /api/v1/webhookswebhooks:writeEnregistre un endpoint https et renvoie son secret de signature, une fois.

Styles disponibles

Passez-en un dans `style_preset`. Chacun règle d'un coup la police, le contour, la couleur d'accent et l'animation — il n'y a rien d'autre à configurer.

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

À savoir avant de coder

  • Les limites de débit sont par clé et renvoyées en en-têtes : `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `Retry-After` sur un 429.
  • `Idempotency-Key` sur un POST rend un rejeu sûr pendant 24 heures ; la première réponse est renvoyée à l'identique.
  • Une clé `sk_test_` exerce l'authentification, les scopes, les limites et la validation, puis répond `simulated: true` sans rien écrire ni dépenser.
  • Les erreurs sont typées : `invalid_request`, `insufficient_credits`, `rate_limit_exceeded`, `upstream_error` — branchez sur le code, jamais sur le message.

Quand ça échoue

Toutes les erreurs ont la même forme : un `code` stable sur lequel brancher, un `hint` qui nomme l'appel qui corrige, et un `request_id` à citer. Le vocabulaire complet est sur /docs/api/errors.

CodeCe que ça veut dire
401 missing_credentialsAucune clé sur la requête, ou une clé inconnue.
403 insufficient_scopeIl manque un scope à la clé ; `details.required_scopes` le nomme.
422 validation_failedUn champ est invalide ; `details.issues` les liste tous.
402 insufficient_creditsPas assez de crédits pour le rendu. Rechargez, ou passez en clé de test.
429 rate_limit_exceededTrop d'appels. Attendez `Retry-After` secondes, puis réessayez.
502 upstream_errorUn fournisseur dont nous dépendons a échoué. Réessayez avec un 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"
  }
}

Codes d'erreur

Webhooks

Arrêtez de faire du polling

Un rendu prend des minutes. Laissez-le venir à vous.

Signés, vérifiables en dix lignes

`X-Autostud-Signature: t=<unix>,v1=<hex>` est un HMAC-SHA256 sur `"<timestamp>.<corps brut>"`. Vérifiez sur le corps brut, avant de le parser.

Réessayés pour vous

Cinq tentatives sur environ deux heures, avec la ligne de livraison écrite avant la première. Un endpoint qui échoue vingt fois d'affilée est désactivé plutôt que martelé.

Dédupliquez sur l'identifiant de livraison

Chaque tentative porte `X-Autostud-Delivery`. Même identifiant, même événement : traitez-le comme la clé primaire du travail que vous déclenchez.

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')
})
Ce que vous obtenez

Pourquoi c'est un appel et pas quinze

Les morceaux difficiles à refaire sont ceux que nous opérons.

Calage au mot

Chaque mot porte son début et sa fin, donc la surbrillance tombe sur la syllabe. Le calage à la phrase est ce qui fait que la plupart des sous-titres automatiques semblent en retard.

116 styles, une chaîne de caractères

Du sous-titre broadcast sobre au style rebondissant surligné. Le préréglage règle police, contour, couleur et animation ensemble, à l'échelle de votre canvas.

L'IA choisit les accents

Une seconde passe lit la transcription et marque les mots qui portent le sens. Les mots de remplissage restent calmes. Un booléen suffit à la désactiver.

Deux voix, deux couleurs

La diarisation est un simple flag. Une interview revient avec chaque voix dans sa couleur, et le spectateur sait qui parle même sans le son.

Les mêmes objets que le dashboard

Une vidéo sous-titrée par l'API s'ouvre dans l'éditeur comme n'importe quelle autre. Corrigez un mot à la main, relancez le rendu, continuez d'automatiser : les deux chemins écrivent le même document.

Pensée pour être rejouée

Clés d'idempotence, erreurs typées, clés de test, webhooks signés et un journal de requêtes sur 30 jours. La moitié ennuyeuse d'une API, celle qu'on sent à 3 h du matin.

FAQ

Les questions que les développeurs nous envoient vraiment

Non, et c'est volontaire : l'API prend une URL. Hébergez la vidéo là où nos serveurs peuvent la lire — votre bucket, un CDN, un lien signé — et passez-la dans `media_url`. Les fichiers envoyés depuis le dashboard ont déjà une URL utilisable.

Pas aujourd'hui. Les sous-titres sont incrustés dans le mp4, ce qu'attendent les plateformes de format court. La liste des mots et leur calage restent stockés sur la vidéo : un fichier séparé est une transformation que vous pouvez faire chez vous à partir de ce que l'API renvoie.

Un rendu, c'est 20 crédits, fixe, quelle que soit la durée. La transcription et la passe d'accentuation sont enregistrées dans votre espace comme tout autre appel IA, et `GET /api/v1/usage` indique ce qu'une clé a consommé sur la période.

Des minutes, pas des secondes : il tourne sur une flotte de workers, pas dans la requête. C'est exactement à ça que sert `render.completed` — abonnez-vous plutôt que de garder une connexion ouverte.

Oui. Rappelez `subtitles.generate` avec `restyle_only: true` et un autre `style_preset` : les mots déjà stockés sur la vidéo sont réutilisés, rien n'est transcrit deux fois.

Whisper détecte la langue tout seul et les sous-titres reviennent dans celle qui est parlée — rien à déclarer. La langue détectée est renvoyée dans la réponse, vous pouvez brancher dessus.

Produisez de la vidéo sous-titrée depuis votre propre backend

Créez une clé, lancez le quickstart, et le premier mp4 sous-titré est à quelques minutes.

Paiements sécurisés
Accès instantané
Annulation à tout moment