API-Referenz
Endpunkte, Felder, Antworten, Credits, Limits und Fehler.
Aktualisiert
So funktioniert es#
Jedes Transkript ist ein Auftrag. Sie senden eine Quelle, der Auftrag läuft im Hintergrund, und wenn er erfolgreich ist, verweist er auf ein Transkript, das Sie so oft lesen oder exportieren können, wie Sie möchten. Basis-URL: https://www.transcriptdock.com. Alle Anfragen und Antworten sind JSON.
# 1. Submitcurl -X POST https://www.transcriptdock.com/v1/jobs \-H "Authorization: Bearer td_live_YOUR_KEY" \-H "Idempotency-Key: video-7680721699171601694" \-H "Content-Type: application/json" \-d '{ "source": { "url": "https://www.tiktok.com/@tiktok/video/7680721699171601694" }, "mode": "captions_only" }'# 2. Wait (returns as soon as the job finishes, up to 25 s per call)curl "https://www.transcriptdock.com/v1/jobs/11111111-1111-4111-8111-111111111111?wait=25" \-H "Authorization: Bearer td_live_YOUR_KEY"# 3. Exportcurl "https://www.transcriptdock.com/v1/transcripts/22222222-2222-4222-8222-222222222222/export?format=srt" \-H "Authorization: Bearer td_live_YOUR_KEY"
Authentifizierung#
Erstellen Sie Schlüssel auf der Seite API-Schlüssel. Ein Schlüssel wird nur einmal angezeigt, sieht aus wie td_live_... und gehört in den Authorization-Header jeder Anfrage. Schlüssel erhalten beim Erstellen festgelegte Berechtigungen: jobs:read, jobs:write, transcripts:read, uploads:write. Erstellen Sie für jede Integration einen eigenen Schlüssel, damit Sie ihn einzeln widerrufen können.
Authorization: Bearer td_live_YOUR_KEY
Idempotency-Key#
Erforderlich bei POST /v1/jobs, /v1/batches, /v1/jobs/{id}/retry, /v1/video-discoveries und /v1/language-discoveries: beliebige 8 bis 128 druckbare ASCII-Zeichen. Wird derselbe Schlüssel mit demselben Body innerhalb von 48 Stunden erneut gesendet, gibt die API das ursprüngliche Objekt zurück. Eine wiederholte Anfrage erzeugt oder berechnet daher nie doppelt. Derselbe Schlüssel mit einem anderen Body liefert 409 IDEMPOTENCY_CONFLICT. Ein guter Schlüssel ist Ihre eigene Kennung für den Inhalt, den Sie transkribieren.
X-Request-Id#
Jede Antwort enthält eine. Nennen Sie sie beim Kontakt mit dem Support.
Endpunkte#
| Methode | Pfad | Funktion | Credits |
|---|---|---|---|
| POST | /v1/jobs | Ein Video, eine Datei oder einen Link transkribieren | 1 pro Transkript aus Untertiteln, 2 pro Minute KI-Transkription |
| GET | /v1/jobs/{id} | Auftragsstatus, wartet bis zu 25 s | Kostenlos |
| GET | /v1/jobs | Auftragsverlauf | Kostenlos |
| POST | /v1/jobs/{id}/cancel | Einen wartenden Auftrag abbrechen | Kostenlos |
| POST | /v1/jobs/{id}/retry | Einen fehlgeschlagenen Auftrag erneut versuchen | Als neuer Auftrag |
| POST | /v1/batches | Viele Videos transkribieren (Stapelgröße je Tarif) | Pro Eintrag, wie oben |
| GET | /v1/batches/{id} | Status des Stapels | Kostenlos |
| GET | /v1/transcripts/{id} | Transkript als JSON | Kostenlos |
| GET | /v1/transcripts/{id}/export | Datei als txt, srt, vtt oder json | Kostenlos |
| DELETE | /v1/transcripts/{id} | Ein Transkript löschen | Kostenlos |
| POST | /v1/uploads | URL zum Hochladen einer Datei abrufen | Kostenlos |
| POST | /v1/uploads/{id}/complete | Upload als abgeschlossen markieren | Kostenlos |
| POST | /v1/video-discoveries | YouTube durchsuchen, einen Kanal, eine Playlist oder ein TikTok-Profil auflisten | 1 pro Seite |
| GET | /v1/video-discoveries/{id} | Ergebnis der Suche | Kostenlos |
| POST | /v1/language-discoveries | Untertitelsprachen eines YouTube-Videos auflisten | 1 |
| GET | /v1/language-discoveries/{id} | Liste der Sprachen | Kostenlos |
| POST | /v1/webhook-endpoints | Eine Webhook-URL registrieren (mit angemeldeter Sitzung) | Kostenlos |
| GET | /v1/webhook-endpoints | Webhook-URLs auflisten | Kostenlos |
| DELETE | /v1/webhook-endpoints/{id} | Eine Webhook-URL deaktivieren (mit angemeldeter Sitzung) | Kostenlos |
| GET | /v1/usage | Credits und Tarif | Kostenlos |
| GET | /v1/capabilities | Was Ihr API-Schlüssel kann | Kostenlos |
Auftrag erstellen#
/v1/jobsGibt 202 mit dem Auftrag zurück. Besitzt Ihr Arbeitsbereich bereits ein Transkript für dasselbe Video und dieselben Optionen, kommt 200 mit einem erfolgreichen Auftrag kostenlos zurück (billing.kind: "cached").
{"id": "11111111-1111-4111-8111-111111111111","status": "queued","stage": "resolve","result_id": null,"error": null,"billing": { "credits_reserved": 2, "credits_charged": 0, "kind": "captions" },"source": { "platform": "tiktok", "media_id": "7680721699171601694", "canonical_url": "https://www.tiktok.com/@tiktok/video/7680721699171601694", "title": null, "upload_id": null },"options": { "mode": "auto", "language": null, "caption_preference": "prefer_creator" },"created_at": "2026-09-16T10:00:00.000Z"}
Das Auftragsobjekt#
Auftrag abrufen#
/v1/jobs/{id}?wait=25Gibt den Auftrag zurück. Mit wait (0 bis 25 Sekunden) bleibt die Anfrage offen und antwortet, sobald der Auftrag endgültig ist. Ein Aufruf ersetzt damit eine Abfrageschleife. Lesezugriffe haben ein eigenes Limit von 120 pro Minute.
Aufträge auflisten#
/v1/jobs?limit=20&cursor=Neueste zuerst, limit 1 bis 100. Geben Sie den next_cursor aus der Antwort als cursor an, um die nächste Seite zu laden. Mit platform und source_id (die source.media_id eines Auftrags) zusammen sehen Sie nur die Aufträge für ein Video, in jedem Modus. So prüft ein Client, ob der Arbeitsbereich schon ein Transkript hat, bevor er erneut sendet.
Auftrag abbrechen#
/v1/jobs/{id}/cancelBricht einen Auftrag ab, dessen KI-Transkription noch nicht begonnen hat. Die Reservierung wird freigegeben. Danach liefert die API 409 CANCELLATION_NOT_ALLOWED, und der Auftrag wird zu Ende geführt.
Auftrag erneut versuchen#
/v1/jobs/{id}/retryErstellt aus einem fehlgeschlagenen Auftrag mit einem wiederholbaren Fehler (retryable) einen neuen Auftrag. Dafür ist ein neuer Idempotency-Key nötig; optionaler Body { "max_credits": 40 }. Die Abrechnung entspricht einem neuen Auftrag. Endgültige Fehler (privates Video, keine Untertitel) liefern 409 JOB_NOT_RETRYABLE: Korrigieren Sie in diesem Fall die Eingabe und senden Sie erneut.
Das Transkript#
/v1/transcripts/{id}{"id": "22222222-2222-4222-8222-222222222222","source": { "platform": "youtube", "media_id": "dQw4w9WgXcQ", "canonical_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "title": "Beispielvideo" },"source_origin": "creator_captions","language": "de","text": "Willkommen zu diesem Beispiel. Dies ist die zweite Zeile.","segments": [{ "start": 0, "end": 2.4, "text": "Willkommen zu diesem Beispiel" },{ "start": 2.4, "end": 4.9, "text": "Dies ist die zweite Zeile" }],"words": null,"timing_granularity": "segment","duration_seconds": 212.0,"recognition": null,"extraction_version": "worker-0.1.0","created_at": "2026-09-16T10:00:14.000Z"}
Transkripte werden für die Aufbewahrungsdauer Ihres Tarifs gespeichert (7 Tage in der Testphase, 30 bei Starter, 90 bei Pro und Scale). DELETE /v1/transcripts/{id} entfernt ein Transkript vorher.
Transkript exportieren#
/v1/transcripts/{id}/export?format=srt| format | Sie erhalten |
|---|---|
| txt | Klartext, ein Abschnitt pro Zeile. |
| srt | SubRip-Untertitel. |
| vtt | WebVTT-Untertitel. |
| json | Das oben beschriebene Transkriptobjekt. |
Kostenlos und unbegrenzt. srt und vtt benötigen Zeitangaben. Ein Transkript ohne Zeitangaben liefert 422 TIMESTAMPS_UNAVAILABLE.
Stapel#
/v1/batchesEine Anfrage, viele Videos. Jeder Eintrag hat dieselben Felder wie Auftrag erstellen. Der gesamte Stapel wird insgesamt angenommen oder insgesamt abgelehnt. Einträge pro Stapel: 1 in der Testphase, 10 bei Starter, 25 bei Pro, 50 bei Scale.
curl -X POST https://www.transcriptdock.com/v1/batches \-H "Authorization: Bearer td_live_YOUR_KEY" \-H "Idempotency-Key: playlist-2026-09-16" \-H "Content-Type: application/json" \-d '{ "items": [{ "source": { "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ" }, "mode": "captions_only" },{ "source": { "url": "https://www.tiktok.com/@tiktok/video/7680721699171601694" }, "mode": "captions_only" }] }'
Das Stapelobjekt hat status (queued, processing, succeeded, partial_success, failed, cancelled), Zähler (total_items, succeeded_items, failed_items, cancelled_items) und items, jeweils mit seiner job_id. Lesen Sie es mit GET /v1/batches/{id}. Jeder Eintrag ist ein normaler Auftrag.
Dateien hochladen#
Ihre eigene Audio- oder Videodatei (mp3, wav, m4a, ogg, aac, mp4, webm; bis 250 MB und 2 Stunden). Reservieren Sie einen Platz, laden Sie die Datei per PUT auf die signierte URL hoch, markieren Sie den Upload als abgeschlossen und reichen Sie ihn dann als Auftrag mit source.upload_id ein. Uploads verwenden immer KI-Transkription.
# 1. Reservecurl -X POST https://www.transcriptdock.com/v1/uploads \-H "Authorization: Bearer td_live_YOUR_KEY" \-H "Content-Type: application/json" \-d '{ "filename": "interview.mp3", "content_type": "audio/mpeg", "bytes": 48213920 }'# -> { "id": "33333333-...", "signed_upload_url": "https://...", "expires_at": "...", "status": "pending" }# 2. Upload the bytes (same Content-Type you declared)curl -X PUT "SIGNED_UPLOAD_URL" -H "Content-Type: audio/mpeg" --data-binary @interview.mp3# 3. Completecurl -X POST https://www.transcriptdock.com/v1/uploads/33333333-3333-4333-8333-333333333333/complete \-H "Authorization: Bearer td_live_YOUR_KEY"# 4. Transcribe itcurl -X POST https://www.transcriptdock.com/v1/jobs \-H "Authorization: Bearer td_live_YOUR_KEY" \-H "Idempotency-Key: interview-01" \-H "Content-Type: application/json" \-d '{ "source": { "upload_id": "33333333-3333-4333-8333-333333333333" }, "mode": "transcribe" }'
Die signierte URL ist 24 Stunden gültig. Danach reservieren Sie einen neuen Platz.
Webhooks#
/v1/webhook-endpointsRegistrieren Sie eine https-URL und übergeben Sie ihre id beim Einreichen als webhook_endpoint_id. Wir senden per POST ein Ereignis, sobald der Auftrag oder Stapel abgeschlossen ist. Die Antwort enthält das Signaturgeheimnis secret genau einmal. Endpunkte zu registrieren oder zu deaktivieren erfordert eine angemeldete Sitzung. Erledigen Sie das daher auf der Seite Webhooks im Dashboard. Ein API-Schlüssel erhält dort 403 FORBIDDEN, kann Endpunkte aber auflisten.
Ereignisse#
{"event_id": "44444444-4444-4444-8444-444444444444","type": "job.succeeded","created_at": "2026-09-16T10:00:14.000Z","job_id": "11111111-1111-4111-8111-111111111111","batch_id": null,"result_id": "22222222-2222-4222-8222-222222222222","metadata": { "order": "8812" },"error": null}
job.succeeded: Rufen Sie dieresult_idab oder exportieren Sie sie.job.failed:errorenthält den Code.batch.completed: Jeder Eintrag ist endgültig. Lesen Sie den Stapel für die Ergebnisse je Eintrag.
Antworten Sie innerhalb weniger Sekunden mit einem beliebigen 2xx-Status. Fehlgeschlagene Zustellungen werden mit zunehmenden Wartezeiten erneut versucht und lassen sich im Dashboard erneut senden. Ein Ereignis kann mehrfach eintreffen. Filtern Sie Duplikate anhand von event_id.
Signatur prüfen#
Header X-TranscriptDock-Event-Id, X-TranscriptDock-Timestamp und X-TranscriptDock-Signature. Die Signatur ist der HMAC-SHA256 (hex) von {event_id}.{timestamp}.{raw_body} mit Ihrem Geheimnis. Lehnen Sie alles ab, das älter als fünf Minuten ist.
import crypto from "node:crypto";export function verify(eventId: string, timestamp: string, rawBody: string, signature: string, secret: string): boolean {if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;const expected = crypto.createHmac("sha256", secret).update(`${eventId}.${timestamp}.${rawBody}`).digest("hex");return expected.length === signature.length && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));}
Videos finden#
/v1/video-discoveriesDurchsuchen Sie YouTube oder listen Sie einen Kanal, eine Playlist oder ein TikTok-Profil auf und übergeben Sie die URLs anschließend an Aufträge. Eine Suche läuft wie ein Auftrag im Hintergrund. Lesen Sie sie mit GET /v1/video-discoveries/{id}, bis status den Wert succeeded hat. 1 Credit pro Seite. Ergebnisse werden 24 Stunden lang gespeichert.
curl -X POST https://www.transcriptdock.com/v1/video-discoveries \-H "Authorization: Bearer td_live_YOUR_KEY" \-H "Idempotency-Key: search-async-rust-1" \-H "Content-Type: application/json" \-d '{ "kind": "youtube_search", "query": "async rust", "limit": 5 }'
Das POST antwortet mit 202 und status: "queued". So sieht ein abgeschlossenes GET /v1/video-discoveries/{id} aus:
{"id": "55555555-5555-4555-8555-555555555555","kind": "youtube_search","status": "succeeded","request": { "kind": "youtube_search", "query": "async rust", "limit": 5 },"videos": [{"platform": "youtube","video_id": "wXtngLBkK4Q","url": "https://www.youtube.com/watch?v=wXtngLBkK4Q","title": "Async Rust explained in 20 minutes","channel_id": "UCSp-OaMpsO8K0KkOqyBl7_w","channel_title": "Let's Get Rusty","duration_s": 1155,"published_at": null,"published_text": "5 months ago","view_count": 83635,"view_count_text": "83,635 views","thumbnail_url": "https://i.ytimg.com/vi/wXtngLBkK4Q/hq720.jpg","tiktok": null}],"profile": null,"next_cursor": "opaque-token","error": null,"created_at": "2026-09-16T12:00:00.000Z","updated_at": "2026-09-16T12:00:03.000Z","expires_at": "2026-09-17T12:00:00.000Z"}
Untertitelsprachen eines Videos#
/v1/language-discoveriesBody { "source": { "url": "https://www.youtube.com/watch?v=..." } } mit einem Idempotency-Key (nur YouTube, 1 Credit). Lesen Sie GET /v1/language-discoveries/{id} für die Liste der Untertitelspuren mit ihren Codes, der Angabe, ob sie vom Ersteller oder automatisch stammen, und der Standardspur. Verwenden Sie die Codes in caption_languages.
Nutzung und Funktionen#
/v1/usage{"plan": "pro","period_end": "2026-10-16T00:00:00.000Z","credits_remaining": 5840,"credits_total": 6000,"credits_reserved": 4,"prepaid_credits": 0,"transcribe_credits_per_minute": 2,"minimum_billable_seconds": 60,"subscription": {"status": "active","interval": "yearly","cancel_at_period_end": false,"current_period_end": "2027-09-16T00:00:00.000Z"}}
credits_remaining enthält credits_reserved bereits nicht (Reservierungen laufender Aufträge). prepaid_credits sind gekaufte Credits, die nie ablaufen.
subscription ist das Stripe-Abonnement hinter einem kostenpflichtigen Tarif und ohne Tarif null. Es enthält den status, das Abrechnungsintervall interval (monthly oder yearly), cancel_at_period_end und current_period_end: wann der Tarif verlängert wird oder endet. period_end ist der Zeitpunkt, zu dem die monatlichen Credits erneuert werden, bei Jahrestarifen ebenfalls jeden Monat.
/v1/capabilitiesWas Ihr API-Schlüssel gerade kann: je Quelle (youtube, tiktok, instagram, upload, direct) die verfügbaren Modi sowie Limits und Preise. Lesen Sie dies, statt Werte fest einzutragen. Die Testphase meldet zum Beispiel auto und transcribe als false.
{"youtube": { "enabled": true, "captions_only": true, "auto": true, "transcribe": true, "social_acquisition_fee": true },"tiktok": { "enabled": true, "captions_only": true, "auto": true, "transcribe": true, "social_acquisition_fee": true },"instagram": { "enabled": false, "captions_only": false, "auto": false, "transcribe": false, "social_acquisition_fee": true, "native_captions": "unverified_disabled" },"upload": { "enabled": true, "captions_only": false, "auto": true, "transcribe": true, "social_acquisition_fee": false },"direct": { "enabled": true, "captions_only": false, "auto": true, "transcribe": true, "social_acquisition_fee": false },"max_duration_ms": 7200000,"max_media_bytes": 262144000,"export_formats": ["txt", "json", "srt", "vtt"],"recognition_profiles": ["standard"],"transcribe_credits_per_minute": 2,"minimum_billable_seconds": 60,"price_version": "2026-09-14","asr_enabled": true,"instagram_enabled": false,"free_caption_credits": 50,"free_caption_credits_period": "month"}
Ratenlimits#
| Tarif | Aufträge / Min. | Laufende Aufträge | Lesezugriffe / Min. |
|---|---|---|---|
| Testphase | 10 | 10 | 120 |
| Starter | 60 | 100 | 120 |
| Pro | 120 | 500 | 120 |
| Scale | 300 | 2,000 | 120 |
Bei Überschreitung erhalten Sie 429 RATE_LIMITED mit einem retry-after-Header (Sekunden) und details.detail, das das Limit nennt. Es wird nichts berechnet. Webhooks und ?wait=25 halten Sie weit unter dem Leselimit.
Fehler#
Alle Fehler haben denselben Aufbau. retryable: true bedeutet, dass dieselbe Anfrage später erfolgreich sein kann. Warten Sie dann die Sekunden aus retry-after, falls vorhanden, sonst einige Sekunden, und verwenden Sie denselben Idempotency-Key erneut, damit nichts doppelt entsteht. Jeder andere Fehler erfordert eine Änderung auf Ihrer Seite.
{"error": {"code": "INSUFFICIENT_BALANCE","message": "Not enough credits. Buy credits or upgrade your plan to continue.","retryable": false,"details": { "detail": "This job needs more credits than you have left. Buy credits or upgrade your plan." },"doc_url": "https://www.transcriptdock.com/docs/api-reference#error-codes"},"request_id": "66666666-6666-4666-8666-666666666666"}
Ein Auftrag, der nach der Annahme fehlschlägt, liefert bei GET /v1/jobs/{id} weiterhin 200 mit status: "failed" und demselben Fehlerobjekt in error. Für einen fehlgeschlagenen Auftrag wird nichts berechnet.
Codes#
| Code | HTTP | Wiederholen | Bedeutung und Lösung |
|---|---|---|---|
INVALID_REQUEST | 422 | Nein | A field is missing or has the wrong shape. details.detail names it. |
INVALID_URL | 422 | Nein | The URL is not a valid https link (max 2048 characters). |
UNSUPPORTED_SOURCE | 422 | Nein | The link is not a YouTube or TikTok video URL. |
UNSAFE_URL | 422 | Nein | The direct media link points at a private or blocked network address. |
INVALID_CURSOR | 422 | Nein | A video discovery cursor expired or is malformed. Start again from the first page. A bad job list cursor returns INVALID_REQUEST. |
CAPABILITY_UNAVAILABLE | 422 | Nein | This mode is not available for this source. GET /v1/capabilities shows what is. |
IDEMPOTENCY_CONFLICT | 409 | Nein | This Idempotency-Key was already used with a different body. Use a new key. |
UNAUTHENTICATED | 401 | Nein | No valid API key or OAuth token in the Authorization header. |
FORBIDDEN | 403 | Nein | The key lacks the scope for this endpoint, or the workspace is disabled. |
EMAIL_UNVERIFIED | 403 | Nein | Verify the account email before using the API. |
NOT_FOUND | 404 | Nein | No such object in this workspace. |
INSUFFICIENT_BALANCE | 402 | Nein | Not enough credits for this job. Buy credits or upgrade. |
PLAN_REQUIRED | 402 | Nein | This needs a paid plan (AI transcription, larger batches) or the trial credits are used up. |
BUDGET_EXCEEDED | 402 | Nein | The measured cost is above max_credits. Nothing was charged; raise the cap or skip the media. |
JOB_NOT_RETRYABLE | 409 | Nein | The failure was final (private video, no captions). Fix the input and submit a new job. |
CANCELLATION_NOT_ALLOWED | 409 | Nein | AI transcription already started; the job will finish. |
RATE_LIMITED | 429 | Ja | Over a rate or queue limit. Wait retry-after seconds; details.detail says which limit. |
SOURCE_NOT_FOUND | 422 | Nein | The video does not exist or was removed. |
SOURCE_PRIVATE | 422 | Nein | The video is private. Only public videos work. |
SOURCE_AUTH_REQUIRED | 422 | Nein | The video needs a login, age check or membership. |
SOURCE_REGION_RESTRICTED | 422 | Nein | The video is blocked in the regions we fetch from. |
NO_CAPTIONS | 422 | Nein | No captions on this video and mode was captions_only. Use auto or transcribe. |
LANGUAGE_UNAVAILABLE | 422 | Nein | None of caption_languages exists on this video. Drop the list to take the default track. |
LANGUAGE_UNSUPPORTED | 422 | Nein | AI transcription does not support the requested language. |
NO_SPEECH | 422 | Nein | AI transcription found no speech in the audio. |
NO_AUDIO | 422 | Nein | The media has no audio track. |
INVALID_MEDIA | 422 | Nein | The file could not be read as audio or video. |
UNSUPPORTED_MEDIA | 422 | Nein | Not an audio or video file type. |
DURATION_LIMIT_EXCEEDED | 413 | Nein | Longer than 2 hours. |
FILE_TOO_LARGE | 413 | Nein | Larger than 250 MB. |
TIMESTAMPS_UNAVAILABLE | 422 | Nein | This transcript has no timings, so srt and vtt exports are unavailable. Use txt or json. |
PROVIDER_REJECTED | 422 | Nein | The AI transcription model could not process this audio. |
SOURCE_RATE_LIMITED | 503 | Ja | The source platform is throttling us. The job retries automatically. |
SOURCE_BLOCKED | 503 | Ja | The source platform blocked the fetch. The job retries automatically. |
SOURCE_TIMEOUT | 503 | Ja | The source platform timed out. The job retries automatically. |
SOURCE_CHANGED | 503 | Ja | The source changed while we read it. The job retries automatically. |
PROVIDER_UNAVAILABLE | 503 | Ja | AI transcription is temporarily unavailable. The job retries automatically. |
STORAGE_UNAVAILABLE | 503 | Ja | File storage is temporarily unavailable. Retry the request. |
INTERNAL_ERROR | 500 | Ja | Our fault. Retry with the same Idempotency-Key; quote X-Request-Id if it persists. |