Send en video-URL og få en mp4 tilbage med undertekster brændt ind ord for ord. Whisper timer hvert ord, en AI-gennemgang vælger dem, der skal fremhæves, og renderingen kører på vores workerflåde.
POSThttps://autostud.ai/api/v1/actions/subtitles.generateIndsæt, sæt din nøgle, kør. Intet her er pseudokode.
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 — autentificér med `Authorization: Bearer sk_live_…`. En `sk_test_`-nøgle går præcis samme vej og stopper, før noget bliver brugt.
Seks trin, fire af dem ét kald hver.
Dashboard, Indstillinger, API-nøgler. Tag forudindstillingen "Automation", hvis du ikke vil vælge scopes i hånden: den dækker videoer, renderinger og filer. Hemmeligheden vises én gang. `sk_live_` bruger, `sk_test_` validerer hele kaldet og stopper før skrivningen.
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"Der er ingen upload-endpoint: API'et læser en URL. Din bucket, dit CDN, et signeret link — alt vores servere kan hente. At registrere den i arbejdsområdets bibliotek er valgfrit og ændrer intet i flowet.
# 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` returnerer det `video_id`, alt andet hænger på. Send en `Idempotency-Key`, så giver et gentaget kald det første svar i stedet for at oprette et projekt mere.
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` klarer hele arbejdet på serveren: Whisper transskriberer med ordpræcis timing, en AI-gennemgang markerer ordene, der skal fremhæves, og en af 116 stilarter lægges på. Svaret rummer antal ord, den præcise længde og det registrerede sprog.
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` lægger jobbet på workerflåden og svarer straks med `render_id`. En rendering koster 20 credits, uanset længde.
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"
}'Abonnér på `render.completed`, så bliver den færdige URL sendt signeret til dig. Foretrækker du selv at hente: list videoens renderinger og læs `render_status`, indtil der står `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.Scopes er det, nøglen skal bære, ikke det du sender.
| Kald | Scope | Hvad det gør |
|---|---|---|
| GET /api/v1 | - | Discovery: hvad nøglen må, dens grænser og dens forbrug. |
| POST /api/v1/actions/videos.create | videos:write | Opretter videoprojektet og returnerer dets id. |
| POST /api/v1/actions/subtitles.generate | videos:execute | Transskriberer, fremhæver, styler og gemmer undertekstsporet. |
| POST /api/v1/actions/renders.create | renders:execute | Sætter renderingen i kø på workerflåden. 20 credits. |
| GET /api/v1/renders?video_id=… | renders:read | En videos renderinger, nyeste først, med status og URL. |
| POST /api/v1/webhooks | webhooks:write | Registrerer en https-endpoint og returnerer dens signeringsnøgle, én gang. |
Send ét som `style_preset`. Hvert forvalg sætter skrifttype, kontur, accentfarve og animation på én gang — der er ikke mere at konfigurere.
default4 ord · simplebold3 ord · simpleimpact3 ord · focus_on_one_wordbeast1 ord · focus_on_one_wordkaraoke5 ord · focus_on_one_wordkaraoke_fill5 ord · karaokeneon4 ord · progressively_visibleminimal6 ord · simplepop5 ord · progressively_visiblepill5 ord · simplecinematic9 ord · simpleAlle fejl har samme form: en stabil `code` at forgrene på, et `hint` der udpeger kaldet som retter det, og et `request_id` at henvise til. Hele ordlisten ligger på /docs/api/errors.
| Kode | Hvad det betyder |
|---|---|
| 401 missing_credentials | Ingen nøgle på kaldet, eller en vi ikke kender. |
| 403 insufficient_scope | Nøglen mangler et scope; `details.required_scopes` nævner det. |
| 422 validation_failed | Et felt er forkert; `details.issues` lister dem alle. |
| 402 insufficient_credits | For få credits til renderingen. Fyld op, eller brug en testnøgle. |
| 429 rate_limit_exceeded | For mange kald. Vent `Retry-After` sekunder, og prøv igen. |
| 502 upstream_error | En leverandør vi afhænger af fejlede. Prøv igen med 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"
}
}En rendering tager minutter. Lad den komme til dig.
`X-Autostud-Signature: t=<unix>,v1=<hex>` er en HMAC-SHA256 over `"<timestamp>.<rå body>"`. Verificér mod den rå body, før du parser den.
Fem forsøg over cirka to timer, og leveringsrækken skrives før det første. En endpoint, der fejler tyve gange i træk, bliver slået fra i stedet for hamret.
Hvert forsøg bærer `X-Autostud-Delivery`. Samme id betyder samme hændelse: behandl det som primærnøgle for det arbejde, du sætter i gang.
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 dele, der er svære at bygge selv, er dem vi driver.
Hvert ord bærer sin egen start og slutning, så fremhævningen lander på stavelsen. Sætningsbaseret timing er grunden til, at de fleste automatiske undertekster føles forsinkede.
Fra rene broadcast-undertekster til det hoppende, fremhævede look. Forvalget sætter skrifttype, kontur, farve og animation samlet, skaleret til dit lærred.
En anden gennemgang læser transskriptionen og markerer ordene, der bærer meningen. Fyldordene får lov at være i fred. En boolean slår det fra.
Diarisering er et flag. Et interview kommer tilbage med hver stemme i sin egen farve, så seeren ved hvem der taler uden lyd.
En video tekstet via API'et åbner i editoren som enhver anden. Ret et ord i hånden, render igen, bliv ved med at automatisere — begge veje skriver det samme dokument.
Idempotensnøgler, typede fejl, testnøgler, signerede webhooks og en forespørgselslog på 30 dage. Den kedelige halvdel af et API, altså den man mærker klokken tre om natten.
Nej, og det er med vilje: API'et tager en URL. Host videoen et sted, vores servere kan læse den — din egen bucket, et CDN, et signeret link — og send den som `media_url`. Filer uploadet via dashboardet har allerede en brugbar URL.
Ikke i dag. Underteksterne renderes ind i mp4'en, hvilket er det, kortformatplatformene har brug for. Ordlisten med timings ligger på videoen, så en separat fil er en omdannelse, du selv kan lave ud fra det, API'et returnerer.
En rendering er 20 credits, fast, uanset længde. Transskriptionen og accentgennemgangen logges i dit arbejdsområde som ethvert andet AI-kald, og `GET /api/v1/usage` viser, hvad en nøgle har brugt i perioden.
Minutter, ikke sekunder: den kører på en workerflåde, ikke inde i kaldet. Præcis derfor findes `render.completed` — abonnér i stedet for at holde en forbindelse åben.
Ja. Kald `subtitles.generate` igen med `restyle_only: true` og et andet `style_preset`: ordene, der allerede ligger på videoen, genbruges, så intet transskriberes to gange.
Whisper registrerer sproget selv, og underteksterne kommer på det, der bliver talt — intet at angive. Det registrerede sprog står i svaret, hvis du vil forgrene på det.
De kører alle i browseren, og du behøver ingen konto for at prøve.
Lav ethvert emne om til en quizvideo
Quizvideoer i 16:9 eller som Shorts
Lav en ordliste om til en sprogvideo
Lav tweets og X-opslag om til videoer
Lav enhver sang om til en karaokevideo
Lav en Reddit-tråd om til en short
Lav et regneark om til en ranglistevideo
Lav et TikTok-kommentarspor om til en sangvideo
Lav virale frugtquizvideoer med AI
Opret en nøgle, kør hurtigstarten, og den første tekstede mp4 er minutter væk.