DocumentatieREST API-referentie

REST API-referentie

Zoek parameters en voorbeelden voor elk /v1-endpoint op. De OpenAPI-specificatie is beschikbaar als JSON en YAML.

Inleiding

Basis-URL
https://api.transcript1.com/v1

Gebruik https://api.transcript1.com/v1 als basis-URL voor je requests.

  • Je verstuurt en ontvangt JSON, met veldnamen in snake_case.
  • Datums en tijdstempels gebruiken ISO 8601 in UTC, zoals 2026-10-13T09:30:00.000Z.
  • De duur van een opname en de tijden in een transcript zijn in seconden.
  • Foutresponses hebben een vaste opbouw. Die vind je onder Fouten.
  • Elke response op een geauthenticeerd request bevat X-RateLimit-Limit en X-RateLimit-Remaining. Lees meer over minuten, abonnementen en limieten.
  • Met source=auto proberen we op YouTube, X, TikTok, Bluesky, Dailymotion en LinkedIn eerst bruikbare ondertitels in de oorspronkelijke taal. Zijn die er niet, dan gebruiken we speech-to-text. Niet elke video heeft ondertitels. Met captions (alleen ondertitels) halen we nooit audio op en schakelen we niet over op STT. Zonder bruikbaar spoor krijg je no_captions. Met source=stt of sprekerherkenning kies je meteen voor audio. In Bronnen en instellingen lees je welke beperkingen gelden en wanneer je tijdstempels per segment of per woord krijgt.

Wil je de API-specificatie in je eigen tooling gebruiken? Download OpenAPI als:

Authenticatie

curl https://api.transcript1.com/v1/account \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY"

Geef je API-sleutel of token mee in de Authorization-header, als Authorization: Bearer <token>.

  • API-sleutel: begint met t1_ en geeft toegang tot alle endpoints. Maak een sleutel aan op “API keys”.
  • OAuth-toegangstoken: begint met t1o_. Clients zoals Claude en ChatGPT krijgen dit wanneer je ze via MCP koppelt. Het token gebruikt de scopes transcriptions:read en transcriptions:write.
ScopeToegang tot
transcriptions:readGET /v1/transcriptions, GET /v1/transcriptions/:id, GET /v1/transcriptions/:id/upload en GET /v1/account
transcriptions:writePOST /v1/transcriptions, DELETE /v1/transcriptions/:id en POST /v1/transcriptions/:id/upload/complete
  • Mist het token de scope die je nodig hebt, dan krijg je 403 insufficient_scope.
  • Ontbreekt de sleutel of het token, of is die ongeldig, dan krijg je 401 unauthorized.

Voor het versturen van chunks gebruik je een ander token. Geef bij PUT /v1/transcriptions/:id/upload/chunks/:index de header X-Upload-Token mee. Je krijgt dat token bij het aanmaken van de upload. De stappen staan bij Bestanden uploaden.

Idempotentie

curl -X POST https://api.transcript1.com/v1/transcriptions \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY" \
  -H "Idempotency-Key: 5f1c2b0e-8d4a-4c3e-9b7a-2e6f1d0c9a8b" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://www.youtube.com/watch?v=dQw4w9WgXcQ"}'

Geef bij POST /v1/transcriptions een Idempotency-Key-header mee. Dan kun je het request veilig herhalen.

Kies een waarde van 1 tot 255 tekens en stuur die als header, niet als queryparameter.

  • Herhaal je het request met dezelfde sleutel en parameters, dan krijg je de oorspronkelijke transcriptie terug en betaal je niet opnieuw.
  • Gebruik je dezelfde sleutel met andere parameters, dan krijg je 409 idempotency_conflict.
  • Maak je een upload in chunks aan, dan levert hetzelfde request met dezelfde sleutel een nieuw uploadtoken op.

Foutmeldingen

402 Payment Required
{
  "error": {
    "code": "insufficient_minutes",
    "message": "Not enough minutes",
    "retryable": false,
    "action_url": "https://transcript1.com/dashboard/billing",
    "minutes_needed": 20,
    "minutes_remaining": 3
  }
}
  • Een fout bij een request betekent dat de API je aanroep meteen weigert.
  • Een fout tijdens de transcriptie ontstaat pas nadat de API die heeft geaccepteerd. Dan staat status op failed.

Zo ziet een foutresponse eruit

Bij een geweigerd /v1-request krijg je een error-object met code, message en retryable.

  • Laat je code reageren op code.
  • Gebruik message voor de uitleg aan de gebruiker. De tekst kan veranderen.
  • Staat retryable op true, dan kan hetzelfde request later wel slagen.

Afhankelijk van de fout krijg je naast retryable extra velden:

VeldFoutcodeWat staat erin?
action_urlinsufficient_minutesDe link om een abonnement te nemen of minuten bij te kopen.
minutes_needed, minutes_remaininginsufficient_minutesHet aantal benodigde minuten en je huidige saldo. Het benodigde aantal is null zolang de duur nog onbekend is.
supported_platformsunsupported_platformDe toegestane platforms: ["youtube", "x", "tiktok", "instagram", "facebook", "bluesky", "twitch", "dailymotion", "pinterest", "linkedin", "snapchat"].
missing_chunksupload_incompleteDe indexen van de chunks die de server nog mist.
max_bytesmedia_too_largeJouw maximale bestandsgrootte in bytes.
paramsinvalid_requestBij ongeldige body- of queryvelden een object dat per veld uitlegt wat je moet aanpassen.

Wanneer de API je request weigert

HTTP-statuscodeOpnieuw proberen?Oorzaak
400, 422invalid_requestNeeEen parameter of bodyveld ontbreekt of is ongeldig. Dit geldt ook voor ongeldige JSON en combinaties zoals diarize met source: "captions" of reuse_recent met webhook_url.
422invalid_urlNeeDe link is niet geldig of komt niet overeen met platform. Gebruik YouTube, X, TikTok, Instagram, Facebook, Bluesky of een ander platform uit Bronnen en instellingen.
422unsupported_platformNeeDe opgegeven waarde voor platform is niet toegestaan.
422unsupported_mediaNeeDe bestandsextensie wordt niet ondersteund.
401unauthorizedNeeJe API-sleutel of token ontbreekt, is ongeldig, verlopen of ingetrokken. Ook een ongeldig of verlopen uploadtoken geeft deze fout.
403insufficient_scopeNeeHet OAuth-token heeft geen transcriptions:read of transcriptions:write waar die scope nodig is.
403email_not_verifiedNeeJe moet eerst je e-mailadres bevestigen om transcripties te kunnen starten.
402insufficient_minutesNeeJe beschikbare saldo is 0 of je hebt te weinig minuten voor deze transcriptie.
402no_active_planNeeJe wilt minuten bijkopen, maar hebt geen actief betaald abonnement. Alleen het billing-endpoint van het dashboard geeft deze fout, niet de transcriptie-endpoints.
404not_foundNeeDe transcriptie bestaat niet of is van een ander team.
409upload_incompleteNeeDe server mist nog chunks. Verstuur die en rond de upload daarna opnieuw af.
409invalid_stateNeeDe transcriptie wacht niet meer op een upload. Je kunt geen chunks meer sturen en de upload niet meer afronden.
409idempotency_conflictNeeJe hebt deze Idempotency-Key eerder met andere parameters gebruikt.
413media_too_largeNeeHet bestand overschrijdt je uploadlimiet. Bekijk Bestanden uploaden.
413invalid_requestNeeDe JSON-body is groter dan 1 MB. Bij te grote bestanden krijg je media_too_large.
429rate_limitedJaJe stuurt te veel requests per minuut. Wacht het aantal seconden uit Retry-After.
429too_many_active_jobsJaEr lopen te veel transcripties of er staan te veel uploads open. Wacht het aantal seconden uit Retry-After.
500internal_errorJaEr gaat iets mis bij transcript1. Probeer het na een korte pauze opnieuw.
503service_unavailableJatranscript1 is even niet beschikbaar. Probeer het na een korte pauze opnieuw.

Bij browserrequests met een inlogcookie controleren we ook vanaf welke site het request komt. Een andere site krijgt 403 forbidden_origin.

Voor API-requests met een Authorization-header geldt die controle niet.

In elke 429-response staat Retry-After: het aantal seconden dat je moet wachten. De limieten zelf vind je bij Minuten, abonnementen en limieten.

Wanneer stuur je een request opnieuw?

  • Herhaal alleen requests met retryable op true: rate_limited, too_many_active_jobs, internal_error en service_unavailable.
  • Houd de wachttijd uit Retry-After aan. Ontbreekt die header, wacht dan bij elke poging langer.
  • Gebruik bij het herhalen van POST /v1/transcriptions dezelfde Idempotency-Key-header. Zo betaal je niet dubbel als het eerste request toch is gelukt.
  • Pas bij alle andere codes eerst je request aan voordat je het nog eens verstuurt.

Als een transcriptie later mislukt

Loopt een transcriptie vast, dan staat status op failed. In het error-object staan code en message.

Ook na een geslaagd request kan de transcriptie nog mislukken. Controleer error dus tijdens het pollen of bij een webhook van het type transcription.failed.

error.codeWat is er mis?Wat kun je doen?
media_unavailableDe video bestaat niet of is niet meer beschikbaar.Niet opnieuw proberen. Controleer de URL.
media_privateDe video is afgeschermd.Gebruik een openbare post of een openbare of verborgen YouTube-video. Hetzelfde request herhalen helpt niet.
login_requiredJe moet op het platform ingelogd zijn om de video te bekijken.Niet opnieuw proberen. Deze fout is definitief; we proberen het niet automatisch opnieuw.
no_audioEr zit geen audiospoor in de video.Niet opnieuw proberen. Deze fout is definitief; we proberen het niet automatisch opnieuw.
age_restrictedDe video heeft een leeftijdsbeperking.Hetzelfde request herhalen helpt niet. Upload het bestand.
live_streamDe uitzending loopt nog of is nog niet begonnen.Probeer het na afloop van de uitzending.
no_captionsJe zette source op captions, maar er is geen bruikbaar ondertitelspoor.Kies source: "auto" of "stt".
media_too_longDe opname duurt langer dan de 5 uur die speech-to-text aankan.Splits het bestand. Hetzelfde request herhalen helpt niet.
unsupported_mediaHet bestand is niet leesbaar of heeft geen audiospoor.Stuur een ondersteund bestand; herhaal niet hetzelfde request.
no_speechGeen spraak gedetecteerd.Niet opnieuw proberen.
unsupported_languageWe ondersteunen de taal van deze opname niet.Kies voor language een ondersteunde code of "auto"; probeer niet opnieuw met dezelfde instelling.
insufficient_minutesJe saldo was op voordat we de minuten konden afschrijven.Koop eerst minuten bij en probeer het dan opnieuw.
fetch_failedOok na meerdere pogingen konden we de opname niet ophalen.Probeer het later opnieuw.
transcription_failedOok na meerdere pogingen lukte speech-to-text niet.Probeer het later opnieuw.

Mislukt een transcriptie of annuleer je die, dan betaal je niets. Hadden we al minuten afgeschreven, dan krijg je die terug.

Object Transcription

Object Transcription
{
  "id": "tr_4fHq8ZbN2xLm0PqRsTuVwX",
  "object": "transcription",
  "status": "completed",
  "source": {
    "platform": "youtube",
    "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "media_id": "dQw4w9WgXcQ"
  },
  "media": {
    "title": "Example video",
    "author": "Example channel",
    "author_url": "https://www.youtube.com/@examplechannel",
    "thumbnail_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
    "duration_seconds": 212
  },
  "options": {
    "source": "auto",
    "language": "auto",
    "diarize": false
  },
  "transcript_source": "youtube_captions",
  "caption_kind": "auto_generated",
  "language": "en",
  "billed_minutes": 4,
  "cached": false,
  "error": null,
  "created_at": "2026-10-13T09:30:00.000Z",
  "completed_at": "2026-10-13T09:30:04.000Z",
  "deleted_at": null,
  "transcript": {
    "text": "Welcome back to the channel. Today we are looking at how transcripts are made.",
    "speakers": [],
    "segments": [
      {
        "start": 0,
        "end": 4.2,
        "speaker": null,
        "language": "en",
        "text": "Welcome back to the channel."
      },
      {
        "start": 4.2,
        "end": 9.8,
        "speaker": null,
        "language": "en",
        "text": "Today we are looking at how transcripts are made."
      }
    ]
  }
}

Velden

  • idstringverplicht
  • objectstringverplicht

    Toegestane waardentranscription

  • statusstringverplicht

    Toegestane waardenawaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled

  • sourceobjectverplicht
    Geneste velden tonen
    With url
    • platformstringverplicht
    • urlstringverplichtnullable
    • media_idstringverplichtnullable
    With filename
    • platformstringverplicht

      Toegestane waardenupload

    • filenamestringverplichtnullable
    • sizenumberverplichtnullable
  • mediaobjectverplichtnullable
    Geneste velden tonen
    • titlestringoptioneelnullable
    • authorstringoptioneelnullable
    • author_urlstringoptioneelnullable
    • thumbnail_urlstringoptioneelnullable
    • filenamestringoptioneel
    • mime_typestringoptioneel
    • sizenumberoptioneel
    • duration_secondsnumberoptioneelnullable
  • optionsobjectverplicht
    Geneste velden tonen
    • sourcestringverplicht

      Toegestane waardenautocaptionsstt

    • languagestringverplicht
    • diarizebooleanverplicht
  • transcript_sourcestringverplichtnullable

    Toegestane waardenyoutube_captionsx_captionsspeech_to_text

  • caption_kindstringverplichtnullable

    Toegestane waardenmanualauto_generated

  • languagestringverplichtnullable
  • billed_minutesintegerverplichtnullable
  • cachedbooleanverplicht
  • errorobjectverplichtnullable
    Geneste velden tonen
    • codestringverplicht
    • messagestringverplichtnullable
  • created_atstring · date-timeverplichtnullable
  • completed_atstring · date-timeverplichtnullable
  • deleted_atstring · date-timeverplichtnullable

    When the transcription was deleted. Always null unless the request includes include_deleted=true.

  • transcriptobjectoptioneel

    Included in GET responses for completed transcriptions.

    Geneste velden tonen
    • textstringverplicht
    • speakersarray of stringsverplicht
    • segmentsarray of objectsverplicht
      Geneste velden tonen
      • startnumberverplicht
      • endnumberverplicht
      • speakerstringverplichtnullable
      • languagestringverplichtnullable
      • textstringverplicht
      • wordsarray of objectsoptioneelnullable
        Geneste velden tonen
        • startnumberverplicht
        • endnumberverplicht
        • textstringverplicht
        • confidencenumberoptioneelnullable
        • speakerstringverplichtnullable

Transcriptions

Create, read, list and delete transcriptions of video links and uploaded files.

Create a transcription

POST /v1/transcriptions

Transcribes an uploaded file or a YouTube, X, TikTok, Instagram, Facebook, Bluesky, Twitch, Dailymotion, Pinterest, LinkedIn, Snapchat link. Social posts must be public; only the first video is used.

Twitch accepts clips and completed VODs; Pinterest accepts native video pins; LinkedIn accepts public video posts; Snapchat accepts Spotlight. New platforms require public recorded native media without supplied account cookies; no live streams or external embeds.

platform is optional and detected from the link. Captions are YouTube/X-only. All sources use the same per-minute price.

Returns 200 for a final result, 201 when awaiting an upload and 202 while processing. Pass wait to wait up to 60 seconds for a final status.

Pass reuse_recent=true with a platform URL to reuse a transcription of the same video and options from the last 24 hours. The response includes reused: true, with no additional charge. Short links may not be matched. An Idempotency-Key replay takes precedence.

curl -X POST https://api.transcript1.com/v1/transcriptions \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://www.youtube.com/watch?v=dQw4w9WgXcQ"}'
{
  "id": "tr_4fHq8ZbN2xLm0PqRsTuVwX",
  "object": "transcription",
  "status": "queued",
  "source": {
    "platform": "youtube",
    "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "media_id": "dQw4w9WgXcQ"
  },
  "media": null,
  "options": {
    "source": "auto",
    "language": "auto",
    "diarize": false
  },
  "transcript_source": null,
  "caption_kind": null,
  "language": null,
  "billed_minutes": null,
  "cached": false,
  "error": null,
  "created_at": "2026-10-13T09:30:00.000Z",
  "completed_at": null,
  "deleted_at": null,
  "reused": false
}

Query

  • waitintegeroptioneelnullableStandaard: 0

    Seconds to wait for a final status before responding, up to 60. Defaults to 0.

  • reuse_recentstringoptioneelStandaard: false

    For platform URLs only. Cannot be combined with webhook_url. Returns the team's most recent transcription of the same video with the same source, language and diarize. It must have been created in the last 24 hours and must not be failed or canceled. Reuses that transcription without creating or charging for a new one.

    Toegestane waardentruefalse

Headers

  • Idempotency-Keystringoptioneel

    Returns the original transcription when you repeat a request with the same key and parameters.

Body

With url
  • platformstringoptioneel

    Optional; detected from the link. If supplied, must match the link.

    Toegestane waardenyoutubextiktokinstagramfacebookblueskytwitchdailymotionpinterestlinkedinsnapchat

  • urlstringverplicht

    YouTube, X, TikTok, Instagram, Facebook, Bluesky, Twitch, Dailymotion, Pinterest, LinkedIn, Snapchat video link. Social posts must be public; only the first video is used. New platforms support public recorded native video without supplied account cookies, not live streams or external embeds.

  • sourcestringoptioneel

    "auto" uses YouTube or X captions when available, otherwise speech-to-text. "captions" is YouTube/X-only. "stt" always uses speech-to-text.

    Toegestane waardenautocaptionsstt

  • languagestringoptioneel
  • diarizebooleanoptioneel
  • webhook_urlstring · urioptioneel
With upload
  • uploadobjectverplicht
    Geneste velden tonen
    • filenamestringverplicht
    • sizeintegerverplicht
    • mime_typestringoptioneel
  • sourcestringoptioneel

    Toegestane waardenautostt

  • languagestringoptioneel
  • diarizebooleanoptioneel
  • webhook_urlstring · urioptioneel
multipart/form-data
  • filestring · binaryverplicht
  • sourcestringoptioneel

    Toegestane waardenautostt

  • languagestringoptioneel
  • diarizebooleanoptioneel
  • webhook_urlstring · urioptioneel

Statuscodes

  • 200 OK — The transcription reached a final status
  • 201 Created — The transcription is awaiting a chunked upload. upload describes where to send each chunk.
  • 202 Accepted — The transcription is processing

Overige statuscodes

  • 400 Bad Request — The JSON request body is malformed
  • 401 Unauthorized — Missing or invalid credential
  • 402 Payment Required — Not enough minutes. Applies to every request body format.
  • 403 Forbidden — Insufficient scope, unverified email, cross-site request or a single-member team plan
  • 409 Conflict — Idempotency-Key was reused with different parameters.
  • 413 Content Too Large — The upload or the JSON request body is too large
  • 422 Unprocessable Content — Invalid request, URL, platform or file type
  • 429 Too Many Requests — Too many requests or too many active transcriptions. Wait for the number of seconds in Retry-After.

Get a transcription

GET /v1/transcriptions/{id}

Returns the transcription object. Completed transcriptions include the transcript. Use format to render it as text, SRT or WebVTT.

If you request a rendered format before completion, the response is JSON. It returns 202 while processing or 200 if the transcription failed or was canceled.

With include_deleted=true, a deleted transcription is returned as a record without a transcript. For deleted records, wait is ignored and rendered formats return 404.

curl https://api.transcript1.com/v1/transcriptions/tr_4fHq8ZbN2xLm0PqRsTuVwX \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY"
{
  "id": "tr_4fHq8ZbN2xLm0PqRsTuVwX",
  "object": "transcription",
  "status": "completed",
  "source": {
    "platform": "youtube",
    "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "media_id": "dQw4w9WgXcQ"
  },
  "media": {
    "title": "Example video",
    "author": "Example channel",
    "author_url": "https://www.youtube.com/@examplechannel",
    "thumbnail_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
    "duration_seconds": 212
  },
  "options": {
    "source": "auto",
    "language": "auto",
    "diarize": false
  },
  "transcript_source": "youtube_captions",
  "caption_kind": "auto_generated",
  "language": "en",
  "billed_minutes": 4,
  "cached": false,
  "error": null,
  "created_at": "2026-10-13T09:30:00.000Z",
  "completed_at": "2026-10-13T09:30:04.000Z",
  "deleted_at": null,
  "transcript": {
    "text": "Welcome back to the channel. Today we are looking at how transcripts are made.",
    "speakers": [],
    "segments": [
      {
        "start": 0,
        "end": 4.2,
        "speaker": null,
        "language": "en",
        "text": "Welcome back to the channel."
      },
      {
        "start": 4.2,
        "end": 9.8,
        "speaker": null,
        "language": "en",
        "text": "Today we are looking at how transcripts are made."
      }
    ]
  }
}

Path

  • idstringverplicht

Query

  • waitintegeroptioneelnullableStandaard: 0

    Seconds to wait for a final status before responding, up to 60. Defaults to 0.

  • formatstringoptioneelStandaard: json

    Toegestane waardenjsontextsrtvtt

  • includestringoptioneel

    Toegestane waardenwords

  • timestampsstringoptioneelStandaard: false

    Toegestane waardentruefalse

  • include_deletedstringoptioneelStandaard: false

    Also returns deleted transcriptions as read-only records without a transcript. Their deleted_at is set. Defaults to false.

    Toegestane waardentruefalse

Statuscodes

  • 200 OK — The transcription, or the rendered transcript
  • 202 Accepted — A rendered format was requested while the transcription is still processing

Overige statuscodes

  • 401 Unauthorized — Missing or invalid credential
  • 403 Forbidden — Insufficient scope or a single-member team plan
  • 404 Not Found — Transcription not found
  • 422 Unprocessable Content — Invalid query parameters
  • 429 Too Many Requests — Too many requests. Wait for the number of seconds in Retry-After.

List transcriptions

GET /v1/transcriptions

Lists your team's transcriptions, newest first, without transcripts. Pass next_cursor as cursor to get the next page.

Deleted transcriptions are hidden unless you pass include_deleted=true.

curl https://api.transcript1.com/v1/transcriptions \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY"
{
  "object": "list",
  "data": [
    {
      "id": "tr_4fHq8ZbN2xLm0PqRsTuVwX",
      "object": "transcription",
      "status": "completed",
      "source": {
        "platform": "youtube",
        "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
        "media_id": "dQw4w9WgXcQ"
      },
      "media": {
        "title": "Example video",
        "author": "Example channel",
        "author_url": "https://www.youtube.com/@examplechannel",
        "thumbnail_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
        "duration_seconds": 212
      },
      "options": {
        "source": "auto",
        "language": "auto",
        "diarize": false
      },
      "transcript_source": "youtube_captions",
      "caption_kind": "auto_generated",
      "language": "en",
      "billed_minutes": 4,
      "cached": false,
      "error": null,
      "created_at": "2026-10-13T09:30:00.000Z",
      "completed_at": "2026-10-13T09:30:04.000Z",
      "deleted_at": null
    }
  ],
  "next_cursor": "eyJjcmVhdGVkQXQiOiIyMDI2LTEwLTEzVDA5OjMwOjAwLjAwMFoiLCJpZCI6IjViMGU2YzFjLTBkNmYtNGMxZi05YjVlLThmM2Y0ZDBhN2ExMSJ9"
}

Query

  • limitintegeroptioneelStandaard: 20
  • cursorstringoptioneel
  • statusstringoptioneel

    Toegestane waardenawaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled

  • platformstringoptioneel
  • include_deletedstringoptioneelStandaard: false

    Also returns deleted transcriptions as read-only records without a transcript. Their deleted_at is set. Defaults to false.

    Toegestane waardentruefalse

Statuscodes

  • 200 OK — A page of transcriptions

Overige statuscodes

  • 401 Unauthorized — Missing or invalid credential
  • 403 Forbidden — Insufficient scope or a single-member team plan
  • 422 Unprocessable Content — Invalid query parameters or cursor
  • 429 Too Many Requests — Too many requests. Wait for the number of seconds in Retry-After.

Cancel or delete a transcription

DELETE /v1/transcriptions/{id}

Cancels an active transcription or one awaiting an upload. Any charged minutes are refunded.

Deletes a completed, failed or canceled transcription together with its stored transcript.

curl -X DELETE https://api.transcript1.com/v1/transcriptions/tr_4fHq8ZbN2xLm0PqRsTuVwX \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY"

Geen body in de response

Path

  • idstringverplicht

Statuscodes

  • 204 No Content — Canceled or deleted

Overige statuscodes

  • 401 Unauthorized — Missing or invalid credential
  • 403 Forbidden — Insufficient scope, cross-site request or a single-member team plan
  • 404 Not Found — Transcription not found
  • 429 Too Many Requests — Too many requests. Wait for the number of seconds in Retry-After.

Uploads

Send a large file in chunks. Start with Create a transcription using an upload body. Send each chunk, then complete the upload.

Upload one chunk

PUT /v1/transcriptions/{id}/upload/chunks/{index}

Sends one chunk of a chunked upload as application/octet-stream.

Authenticate with the X-Upload-Token from the create response. This endpoint does not use a bearer credential.

The body must match the planned chunk size exactly. Sending a chunk again replaces it.

curl -X PUT https://api.transcript1.com/v1/transcriptions/tr_4fHq8ZbN2xLm0PqRsTuVwX/upload/chunks/0 \
  -H "X-Upload-Token: t1u_Zk3vYb8Nw1ZrT5xLpD0aHcE7sUj9GfMiO2yXtVnR4Bw" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @chunk-0.bin
{
  "object": "upload_chunk",
  "index": 0,
  "size": 838860
}

Path

  • idstringverplicht
  • indexintegeroptioneelnullable

    Zero-based chunk number from the upload plan

Headers

  • X-Upload-Tokenstringverplicht

Body

  • (raw body)string · binaryverplicht

Statuscodes

  • 200 OK — The chunk was stored

Overige statuscodes

  • 401 Unauthorized — Missing, invalid or expired upload token
  • 404 Not Found — Transcription not found
  • 409 Conflict — The transcription is no longer awaiting an upload
  • 422 Unprocessable Content — Index outside the chunk plan or wrong body size

Get upload progress

GET /v1/transcriptions/{id}/upload

Lists the received chunks of a chunked upload so an interrupted upload can resume.

curl https://api.transcript1.com/v1/transcriptions/tr_4fHq8ZbN2xLm0PqRsTuVwX/upload \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY"
{
  "object": "upload",
  "status": "awaiting_upload",
  "total_bytes": 48210334,
  "uploaded_bytes": 4194300,
  "received_chunks": [
    0,
    1,
    2,
    3,
    4
  ],
  "chunks": [
    {
      "index": 0,
      "offset": 0,
      "size": 838860
    },
    {
      "index": 1,
      "offset": 838860,
      "size": 838860
    },
    {
      "index": 2,
      "offset": 1677720,
      "size": 838860
    },
    {
      "index": 3,
      "offset": 2516580,
      "size": 838860
    },
    {
      "index": 4,
      "offset": 3355440,
      "size": 838860
    },
    {
      "index": 5,
      "offset": 4194300,
      "size": 8388608
    },
    {
      "index": 6,
      "offset": 12582908,
      "size": 8388608
    },
    {
      "index": 7,
      "offset": 20971516,
      "size": 8388608
    },
    {
      "index": 8,
      "offset": 29360124,
      "size": 8388608
    },
    {
      "index": 9,
      "offset": 37748732,
      "size": 8388608
    },
    {
      "index": 10,
      "offset": 46137340,
      "size": 2072994
    }
  ],
  "expires_at": "2026-10-13T10:30:00.000Z"
}

Path

  • idstringverplicht

Statuscodes

  • 200 OK — Upload progress

Overige statuscodes

  • 401 Unauthorized — Missing or invalid credential
  • 403 Forbidden — Insufficient scope or a single-member team plan
  • 404 Not Found — Transcription or upload not found
  • 429 Too Many Requests — Too many requests. Wait for the number of seconds in Retry-After.

Complete a chunked upload

POST /v1/transcriptions/{id}/upload/complete

Checks that every planned chunk arrived with the planned size. Then assembles the file and queues the transcription.

curl -X POST https://api.transcript1.com/v1/transcriptions/tr_4fHq8ZbN2xLm0PqRsTuVwX/upload/complete \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY"
{
  "id": "tr_4fHq8ZbN2xLm0PqRsTuVwX",
  "object": "transcription",
  "status": "queued",
  "source": {
    "platform": "upload",
    "filename": "interview.m4a",
    "size": 48210334
  },
  "media": {
    "filename": "interview.m4a",
    "mime_type": "audio/mp4",
    "size": 48210334
  },
  "options": {
    "source": "auto",
    "language": "auto",
    "diarize": false
  },
  "transcript_source": null,
  "caption_kind": null,
  "language": null,
  "billed_minutes": null,
  "cached": false,
  "error": null,
  "created_at": "2026-10-13T09:30:00.000Z",
  "completed_at": null,
  "deleted_at": null
}

Path

  • idstringverplicht

Statuscodes

  • 202 Accepted — The transcription is queued

Overige statuscodes

  • 401 Unauthorized — Missing or invalid credential
  • 402 Payment Required — Not enough minutes to queue the transcription. The upload stays awaiting completion.
  • 403 Forbidden — Insufficient scope, cross-site request or a single-member team plan
  • 404 Not Found — Transcription or upload not found
  • 409 Conflict — upload_incomplete means chunks are missing. missing_chunks lists them. invalid_state means the transcription is not awaiting an upload.
  • 429 Too Many Requests — Too many requests or too many active transcriptions. Wait for the number of seconds in Retry-After.

Account

Your plan, remaining minutes and rate limits.

Get your account

GET /v1/account

Returns the authenticated user, current plan and remaining transcription minutes.

curl https://api.transcript1.com/v1/account \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY"
{
  "object": "account",
  "user": {
    "id": "5b0e6c1c-0d6f-4c1f-9b5e-8f3f4d0a7a11",
    "email": "[email protected]"
  },
  "plan": {
    "id": "9d4e0c0a-2b8a-4f0c-8d63-6a8d3c8a1f22",
    "name": "Monthly"
  },
  "minutes": {
    "remaining": 1180,
    "cycle": 980,
    "topup": 200,
    "topup_usable": true,
    "resets_at": "2026-11-13T09:30:00.000Z"
  },
  "renews_at": "2026-11-13T09:30:00.000Z",
  "limits": {
    "requests_per_minute": 200,
    "max_active_jobs": 10
  }
}

Statuscodes

  • 200 OK — The authenticated user's account

Overige statuscodes

  • 401 Unauthorized — Missing or invalid credential
  • 403 Forbidden — Insufficient scope or a single-member team plan
  • 404 Not Found — No account found
  • 429 Too Many Requests — Too many requests. Wait for the number of seconds in Retry-After.

Object Account

Object Account
{
  "object": "account",
  "user": {
    "id": "5b0e6c1c-0d6f-4c1f-9b5e-8f3f4d0a7a11",
    "email": "[email protected]"
  },
  "plan": {
    "id": "9d4e0c0a-2b8a-4f0c-8d63-6a8d3c8a1f22",
    "name": "Monthly"
  },
  "minutes": {
    "remaining": 1180,
    "cycle": 980,
    "topup": 200,
    "topup_usable": true,
    "resets_at": "2026-11-13T09:30:00.000Z"
  },
  "renews_at": "2026-11-13T09:30:00.000Z",
  "limits": {
    "requests_per_minute": 200,
    "max_active_jobs": 10
  }
}

Velden

  • objectstringverplicht

    Toegestane waardenaccount

  • userobjectverplicht
    Geneste velden tonen
    • idstringverplicht
    • emailstringverplicht
  • planobjectverplichtnullable
    Geneste velden tonen
    • idstringverplicht
    • namestringverplicht
  • minutesobjectverplicht
    Geneste velden tonen
    • remainingnumberverplicht
    • cyclenumberverplicht
    • topupnumberverplicht
    • topup_usablebooleanverplicht
    • resets_atstring · date-timeverplichtnullable
  • renews_atstring · date-timeverplichtnullable
  • limitsobjectverplicht
    Geneste velden tonen
    • requests_per_minutenumberverplicht
    • max_active_jobsnumberverplicht

Webhooks

import { Buffer } from 'node:buffer';
import crypto from 'node:crypto';

// header: X-Transcript1-Signature, rawBody: the request body exactly as received,
// secret: your full signing secret including the whsec_ prefix.
export const verifySignature = (secret, header, rawBody, nowSeconds = Math.floor(Date.now() / 1000)) => {
  const fields = Object.fromEntries(header.split(',').map(part => part.trim().split('=')));
  const t = Number(fields.t);

  if (!Number.isInteger(t) || !fields.v1 || Math.abs(nowSeconds - t) > 300) {
    return false;
  }

  const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');

  return fields.v1.length === expected.length
    && crypto.timingSafeEqual(Buffer.from(fields.v1), Buffer.from(expected));
};
transcription.completed
{
  "type": "transcription.completed",
  "created_at": "2026-10-13T09:30:04.000Z",
  "data": {
    "id": "tr_8fK2Lm0PqRsTuVwXyZaBcD",
    "object": "transcription",
    "status": "completed",
    "transcript_source": "youtube_captions",
    "billed_minutes": 4,
    "error": null
  }
}

Met webhook_url laat je je server weten wanneer de transcriptie klaar is. Geef die URL mee bij het aanmaken. Bij een geslaagde of mislukte transcriptie stuurt transcript1 daar een ondertekend POST-request naartoe.

Je kunt webhooks alleen via de REST API instellen. De MCP-server heeft hiervoor geen parameter.

Geef je webhook-URL mee

Bij POST /v1/transcriptions geef je webhook_url op deze manier mee:

  • Bij een ondersteunde videolink of het aanmaken van een upload in chunks: in de JSON-body.
  • Bij een bestand dat je in één request uploadt: als formulierveld.

Gebruik een URL die:

  • HTTPS gebruikt.
  • Geen gebruikersnaam of wachtwoord bevat.
  • Uitkomt op een openbaar adres.

Verwijst de URL naar een privéadres, loopback-adres, link-local-adres of een ander niet-openbaar adres, dan krijg je 422 invalid_request. We controleren het adres bij het aanmaken en opnieuw bij elke poging om de webhook te versturen.

Je kunt webhook_url niet samen met reuse_recent=true gebruiken.

Welke events ontvang je?

typeWanneer ontvang je dit?
transcription.completedZodra de status completed is.
transcription.failedZodra de status failed is. In data.error staan de code en message.

Annuleer je een transcriptie, dan sturen we geen webhook.

Wat staat er in het request?

De webhook heeft een JSON-body met deze velden:

  • In created_at staat wanneer het event is aangemaakt.
  • In data staat het transcriptieobject, zonder het veld transcript.

Haal de tekst op met GET /v1/transcriptions/:id. Gebruik daarvoor de id uit data.

Deze headers komen mee:

  • Content-Type: application/json
  • User-Agent: transcript1-webhooks/1.0
  • X-Transcript1-Signature; hieronder lees je hoe je die controleert.

Controleer de handtekening

In elk webhookrequest staat X-Transcript1-Signature, met de waarde t=<unix seconds>,v1=<hex digest>.

  • t geeft in Unix-seconden aan wanneer we het request hebben ondertekend.
  • v1 bevat de HMAC-SHA256 als hexwaarde. Bereken die over "<t>.<raw body>": t, een punt en de body zoals je die hebt ontvangen. Gebruik je volledige geheime sleutel, dus inclusief whsec_.

Controleer de handtekening op de oorspronkelijke bytes, vóór je de JSON parset. Zet je geparste JSON weer om naar tekst, dan kunnen spaties of de veldvolgorde anders zijn. De handtekening klopt dan niet meer.

  • Vergelijk de handtekeningen in constante tijd.
  • Weiger requests waarvan t te ver van de huidige tijd ligt. De voorbeelden staan een verschil van 5 minuten toe.
  • Laat Express de body als tekst inlezen, zonder die eerst te parsen.
  • Geef bij Flask request.get_data(as_text=True) door als raw_body.

Je geheime sleutel beheren

Je team heeft één geheime sleutel die met whsec_ begint. We gebruiken die voor de webhooks van alle transcripties die je team aanmaakt.

Je kunt de sleutel bekijken of vervangen op “Webhooks”.

Een vervanging gaat direct in. Elke webhook die we daarna versturen, gebruikt de nieuwe sleutel.

Aflevering en nieuwe pogingen

  • Antwoordt je server met 2xx, dan beschouwen we de webhook als afgeleverd.
  • Een andere statuscode, een verbindingsfout of geen antwoord binnen 10 seconden telt als een mislukte poging.
  • We proberen het maximaal 6 keer in totaal. Tussen de pogingen loopt de wachttijd exponentieel op: 2, 4, 8, 16 en 32 minuten. De laatste poging is ongeveer een uur na de eerste.
  • Geef meteen de uiteindelijke URL op. transcript1 volgt geen redirects; ook 3xx telt als mislukt.
  • Dezelfde webhook kan vaker aankomen, bijvoorbeeld als je server pas na de time-out antwoordt. Voorkom dubbele verwerking met data.id en type.