Übersicht
Die capWizard-API folgt einem einfachen Request-Response-Muster über HTTPS. Alle Endpoints liefern application/json, außer Datei-Endpoints (Preview-JPG, Result-MP4) — die liefern den jeweiligen Binärtyp.
Der typische Flow ist:
- Upload in 3 Stufen (init → chunk → finish) — chunked für große Dateien bis 10 GB
- Transcribe startet einen asynchronen Job — Whisper läuft im Worker
- Render startet einen zweiten Job, der die Captions ins Video brennt
- Poll Job-Status, sobald
stage="done"ist → Download via/api/result/{id}
Authentication
Aktuell sind die Endpoints öffentlich erreichbar — keine API-Keys, keine OAuth. Das passt zur Self-Service-Idee der Web-App, ist aber für Production-Pipelines ungenügend.
Authorization: Bearer <key>-Header schicken. Wenn du jetzt schon dagegen baust: API-Keys gibt's später unter /studio/.
Quickstart — 5 Schritte zum fertigen Video
Vollständiges End-to-End-Beispiel in Python. Setzt requests voraus (pip install requests).
{"ok":true} wenn die API läuft.upload_id, mit der du danach Chunks streamst.Query-Parameter
| Name | Type | Beschreibung |
|---|---|---|
| filename | string | Original-Dateiname (für Extension-Detection). Default: video.mp4 |
Query-Parameter
| Name | Type | Beschreibung |
|---|---|---|
| upload_id | stringrequired | Von /upload/init zurückgegeben |
| ext | stringrequired | Datei-Extension, ebenfalls aus init |
size > 10 GB wird der Upload abgebrochen (HTTP 413).job_id, dann pollst du /api/jobs/{id} bis stage="done".Request Body (JSON)
| Field | Type | Beschreibung |
|---|---|---|
| upload_id | stringrequired | Aus dem Upload-Flow |
| target | string | null | null/leer = Originalsprache (Whisper auto). "en" = Whisper-Translation (exakte Timing-Treue). "de", "es", "fr", "it", "pt" = lokale Übersetzung über CTranslate2 + proportionales Re-Timing. |
stage="done" ist.Du kannst dieses Array editieren (Eigennamen, Fachbegriffe) bevor du es in /api/render schickst.
Request Body (JSON)
| Field | Type | Beschreibung |
|---|---|---|
| upload_id | stringrequired | Aus Upload-Flow |
| words | arrayrequired | Array von {word, start, end} — siehe Words-Modell |
| style | object | Caption-Stil (Font, Größe, Farbe, …). Siehe Style-Objekt. Default = Movyng-Preset. |
| target | string | null | Wie bei /api/transcribe — wenn du übersetzen lassen willst. |
Mögliche Werte für stage: siehe Job-Stages.
video/mp4 mit Content-Disposition: attachment. Filename: capwizard_<jobid>.mp4.font_id, die du im Style-Objekt bei font referenzieren kannst.Query-Parameter
| Name | Type | Beschreibung |
|---|---|---|
| filename | string | Original-Dateiname (für die Family-Detection). Body ist die rohe Schrift-Datei. |
Request Body (JSON)
| Field | Type | Beschreibung |
|---|---|---|
| job_id | stringrequired | Render-Job-ID |
| stringrequired | RFC-konforme Adresse, max 254 Zeichen. Control-Chars werden rejected (Mail-Header-Injection-Schutz). |
Modell: Style-Objekt
Wird an /api/render übergeben. Alle Größen sind als Anteil der Video-Höhe definiert — damit derselbe Style auf 9:16, 1:1 und 16:9 konsistent sitzt.
| Field | Type | Beschreibung |
|---|---|---|
| mode | "single" | "phrase" | Ein Wort = klassisch TikTok-Stil. Phrase = 3 Wörter gleichzeitig, das aktive ist farbig hervorgehoben. |
| font | string | Schrift-Family (z.B. "Montserrat Black") oder Custom-Font-ID aus font/upload. |
| font_frac | float | Schriftgröße als Anteil der Höhe (0.05 = 5 %). |
| bold | boolean | Bold ja/nein. |
| all_caps | boolean | GROSSBUCHSTABEN. |
| pos_frac | float | Vertikale Position als Anteil der Höhe (0.78 = ca. 78 %, also unteres Drittel). |
| primary | ASS-color | Textfarbe im Format &HAABBGGRR (BGR mit Alpha, ASS-Konvention). &H00FFFFFF = volles Weiß. |
| effect | "outline" | "box" | Outline = klassische Kontur. Box = Hintergrund-Rechteck hinter dem Text. |
| outline_col | ASS-color | Konturfarbe (nur bei effect="outline"). |
| outline_frac | float | Konturdicke (Anteil der Höhe). |
| box_col | ASS-color | Box-Hintergrund (nur bei effect="box"). Alpha kontrolliert die Deckkraft. |
| shadow_frac | float | Schatten-Offset. |
| shadow_col | ASS-color | Schattenfarbe. |
| shadow_blur | boolean | Soften via libass-Blur. |
| highlight_col | ASS-color | Aktives Wort in Phrase-Mode. |
| phrase_words | integer | Wörter pro Fenster im Phrase-Mode (2–5, Default 3). |
Modell: Words-Format
Array von Objekten mit drei Feldern. Zeiten in Sekunden, float.
Du kannst die Reihenfolge oder Inhalte ändern (z.B. Eigennamen korrigieren) — Render baut die Caption-Spur entsprechend.
Modell: Job-Stages
/api/jobs/{id} liefert ein stage-Feld mit folgenden Werten:
| Stage | Beschreibung |
|---|---|
| queued | Job wartet auf den Worker. Modell-Cold-Start beim ersten Job kann ein paar Sekunden dauern. |
| extracting | Audio wird mit ffmpeg aus dem Video extrahiert. |
| transcribing | Whisper läuft. percent ist 0–95. |
| translating | EU-Sprachen-Übersetzung läuft (nur wenn target gesetzt und ungleich Quellsprache). |
| burning | ffmpeg brennt Captions in das Video ein. percent 0–99. |
| done | Fertig — Result kann abgerufen werden. |
| failed | Irgendwas ging schief. percent: 0. |
Limits
| Limit | Wert | Hinweis |
|---|---|---|
| Dateigröße | 10 GB | Pro Video. Hard-Limit, danach HTTP 413. |
| Videos pro Run | 1 | Batch-Verarbeitung im Studio-UI, API: pro Job ein Video. |
| Schrift-Dateigröße | 20 MB | TTF/OTF. |
| Allowed Extensions | .mp4 .mov .m4v .webm .mkv | Andere → 400. |
| Retention | 24 h | Alle Upload-/Result-Dateien werden automatisch gelöscht. |
| Rate-Limit | — | Aktuell ungerated. Phase 3 bringt 5 Jobs/h pro IP. |
Fehlercodes
| Code | Bedeutung |
|---|---|
| 400 | Ungültiger Request (Format nicht unterstützt, ungültige E-Mail, kaputtes Video, …) |
| 404 | Resource nicht gefunden (Upload-ID, Job-ID, Result, Schrift) |
| 413 | Payload too large — Datei > 10 GB oder Schrift > 20 MB |
| 422 | FastAPI Validation Error — Pydantic-Schema verletzt |
| 500 | Server-Fehler — unerwartet, bitte Issue melden |
| 503 | Service-Konfig fehlt (z.B. SMTP nicht konfiguriert bei notify/test) |
Fehler-Body folgt FastAPI-Standard: {"detail": "<Klartext>"}.