Stuur een video-URL en krijg een mp4 terug met woord-voor-woord ingebrande ondertitels. Whisper timet elk woord, een AI-pass kiest de accenten, en het renderen draait op onze worker-vloot.
POSThttps://autostud.ai/api/v1/actions/subtitles.generatePlakken, sleutel invullen, uitvoeren. Niets hiervan is pseudocode.
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)Basis-URL: https://autostud.ai/api/v1 — authenticeer met `Authorization: Bearer sk_live_…`. Een `sk_test_`-sleutel legt exact dezelfde weg af en stopt vlak voor er iets wordt uitgegeven.
Zes stappen, waarvan vier één request.
Dashboard, Instellingen, API-sleutels. Neem de preset "Automation" als je scopes niet met de hand wilt kiezen: die dekt video’s, renders en bestanden. Het secret zie je één keer. `sk_live_` geeft uit, `sk_test_` valideert het hele request en stopt voor de schrijfactie.
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"Er is geen upload-endpoint: de API leest een URL. Je eigen bucket, je CDN, een ondertekende link — alles wat onze servers kunnen ophalen. Registreren in de werkruimtebibliotheek is optioneel en verandert niets aan de flow.
# 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"
}'`videos.create` geeft de `video_id` terug waar al het andere aan hangt. Stuur een `Idempotency-Key` en een herhaald request geeft het eerste antwoord in plaats van een tweede project.
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"
}'`subtitles.generate` doet het hele werk serverside: Whisper transcribeert met woordtiming, een AI-pass markeert de woorden met nadruk, en een van 116 stijlen wordt toegepast. Terug krijg je het aantal woorden, de exacte duur en de gedetecteerde taal.
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
}'`renders.create` zet de job op de worker-vloot en antwoordt meteen met de `render_id`. Een render kost 20 credits, ongeacht de lengte.
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"
}'Abonneer je op `render.completed` en de definitieve URL wordt ondertekend naar je gestuurd. Wil je liever zelf ophalen: lijst de renders van de video en lees `render_status` tot die `done` zegt.
# 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.Scopes zijn wat de sleutel moet dragen, niet wat je meestuurt.
| Call | Scope | Wat het doet |
|---|---|---|
| GET /api/v1 | - | Discovery: wat deze sleutel mag, zijn limieten en zijn verbruik. |
| POST /api/v1/actions/videos.create | videos:write | Maakt het videoproject en geeft de id terug. |
| POST /api/v1/actions/subtitles.generate | videos:execute | Transcribeert, markeert, stijlt en bewaart de ondertitelspoor. |
| POST /api/v1/actions/renders.create | renders:execute | Zet de render op de worker-vloot. 20 credits. |
| GET /api/v1/renders?video_id=… | renders:read | De renders van een video, nieuwste eerst, met status en URL. |
| POST /api/v1/webhooks | webhooks:write | Registreert een https-endpoint en geeft het signing secret terug, één keer. |
Geef er één mee als `style_preset`. Elke preset zet lettertype, outline, accentkleur en animatie in één keer — er valt verder niets te configureren.
default4 woorden · simplebold3 woorden · simpleimpact3 woorden · focus_on_one_wordbeast1 woorden · focus_on_one_wordkaraoke5 woorden · focus_on_one_wordkaraoke_fill5 woorden · karaokeneon4 woorden · progressively_visibleminimal6 woorden · simplepop5 woorden · progressively_visiblepill5 woorden · simplecinematic9 woorden · simpleElke fout heeft dezelfde vorm: een stabiele `code` om op te vertakken, een `hint` die de call noemt die het oplost, en een `request_id` om te citeren. Het volledige vocabulaire staat op /docs/api/errors.
| Code | Wat het betekent |
|---|---|
| 401 missing_credentials | Geen sleutel op het verzoek, of een die we niet kennen. |
| 403 insufficient_scope | De sleutel mist een scope; `details.required_scopes` noemt hem. |
| 422 validation_failed | Een veld klopt niet; `details.issues` somt ze allemaal op. |
| 402 insufficient_credits | Te weinig credits voor de render. Vul aan, of gebruik een testsleutel. |
| 429 rate_limit_exceeded | Te veel calls. Wacht `Retry-After` seconden en probeer opnieuw. |
| 502 upstream_error | Een provider waarvan we afhangen viel uit. Opnieuw met 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"
}
}Een render duurt minuten. Laat hem naar je toe komen.
`X-Autostud-Signature: t=<unix>,v1=<hex>` is een HMAC-SHA256 over `"<timestamp>.<ruwe body>"`. Verifieer tegen de ruwe body, voordat je hem parset.
Vijf pogingen over ongeveer twee uur, met de bezorgrij vóór de eerste geschreven. Een endpoint dat twintig keer op rij faalt wordt uitgezet in plaats van platgelegd.
Elke poging draagt `X-Autostud-Delivery`. Zelfde id is hetzelfde event: behandel het als de primaire sleutel van het werk dat je start.
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')
})De stukken die moeilijk na te bouwen zijn, draaien bij ons.
Elk woord heeft zijn eigen begin en eind, dus de highlight valt op de lettergreep. Timing per zin is precies waarom de meeste automatische ondertitels te laat aanvoelen.
Van strakke broadcast-ondertitels tot de stuiterende highlight-look. De preset zet lettertype, outline, kleur en animatie samen, geschaald op je canvas.
Een tweede pass leest het transcript en markeert de woorden die de betekenis dragen. Stopwoorden blijven rustig. Eén boolean zet het uit.
Diarisatie is een vlag. Een interview komt terug met elke stem in zijn eigen kleur, zodat een kijker zonder geluid weet wie er praat.
Een via de API ondertitelde video opent in de editor als elke andere. Corrigeer een woord met de hand, render opnieuw, blijf automatiseren — beide paden schrijven hetzelfde document.
Idempotency-keys, getypeerde fouten, testsleutels, ondertekende webhooks en een requestlog van 30 dagen. De saaie helft van een API, oftewel de helft die je om 3 uur ’s nachts voelt.
Nee, en dat is bewust: de API neemt een URL. Host de video waar onze servers hem kunnen lezen — je eigen bucket, een CDN, een ondertekende link — en geef hem mee als `media_url`. Bestanden die je via het dashboard uploadt hebben al een bruikbare URL.
Vandaag niet. De ondertitels worden in de mp4 gerenderd, wat kortevideoplatforms nodig hebben. De woordenlijst met timings staat op de video, dus een los bestand is een omzetting die je zelf kunt doen met wat de API teruggeeft.
Een render is 20 credits, vast, ongeacht de lengte. De transcriptie en de nadrukpass worden in je werkruimte gelogd zoals elke andere AI-call, en `GET /api/v1/usage` laat zien wat een sleutel deze periode heeft verbruikt.
Minuten, geen seconden: hij draait op een worker-vloot, niet in het request. Precies daarvoor bestaat `render.completed` — abonneer je in plaats van een verbinding open te houden.
Ja. Roep `subtitles.generate` opnieuw aan met `restyle_only: true` en een andere `style_preset`: de woorden die al op de video staan worden hergebruikt, dus niets wordt twee keer getranscribeerd.
Whisper detecteert de taal zelf en de ondertitels komen terug in wat er gesproken wordt — niets te declareren. De gedetecteerde taal zit in het antwoord, zodat je erop kunt vertakken.
Ze draaien allemaal in de browser, zonder account om te proberen.
Maak van elk onderwerp een quizvideo
Quizvideo's in 16:9 of als Shorts
Maak van een woordenlijst een taalvideo
Zet tweets en X-posts om in video's
Maak van elk nummer een karaokevideo
Maak van een Reddit-thread een short
Maak van een spreadsheet een ranglijstvideo
Maak van een TikTok-reactieveld een liedjevideo
Maak virale fruitquizvideo's met AI
Maak een sleutel, draai de quickstart, en de eerste ondertitelde mp4 is minuten weg.