API-referentie
Endpoints, velden, antwoorden, credits, limieten en fouten.
Bijgewerkt
Hoe het werkt#
Elke transcriptie loopt via een taak. Je dient een bron in, de taak draait op de achtergrond, en wanneer die slaagt, verwijst hij naar een transcriptie die je zo vaak als je wilt kunt lezen of exporteren. Basis-URL: https://www.transcriptdock.com. Alle verzoeken en antwoorden zijn 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"
Authenticatie#
Maak sleutels aan op de pagina API keys. Een sleutel wordt één keer getoond, ziet eruit als td_live_... en gaat in de Authorization-header van elk verzoek. Sleutels krijgen bij het aanmaken scopes: jobs:read, jobs:write, transcripts:read, uploads:write. Maak per koppeling een eigen sleutel aan, zodat je er één apart kunt intrekken.
Authorization: Bearer td_live_YOUR_KEY
Idempotency-Key#
Verplicht bij POST /v1/jobs, /v1/batches, /v1/jobs/{id}/retry, /v1/video-discoveries en /v1/language-discoveries: elke tekst van 8 tot 128 afdrukbare ASCII-tekens. Als je binnen 48 uur dezelfde sleutel met dezelfde body stuurt, krijg je het oorspronkelijke object terug, zodat een opnieuw verzonden verzoek nooit dubbel iets aanmaakt of afrekent. Dezelfde sleutel met een andere body geeft 409 IDEMPOTENCY_CONFLICT. Een goede sleutel is je eigen id voor wat je transcribeert.
X-Request-Id#
Elk antwoord bevat er een. Vermeld hem wanneer je contact opneemt met support.
Endpoints#
| Methode | Pad | Wat het doet | Credits |
|---|---|---|---|
| POST | /v1/jobs | Transcribeert één video, bestand of link | 1 per transcriptie van ondertitels, 2 per minuut AI-transcriptie |
| GET | /v1/jobs/{id} | Status van een taak, wacht maximaal 25 s | Gratis |
| GET | /v1/jobs | Taakgeschiedenis | Gratis |
| POST | /v1/jobs/{id}/cancel | Annuleert een taak in de wachtrij | Gratis |
| POST | /v1/jobs/{id}/retry | Probeert een mislukte taak opnieuw | Als nieuwe taak |
| POST | /v1/batches | Transcribeert veel video's (batchgrootte van het abonnement) | Per item, zoals hierboven |
| GET | /v1/batches/{id} | Status van een batch | Gratis |
| GET | /v1/transcripts/{id} | Transcriptie als JSON | Gratis |
| GET | /v1/transcripts/{id}/export | txt-, srt-, vtt- of json-bestand | Gratis |
| DELETE | /v1/transcripts/{id} | Verwijdert een transcriptie | Gratis |
| POST | /v1/uploads | Krijg een URL om een bestand naar te uploaden | Gratis |
| POST | /v1/uploads/{id}/complete | Markeert de upload als voltooid | Gratis |
| POST | /v1/video-discoveries | Zoekt op YouTube, toont een kanaal, afspeellijst of TikTok-profiel | 1 per pagina |
| GET | /v1/video-discoveries/{id} | Resultaat van een videozoekopdracht | Gratis |
| POST | /v1/language-discoveries | Toont de ondertiteltalen van een YouTube-video | 1 |
| GET | /v1/language-discoveries/{id} | Lijst met talen | Gratis |
| POST | /v1/webhook-endpoints | Registreert een webhook-URL (vereist een ingelogde sessie) | Gratis |
| GET | /v1/webhook-endpoints | Toont webhook-URL's | Gratis |
| DELETE | /v1/webhook-endpoints/{id} | Schakelt een webhook-URL uit (vereist een ingelogde sessie) | Gratis |
| GET | /v1/usage | Credits en abonnement | Gratis |
| GET | /v1/capabilities | Wat je sleutel kan doen | Gratis |
Een taak aanmaken#
/v1/jobsGeeft 202 terug met de taak. Heeft je werkruimte al een transcriptie voor dezelfde video en opties, dan geeft hij 200 terug met een geslaagde taak, gratis (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"}
Het taakobject#
Een taak ophalen#
/v1/jobs/{id}?wait=25Geeft de taak terug. Met wait (0 tot 25 seconden) blijft het verzoek open en geeft het antwoord zodra de taak definitief is. Eén aanroep vervangt zo een pollinglus. Lezen heeft een eigen limiet van 120 per minuut.
Taken tonen#
/v1/jobs?limit=20&cursor=Nieuwste eerst, limit 1 tot 100. Geef de next_cursor van het antwoord terug als cursor voor de volgende pagina. Voeg platform en source_id samen toe (de source.media_id van een taak) om alleen de taken voor één video te zien, in elke modus. Zo controleert een client of de werkruimte al een transcriptie heeft voordat hij opnieuw indient.
Een taak annuleren#
/v1/jobs/{id}/cancelAnnuleert een taak waarvan de AI-transcriptie nog niet is gestart; de reservering wordt vrijgegeven. Daarna geeft hij 409 CANCELLATION_NOT_ALLOWED terug en maakt de taak af.
Een taak opnieuw proberen#
/v1/jobs/{id}/retryMaakt een nieuwe taak aan vanuit een mislukte taak waarvan de fout retryable was. Heeft een nieuwe Idempotency-Key nodig; optionele body { "max_credits": 40 }. Wordt geprijsd zoals een nieuwe taak. Definitieve fouten (privévideo, geen ondertitels) geven 409 JOB_NOT_RETRYABLE terug: pas de invoer aan en dien opnieuw in.
De transcriptie#
/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": "Voorbeeldvideo" },"source_origin": "creator_captions","language": "nl","text": "Welkom bij deze video. Vandaag bekijken we hoe het werkt.","segments": [{ "start": 0, "end": 2.4, "text": "Welkom bij deze video" },{ "start": 2.4, "end": 4.9, "text": "Vandaag bekijken we hoe het werkt" }],"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"}
Transcripties worden bewaard voor de bewaartermijn van je abonnement (7 dagen bij de proef, 30 bij Starter, 90 bij Pro en Scale). DELETE /v1/transcripts/{id} verwijdert er eerder één.
Een transcriptie exporteren#
/v1/transcripts/{id}/export?format=srt| format | Je krijgt |
|---|---|
| txt | Platte tekst, één segment per regel. |
| srt | SubRip-ondertitels. |
| vtt | WebVTT-ondertitels. |
| json | Het transcriptieobject hierboven. |
Gratis, onbeperkt. srt en vtt hebben timings nodig; een transcriptie zonder timings geeft 422 TIMESTAMPS_UNAVAILABLE terug.
Batches#
/v1/batchesEén verzoek, veel video's. Elk item heeft dezelfde velden als Een taak aanmaken; de hele batch wordt samen geaccepteerd of afgewezen. Items per batch: 1 bij de proef, 10 bij Starter, 25 bij Pro, 50 bij 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" }] }'
Het batchobject heeft status (queued, processing, succeeded, partial_success, failed, cancelled), aantallen (total_items, succeeded_items, failed_items, cancelled_items) en items, elk met zijn job_id. Lees het uit met GET /v1/batches/{id}; elk item is een gewone taak.
Uploads#
Je eigen audio of video (mp3, wav, m4a, ogg, aac, mp4, webm; tot 250 MB en 2 uur). Reserveer een plek, stuur het bestand met PUT naar de ondertekende URL, markeer het als voltooid en dien het daarna in als taak met source.upload_id. Uploads gebruiken altijd AI-transcriptie.
# 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" }'
De ondertekende URL is 24 uur geldig; reserveer daarna een nieuwe plek.
Webhooks#
/v1/webhook-endpointsRegistreer een https-URL en geef het id mee als webhook_endpoint_id wanneer je indient. Wij sturen een POST met een event zodra de taak of batch klaar is. Het antwoord bevat het ondertekeningsgeheim (secret) één keer. Endpoints registreren en uitschakelen vereist een ingelogde sessie, dus doe dat op de pagina Webhooks van het dashboard; een API-sleutel krijgt daar 403 FORBIDDEN, maar kan endpoints wel tonen.
Events#
{"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: haalresult_idop of exporteer hem.job.failed:errorbevat de code.batch.completed: elk item is definitief; lees de batch voor de resultaten per item.
Antwoord binnen enkele seconden met een 2xx. Mislukte leveringen worden met oplopende wachttijd opnieuw geprobeerd en kunnen vanuit het dashboard opnieuw worden verstuurd. Een event kan meer dan één keer binnenkomen: filter dubbelen op event_id.
De handtekening controleren#
Headers X-TranscriptDock-Event-Id, X-TranscriptDock-Timestamp en X-TranscriptDock-Signature. De handtekening is de HMAC-SHA256 (hex) van {event_id}.{timestamp}.{raw_body} met je geheim. Wijs alles af dat ouder is dan vijf minuten.
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));}
Video's zoeken#
/v1/video-discoveriesZoek op YouTube of toon een kanaal, afspeellijst of TikTok-profiel, en geef de URL's daarna door aan taken. Een videozoekopdracht draait op de achtergrond, net als een taak: lees hem uit met GET /v1/video-discoveries/{id} totdat status succeeded is. 1 credit per pagina; resultaten worden 24 uur bewaard.
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 }'
De POST antwoordt met 202 en status: "queued". Een afgeronde GET /v1/video-discoveries/{id} ziet er zo uit:
{"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"}
Ondertiteltalen van een video#
/v1/language-discoveriesBody { "source": { "url": "https://www.youtube.com/watch?v=..." } } met een Idempotency-Key (alleen YouTube, 1 credit). Lees GET /v1/language-discoveries/{id} voor de lijst met ondertiteltracks met hun codes, of ze van de maker of automatisch zijn, en welke de standaard is. Gebruik de codes in caption_languages.
Gebruik en mogelijkheden#
/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 houdt al geen rekening meer met credits_reserved (reserveringen voor lopende taken). prepaid_credits zijn gekochte credits; die verlopen nooit.
subscription is het Stripe-abonnement achter een betaald abonnement, en null zonder abonnement: de status, de facturatieperiode interval (monthly of yearly), cancel_at_period_end en current_period_end, wanneer het abonnement wordt verlengd of eindigt. period_end is het moment waarop de maandelijkse credits worden vernieuwd, elke maand, ook bij jaarabonnementen.
/v1/capabilitiesWat je sleutel nu kan: per bron (youtube, tiktok, instagram, upload, direct) welke modi beschikbaar zijn, plus limieten en prijzen. Lees dit uit in plaats van het vast in je code te zetten; de proef meldt bijvoorbeeld auto en 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"}
Limieten voor verzoeken#
| Abonnement | Verzoeken indienen / min | Taken in uitvoering | Lezen / min |
|---|---|---|---|
| Proef | 10 | 10 | 120 |
| Starter | 60 | 100 | 120 |
| Pro | 120 | 500 | 120 |
| Scale | 300 | 2,000 | 120 |
Bij een overschreden limiet krijg je 429 RATE_LIMITED met een retry-after-header (in seconden) en details.detail met de naam van de limiet. Er wordt niets afgeschreven. Webhooks en ?wait=25 houden je ver onder de leeslimiet.
Fouten#
Elke fout heeft dezelfde vorm. retryable: true betekent dat hetzelfde verzoek later kan slagen: wacht retry-after seconden als die er is, anders een paar seconden, en gebruik dezelfde Idempotency-Key opnieuw zodat er niets dubbel komt. Bij elke andere fout moet je iets aan je kant aanpassen.
{"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"}
Een taak die na acceptatie mislukt, krijgt nog steeds 200 bij GET /v1/jobs/{id}, met status: "failed" en hetzelfde foutobject in error. Voor een mislukte taak wordt niets afgeschreven.
Codes#
| Code | HTTP | Opnieuw | Betekenis en wat je doet |
|---|---|---|---|
INVALID_REQUEST | 422 | Nee | Een veld ontbreekt of heeft de verkeerde vorm. details.detail noemt het veld. |
INVALID_URL | 422 | Nee | De URL is geen geldige https-link (maximaal 2048 tekens). |
UNSUPPORTED_SOURCE | 422 | Nee | De link is geen YouTube- of TikTok-videolink. |
UNSAFE_URL | 422 | Nee | De directe medialink verwijst naar een privé- of geblokkeerd netwerkadres. |
INVALID_CURSOR | 422 | Nee | Een cursor van een videozoekopdracht is verlopen of onjuist. Begin opnieuw bij de eerste pagina. Een ongeldige cursor voor de takenlijst geeft INVALID_REQUEST. |
CAPABILITY_UNAVAILABLE | 422 | Nee | Deze modus is niet beschikbaar voor deze bron. GET /v1/capabilities laat zien wat wel beschikbaar is. |
IDEMPOTENCY_CONFLICT | 409 | Nee | Deze Idempotency-Key is al gebruikt met een andere body. Gebruik een nieuwe sleutel. |
UNAUTHENTICATED | 401 | Nee | Geen geldige API-sleutel of OAuth-token in de Authorization-header. |
FORBIDDEN | 403 | Nee | De sleutel mist de scope voor dit endpoint, of de werkruimte is uitgeschakeld. |
EMAIL_UNVERIFIED | 403 | Nee | Verifieer het e-mailadres van je account voordat je de API gebruikt. |
NOT_FOUND | 404 | Nee | Dit object bestaat niet in deze werkruimte. |
INSUFFICIENT_BALANCE | 402 | Nee | Niet genoeg credits voor deze taak. Koop credits of upgrade. |
PLAN_REQUIRED | 402 | Nee | Dit vereist een betaald abonnement (AI-transcriptie, grotere batches) of de proefcredits zijn op. |
BUDGET_EXCEEDED | 402 | Nee | De gemeten kosten zijn hoger dan max_credits. Er is niets afgeschreven; verhoog de limiet of sla de media over. |
JOB_NOT_RETRYABLE | 409 | Nee | De fout was definitief (privévideo, geen ondertitels). Pas de invoer aan en dien een nieuwe taak in. |
CANCELLATION_NOT_ALLOWED | 409 | Nee | AI-transcriptie is al gestart; de taak wordt afgemaakt. |
RATE_LIMITED | 429 | Ja | Een snelheids- of wachtrijlimiet is overschreden. Wacht retry-after seconden; details.detail zegt welke limiet. |
SOURCE_NOT_FOUND | 422 | Nee | De video bestaat niet of is verwijderd. |
SOURCE_PRIVATE | 422 | Nee | De video is privé. Alleen openbare video's werken. |
SOURCE_AUTH_REQUIRED | 422 | Nee | De video vereist inloggen, een leeftijdscontrole of een lidmaatschap. |
SOURCE_REGION_RESTRICTED | 422 | Nee | De video is geblokkeerd in de regio's waaruit wij ophalen. |
NO_CAPTIONS | 422 | Nee | Deze video heeft geen ondertitels en de modus was captions_only. Gebruik auto of transcribe. |
LANGUAGE_UNAVAILABLE | 422 | Nee | Geen van de caption_languages bestaat voor deze video. Laat de lijst weg om de standaardtrack te gebruiken. |
LANGUAGE_UNSUPPORTED | 422 | Nee | AI-transcriptie ondersteunt de gevraagde taal niet. |
NO_SPEECH | 422 | Nee | AI-transcriptie heeft geen spraak in de audio gevonden. |
NO_AUDIO | 422 | Nee | De media heeft geen audiotrack. |
INVALID_MEDIA | 422 | Nee | Het bestand kon niet worden gelezen als audio of video. |
UNSUPPORTED_MEDIA | 422 | Nee | Geen ondersteund audio- of videobestandstype. |
DURATION_LIMIT_EXCEEDED | 413 | Nee | Langer dan 2 uur. |
FILE_TOO_LARGE | 413 | Nee | Groter dan 250 MB. |
TIMESTAMPS_UNAVAILABLE | 422 | Nee | Deze transcriptie heeft geen timings, dus srt- en vtt-exports zijn niet beschikbaar. Gebruik txt of json. |
PROVIDER_REJECTED | 422 | Nee | Het AI-transcriptiemodel kon deze audio niet verwerken. |
SOURCE_RATE_LIMITED | 503 | Ja | Het bronplatform beperkt ons verkeer. De taak probeert het automatisch opnieuw. |
SOURCE_BLOCKED | 503 | Ja | Het bronplatform heeft het ophalen geblokkeerd. De taak probeert het automatisch opnieuw. |
SOURCE_TIMEOUT | 503 | Ja | Het bronplatform reageerde niet op tijd. De taak probeert het automatisch opnieuw. |
SOURCE_CHANGED | 503 | Ja | De bron veranderde terwijl we die lazen. De taak probeert het automatisch opnieuw. |
PROVIDER_UNAVAILABLE | 503 | Ja | AI-transcriptie is tijdelijk niet beschikbaar. De taak probeert het automatisch opnieuw. |
STORAGE_UNAVAILABLE | 503 | Ja | Bestandsopslag is tijdelijk niet beschikbaar. Stuur het verzoek opnieuw. |
INTERNAL_ERROR | 500 | Ja | Dit is onze fout. Probeer het opnieuw met dezelfde Idempotency-Key; vermeld X-Request-Id als het probleem aanhoudt. |