DEVELOPER · API · INTEGRATION
API ACCESS.
Automatisiere Transkriptionen via REST API. Abrechnung läuft per Minute — identisch zum Web-Interface.
Guthaben
—
Preis: wird geladen…
API Keys
Wird geladen…
Quickstart
Endpoints
Webhook
Minimales Beispiel (Python)
import httpx API_KEY = "sk_live_..." BASE = "https://subli.ch" # 1. Job starten resp = httpx.post(f"{BASE}/api/v1/transcribe", headers={"Authorization": f"Bearer {API_KEY}"}, json={"url": "https://example.com/podcast.mp3"}) job_id = resp.json()["job_id"] # 2. Auf Fertigstellung warten import time while True: status = httpx.get(f"{BASE}/api/v1/job/{job_id}", headers={"Authorization": f"Bearer {API_KEY}"}).json() if status["status"] == "done": break if status["status"] == "error": raise SystemExit(f"Fehler: {status['error']}") time.sleep(5) # 3. SRT herunterladen srt = httpx.get(f"{BASE}/api/v1/result/{job_id}", headers={"Authorization": f"Bearer {API_KEY}"}).text print(srt)
Mit Webhook (empfohlen)
resp = httpx.post(f"{BASE}/api/v1/transcribe", headers={"Authorization": f"Bearer {API_KEY}"}, json={ "url": "https://example.com/podcast.mp3", "webhook_url": "https://dein-server.com/callback" }) # SUBLI ruft dich auf, sobald der Job fertig (oder fehlgeschlagen) ist.
Datei direkt hochladen
with open("interview.mp4", "rb") as f: resp = httpx.post(f"{BASE}/api/v1/transcribe", headers={"Authorization": f"Bearer {API_KEY}"}, files={"file": ("interview.mp4", f, "video/mp4")}, data={"webhook_url": "https://dein-server.com/callback"}) # optional job_id = resp.json()["job_id"]
POST /api/v1/transcribe
Startet einen Transkriptions-Job.
// A) per URL — Content-Type: application/json { "url": "https://…/podcast.mp3", // HTTPS, max 4 GB "webhook_url": "https://…/callback", // optional "num_speakers": 2 // optional (oder min_speakers / max_speakers) } // Response 200 — Download läuft im Hintergrund { "job_id": "…", "status": "downloading" } // Zu wenig Guthaben zeigt sich danach beim Job-Status: // { "status": "error", "error": "insufficient_funds", "cost_rappen": 1350, "missing_rappen": 450 } // B) Datei-Upload — Content-Type: multipart/form-data // Felder: file (Pflicht), webhook_url / num_speakers / min_speakers / max_speakers (optional) // Response 200 { "job_id": "…", "status": "queued", "duration_seconds": 1823.0 } // Response 402 — zu wenig Guthaben { "reason": "insufficient_funds", "cost_rappen": 1350, "balance_rappen": 900, "missing_rappen": 450 }
GET /api/v1/job/{job_id}
// status: "downloading" | "queued" | "loading" | "transcribing" | "processing" | "done" | "error" { "job_id": "…", "status": "transcribing", "progress": 30, "error": null }
GET /api/v1/result/{job_id}?format=srt
format: srt (default), vtt oder json. Noch nicht fertig → 425, fehlgeschlagen → 422. Ergebnisse bleiben 30 Tage abrufbar.
// SRT (text/plain) 1 00:00:00,000 --> 00:00:03,420 Willkommen zum Podcast. // JSON — jedes Wort/Segment trägt automatisch ein "speaker"-Feld (z.B. "SPEAKER_00") { "words": […], "segments": […] }
Auth-Header für alle Requests:
Authorization: Bearer sk_live_…
Wenn du webhook_url mitgibst (HTTPS), sendet SUBLI bei Job-Abschluss einen POST mit diesem Payload:
{ "event": "transcription.done", "job_id": "…", "status": "done", "result_url": "https://subli.ch/api/v1/result/{job_id}", "srt_url": "https://subli.ch/api/v1/result/{job_id}?format=srt", "json_url": "https://subli.ch/api/v1/result/{job_id}?format=json" } // Bei einem Fehler: { "event": "transcription.failed", "job_id": "…", "status": "error", "error": "…" }
Signatur verifizieren
Jeder Webhook-Request enthält den Header X-Subli-Signature — ein HMAC-SHA256 über den rohen Request-Body (genau die empfangenen Bytes, nicht neu serialisieren), signiert mit dem Webhook Secret des API-Keys, mit dem der Job gestartet wurde (sichtbar in der Key-Liste oben).
import hmac, hashlib, json def verify(body_bytes, signature, secret): expected = hmac.new( secret.encode(), body_bytes, hashlib.sha256 ).hexdigest() return hmac.compare_digest(expected, signature)