Owl3D Cloud API
Die API wandelt ein 2D-Video in Side-by-Side-3D um. Ihr Code holt einen Preis, lädt die Datei hoch, wartet auf den Auftrag und lädt das Ergebnis herunter. Sie führt dieselbe Umwandlung aus wie Owl3D Cloud.
Ein KI-Coding-Agent kann diese Seite als reinen Text unter /llms.txt lesen.
Vor dem Start
- Melden Sie sich unter app.owl3d.com an und bestätigen Sie Ihre E-Mail-Adresse.
- Wählen Sie einen Tarif oder kaufen Sie Credits. Ein Auftrag verbraucht zuerst die monatlichen Credits Ihres Tarifs, dann gekaufte Credits. Test-Credits zählen ebenfalls.
- Öffnen Sie API-Schlüssel und erstellen Sie einen Schlüssel. Die Seite zeigt den Schlüssel nur einmal an.
Legen Sie den Schlüssel in der Umgebungsvariable OWL3D_API_KEY ab. Alle Beispiele auf dieser Seite lesen ihn von dort.
Für die Nutzung der API gelten die Owl3D Cloud API Terms (auf Englisch).
export OWL3D_API_KEY="o3d_live_..."Authentifizierung
| Element | Wert |
|---|---|
| Basis-URL | https://api.owl3d.com |
| Schlüsselformat | o3d_live_<keyId>_<secret> |
| Anmelde-Header | Authorization: Bearer <key> |
Schreiben Sie Bearer mit großem B und einem Leerzeichen. Andere Formen erhalten 401.
Jede Route braucht einen Scope: jobs:read oder jobs:write. Die Routentabelle nennt den Scope jeder Route.
Halten Sie den API-Schlüssel geheim. Er kann Ihre Credits ausgeben. Wenn ein Schlüssel offengelegt wurde, widerrufen Sie ihn auf der Seite für API-Schlüssel. Ein widerrufener Schlüssel wird innerhalb von 60 Sekunden ungültig.
GET /v1/jobs/{id}
curl https://api.owl3d.com/v1/jobs/job_... \
-H "Authorization: Bearer $OWL3D_API_KEY"{"id": "job_...", "status": "converting"}Ein Video umwandeln
Laden Sie ein Skript herunter und führen Sie es mit Ihrem Video aus. Jedes Skript führt alle folgenden Schritte aus.
| Skript | Voraussetzungen | Aufruf |
|---|---|---|
| convert.sh | bash, curl, jq, ffprobe | bash convert.sh my-video.mp4 |
| convert.py | Python 3.9+, requests, ffprobe |
python3 convert.py my-video.mp4 |
| convert.mjs | Node.js 20+, ffprobe | node convert.mjs my-video.mp4 |
convert.sh · convert.py · convert.mjs
curl -O https://www.owl3d.com/docs/api/convert.sh
bash convert.sh my-video.mp4Die Skripte sind optional. Ihr eigener Code kann jede Sprache verwenden. Er braucht HTTPS-Aufrufe, SHA-256 und die Dateiangaben. Mit Upload zuerst braucht er nur HTTPS-Aufrufe.
Der Ablauf hat sechs Schritte:
- Dateiangaben lesen und den Fingerabdruck erstellen.
POST /v1/estimates: den Preis abfragen. Es wird nichts berechnet.POST /v1/jobs: den Preis bestätigen. Dies reserviert die Credits.- Jeden Teil per
PUTan seine Upload-URL senden, dannPOST /v1/jobs/{id}/upload-complete. GET /v1/jobs/{id}alle 15 Sekunden abfragen.GET /v1/jobs/{id}/result: einen Download-Link abrufen. Der Link gilt 15 Minuten und nur fürGET.
Upload zuerst lässt die Schritte 1 und 2 weg. Ihr Code sendet Dateiname und Dateigröße an POST /v1/jobs. Nach dem Upload liest der Server die Datei und legt den Preis fest.
Fehler
Die meisten Fehlerantworten haben einen JSON-Body mit error, einem kurzen Code.
| Status | Bedeutung |
|---|---|
400 |
Ungültige Anfrage, zum Beispiel bad_fingerprint |
401 |
Kein Token, ein falsches Token oder ein widerrufener Schlüssel |
402 |
short_of_credits: Tarif-Credits, Test-Credits und gekaufte Credits reichen zusammen nicht für den Preis |
403 |
insufficient_scope oder die Route ist nicht öffentlich |
404 |
no_job. In der Cloud-App erstellte Aufträge sind für die API nicht sichtbar |
409 |
Zustandskonflikt, zum Beispiel not_uploading oder endpoint_exists |
410 |
Das Ergebnis ist abgelaufen, oder insufficient_credits_expired: Der Auftrag hat 24 Stunden auf Credits gewartet |
429 |
Ein Limit ist voll. Siehe Limits |
Regeln für Wiederholungen:
- Bei
429warten SieRetry-AfterSekunden und senden dieselbe Anfrage erneut. - Bei
5xxoder einem Netzwerkfehler erhöhen Sie die Wartezeit schrittweise von 1 Sekunde bis 60 Sekunden. - Bei jedem anderen
4xxkorrigieren Sie die Anfrage.
curl -i https://api.owl3d.com/v1/jobs/job_unknown \
-H "Authorization: Bearer $OWL3D_API_KEY"{"error": "no_job"}Limits
| Limit | Wert | Antwort |
|---|---|---|
| Laufende Aufträge | 10 für alle API-Schlüssel eines Kontos zusammen. 15 für das ganze Konto, alle Kanäle zusammen. Optional ein Limit pro Schlüssel | 429 concurrency_limit, Retry-After: 15 |
| Anfragen | 120 pro Minute und Schlüssel | 429, Retry-After: 60 |
| Burst | Jede Route 10 pro Sekunde, Burst 20, für alle Aufrufer zusammen | 429 throttled, Retry-After: 1 |
| Tägliches Credit-Limit | Optional pro Schlüssel | 429 daily_credit_cap, bis 00:00 UTC |
| Aktive Schlüssel | 10 pro Konto | Erstellen abgelehnt |
| Eingabe | 100 GB, 3 Stunden, 4096 x 2160, 60 fps | Preisabfrage abgelehnt |
| Container | MP4, MOV, MKV, M4V | Preisabfrage abgelehnt |
Der Body einer 429 concurrency_limit nennt das volle Limit. scope ist api (alle API-Schlüssel des Kontos), account (alle Aufträge des Kontos) oder key (dieser Schlüssel). Starten Sie den nächsten Auftrag, wenn einer endet.
{
"error": "concurrency_limit",
"scope": "api",
"limit": 10,
"inProgress": 10
}Preise
POST /v1/estimates nennt den genauen Preis einer Datei, bevor Sie bezahlen.
Auf beiden Wegen liest der Server die hochgeladene Datei und legt daraus den endgültigen Preis fest. Mit Upload zuerst sehen Sie den Preis erst nach dem Upload. Wenn das Guthaben den Preis nicht deckt, wartet der Auftrag. Siehe Zu wenig Credits.
Routen
| Methode und Pfad | Scope | Funktion |
|---|---|---|
POST /v1/estimates |
jobs:write |
Preis und Dauer. Es wird nichts berechnet. 1 Stunde gültig, für einen Auftrag |
POST /v1/jobs |
jobs:write |
Reserviert Credits und gibt den Upload-Plan zurück. Mit estimateId, oder mit filename und sizeBytes (Upload zuerst) |
GET /v1/jobs/{id}/upload |
jobs:read |
Upload-Status: done, missing und neue parts-URLs |
POST /v1/jobs/{id}/upload-complete |
jobs:write |
Sendet die ETags und stellt den Auftrag in die Warteschlange |
GET /v1/jobs/{id} |
jobs:read |
Status, Fortschritt, verbleibende Zeit |
POST /v1/jobs/{id}/cancel |
jobs:write |
Bricht den Auftrag ab |
POST /v1/jobs/{id}/resume |
jobs:write |
Setzt einen Auftrag mit insufficient_credits fort, nachdem Sie Credits hinzugefügt haben. Kein neuer Upload |
GET /v1/jobs/{id}/result |
jobs:read |
Download-Link, 15 Minuten |
Preisabfragen
POST /v1/estimates nennt Preis und Dauer für eine Datei. Es wird nichts berechnet. Eine Preisabfrage gilt 1 Stunde, für einen Auftrag.
| Feld | Wert |
|---|---|
name, size |
Der Dateiname und die Größe in Bytes |
durationSeconds, width, height, fps |
Mit einem beliebigen Werkzeug aus der Datei gelesen, etwa ffprobe oder MediaInfo |
codec |
Einer von H.264, HEVC, AV1, VP9 |
bitDepth, chroma |
Aus der Datei gelesen. chroma ist 4:2:0 |
fingerprint |
{size, headSha256, tailSha256, edgeBytes} |
edgeBytesist 4194304 oder bei einer kleineren Datei die Dateigröße.headSha256undtailSha256sind die Hashes der ersten und der letztenedgeBytesder Datei.
In der Antwort bedeutet "ok": false, dass die Preisabfrage abgelehnt wird. Lesen Sie reason. Ist credits.shortBy größer als 0, braucht das Konto mehr Credits. credits.fromPlan, credits.fromTrial und credits.fromPurchased zeigen, welche Credits den Preis bezahlen.
POST /v1/estimates
curl https://api.owl3d.com/v1/estimates \
-H "Authorization: Bearer $OWL3D_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "my-video.mp4",
"size": 104857600,
"durationSeconds": 120,
"width": 1920, "height": 1080, "fps": 24,
"codec": "H.264", "bitDepth": 8, "chroma": "4:2:0",
"fingerprint": {
"size": 104857600,
"headSha256": "<SHA-256 of the first 4194304 bytes>",
"tailSha256": "<SHA-256 of the last 4194304 bytes>",
"edgeBytes": 4194304
}
}'{
"ok": true,
"id": "est_...",
"credits": {
"total": 60,
"fromPlan": 60,
"fromTrial": 0,
"fromPurchased": 0,
"shortBy": 0
},
"etaMinutes": 6,
"hdr": {"detected": false},
"output": {"format": "FULL_SBS", "width": 3840, "height": 1080}
}Aufträge
POST /v1/jobs mit {"estimateId": "est_..."} bestätigt den Preis. Dies reserviert die Credits. Die Antwort enthält die id des Auftrags und den Upload-Plan: upload.partSize und die URLs in upload.parts.
Ausgabeoptionen
POST /v1/jobs akzeptiert zusätzlich output: {layout, max_height}.
layout:full_sbs(Standard).max_height:"source"(Standard),2160oder1080.
POST /v1/jobs
curl https://api.owl3d.com/v1/jobs \
-H "Authorization: Bearer $OWL3D_API_KEY" \
-H "Content-Type: application/json" \
-d '{"estimateId": "est_...", "output": {"layout": "full_sbs", "max_height": "source"}}'{
"id": "job_...",
"status": "uploading",
"upload": {
"partSize": 67108864,
"parts": ["https://...", "https://..."],
"completeUrl": "/v1/jobs/job_.../upload-complete"
}
}Upload zuerst
Senden Sie POST /v1/jobs ohne estimateId. Ihr Code liest die Datei nicht und erstellt keinen Fingerabdruck.
| Feld | Wert |
|---|---|
filename |
Der Dateiname, höchstens 255 Zeichen. Er endet auf .mp4, .mov, .mkv oder .m4v |
sizeBytes |
Die Dateigröße in Bytes |
output |
Optional. Siehe Ausgabeoptionen |
- Das Guthaben muss den Mindestpreis decken. Sonst lautet die Antwort
402 short_of_credits, und es entsteht kein Auftrag. - Die Antwort
201enthält zusätzlichreservedCreditsund"priceAfterUpload": true. - Nach dem Upload liest der Server die Datei und legt den Preis fest.
- Wenn der Server die Datei nicht umwandeln kann, geht der Auftrag auf
failed. Es wird nichts berechnet, und die Datei wird gelöscht.
HDR10-Videos brauchen eine Preisabfrage. Ohne sie lautet die Antwort 400 hdr_needs_estimate.
POST /v1/jobs (upload first)
curl https://api.owl3d.com/v1/jobs \
-H "Authorization: Bearer $OWL3D_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"filename\": \"my-video.mp4\", \"sizeBytes\": $(wc -c < my-video.mp4)}"{
"id": "job_...",
"status": "uploading",
"upload": {
"partSize": 67108864,
"parts": ["https://...", "https://..."],
"completeUrl": "/v1/jobs/job_.../upload-complete"
},
"reservedCredits": 15,
"priceAfterUpload": true
}Zu wenig Credits
Wenn der Preis über dem Guthaben liegt, geht der Auftrag auf insufficient_credits. Es wird nichts berechnet. Das gilt für beide Wege, mit oder ohne Preisabfrage.
GET /v1/jobs/{id}zeigtshortBy(die fehlenden Credits),neededCredits,deleteAtundresumeUrl.- Fügen Sie Credits hinzu und senden Sie dann
POST /v1/jobs/{id}/resume. Laden Sie die Datei nicht erneut hoch. - Solange das Guthaben noch nicht reicht, antwortet resume mit
402 short_of_creditsundshortBy. - Ohne resume vor
deleteAt(24 Stunden) geht der Auftrag auffailedmitinsufficient_credits_expired. Die Datei wird gelöscht.
POST /v1/jobs/{id}/resume
curl -X POST https://api.owl3d.com/v1/jobs/job_.../resume \
-H "Authorization: Bearer $OWL3D_API_KEY"{
"id": "job_...",
"status": "queued"
}{
"error": "short_of_credits",
"shortBy": 120,
"neededCredits": 450,
"deleteAt": "2026-11-04T09:00:00.000Z"
}Uploads
- Teilen Sie die Datei in Teile von
upload.partSizeBytes. Teil 1 beginnt bei Byte 0. - Senden Sie jeden Teil per
PUTan seine URL inupload.parts. Behalten Sie denETag-Header jeder Antwort samt Anführungszeichen. - Senden Sie
POST /v1/jobs/{id}/upload-completemit{"etags": [...]}in der Reihenfolge der Teile.
Jede URL ist für eine genaue Länge signiert. Ein Teil muss partSize Bytes groß sein, der letzte Teil enthält den Rest. Der Speicher antwortet mit 403 bei jeder anderen Länge und bei einem Chunked-Body. Senden Sie Content-Length.
Wenn ein Upload abbricht, beginnen Sie nicht von vorn:
- Rufen Sie
GET /v1/jobs/{id}/uploadauf. - Lesen Sie
done. Jeder Eintrag hatpartNumber,etagundsize. - Lesen Sie
missing. Es listet Teilnummern. - Laden Sie jeden fehlenden Teil an
parts[partNumber - 1]hoch. Diese URLs sind 1 Stunde lang gültig. - Schließen Sie mit allen ETags in der Reihenfolge der Teile ab. Verwenden Sie dieselbe Datei.
Schließen Sie einen Upload innerhalb von 24 Stunden ab. Danach entfernt der Speicher die Teile eines nicht abgeschlossenen Uploads.
PUT upload.parts[n] · POST /v1/jobs/{id}/upload-complete
split -b 67108864 my-video.mp4 part_
curl -sS -D - -o /dev/null -X PUT --upload-file part_aa "<upload.parts[0]>" | grep -i '^etag'
curl -sS -D - -o /dev/null -X PUT --upload-file part_ab "<upload.parts[1]>" | grep -i '^etag'
curl https://api.owl3d.com/v1/jobs/job_.../upload-complete \
-H "Authorization: Bearer $OWL3D_API_KEY" \
-H "Content-Type: application/json" \
-d '{"etags": ["\"<etag of part 1>\"", "\"<etag of part 2>\""]}'{"id": "job_...", "status": "queued"}GET /v1/jobs/{id}/upload
curl https://api.owl3d.com/v1/jobs/job_.../upload \
-H "Authorization: Bearer $OWL3D_API_KEY"{
"id": "job_...",
"partSize": 67108864,
"parts": ["https://...", "https://..."],
"completeUrl": "/v1/jobs/job_.../upload-complete",
"done": [{"partNumber": 1, "etag": "\"...\"", "size": 67108864}],
"missing": [2]
}Auftragsstatus
GET /v1/jobs/{id} nennt Status, Fortschritt und verbleibende Zeit. Fragen Sie alle 15 Sekunden ab.
status |
Bedeutung |
|---|---|
uploading |
Der Auftrag wartet auf die Datei |
queued |
Der Auftrag wartet auf eine GPU. Ein Auftrag kann kurz von converting zurück zu queued wechseln |
converting |
progress geht von 0 bis 1 |
delayed |
Auf unserer Seite angehalten. Die Credits bleiben reserviert |
insufficient_credits |
Der Preis liegt über dem Guthaben. Fügen Sie shortBy Credits hinzu und rufen Sie dann resume auf. Siehe Zu wenig Credits |
done |
Fertig. result enthält Name, Größe und Link-Pfad |
failed |
error enthält einen code. Die Credits wurden zurückgebucht |
cancelled |
Vom Aufrufer abgebrochen |
GET /v1/jobs/{id}
curl https://api.owl3d.com/v1/jobs/job_... \
-H "Authorization: Bearer $OWL3D_API_KEY"{
"id": "job_...",
"status": "converting",
"progress": 0.42,
"etaSeconds": 310
}Ergebnisse
GET /v1/jobs/{id}/result gibt einen Download-Link für einen Auftrag mit done. Der Link gilt 15 Minuten und nur für GET. Für einen neuen Link rufen Sie die Route erneut auf. Ist das Ergebnis abgelaufen, lautet die Antwort 410.
GET /v1/jobs/{id}/result
curl https://api.owl3d.com/v1/jobs/job_.../result \
-H "Authorization: Bearer $OWL3D_API_KEY"
curl -o output.mp4 "<url>"{
"url": "https://...",
"filename": "...",
"sizeBytes": 209715200,
"expiresInS": 900
}Abbrechen
POST /v1/jobs/{id}/cancel bricht einen Auftrag ab. Ein Auftrag, der vor dem Start der Umwandlung abgebrochen wird, kostet nichts. Danach kostet er den Preis x progress, aufgerundet, mindestens 1 Credit.
POST /v1/jobs/{id}/cancel
curl -X POST https://api.owl3d.com/v1/jobs/job_.../cancel \
-H "Authorization: Bearer $OWL3D_API_KEY"{"id": "job_...", "status": "cancelled"}