DokuREST-API-Referenz

REST-API-Referenz

Parameter und Beispiele für alle /v1-Endpoints. Die OpenAPI-Spezifikation kannst du als JSON oder YAML herunterladen.

Überblick

Base URL
https://api.transcript1.com/v1

Alle API-Aufrufe gehen an die Basis-URL https://api.transcript1.com/v1.

  • Sende und empfange JSON. Die Feldnamen verwenden snake_case.
  • Zeitstempel folgen ISO 8601 und beziehen sich auf UTC, etwa 2026-10-13T09:30:00.000Z.
  • Laufzeiten und Zeitangaben im Transkript stehen in Sekunden.
  • Für alle Fehler gilt dasselbe Antwortformat. Details findest du unter Fehler.
  • Bei authentifizierten Requests enthält jede Antwort die Header X-RateLimit-Limit und X-RateLimit-Remaining. Mehr dazu unter Tarife und Limits.
  • Mit source=auto nutzt transcript1 auf YouTube, X, TikTok, Bluesky, Dailymotion und LinkedIn zuerst verwendbare Untertitel in der Originalsprache. Gibt es keine, übernimmt Speech-to-Text. Nicht jedes Video hat Untertitel. Der Modus source=captions lädt kein Audio herunter und wechselt nicht zu STT. Fehlen verwendbare Untertitel, bekommst du no_captions. Mit source=stt oder aktivierter Sprecherzuordnung wird dagegen direkt das Audio transkribiert. Unter Quellen und Einstellungen siehst du die Einschränkungen je Plattform und erfährst, wann Segment- oder Wort-Zeitstempel verfügbar sind.

Die maschinenlesbare OpenAPI-Spezifikation gibt es in zwei Formaten:

Authentifizierung

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

Authentifiziere deine Requests über den Header Authorization: Authorization: Bearer <token>.

  • API-Schlüssel beginnen mit t1_ und funktionieren für alle Endpoints. Erstelle einen im Dashboard unter „API keys“.
  • OAuth-Access-Tokens beginnen mit t1o_. MCP-Clients wie Claude und ChatGPT bekommen ein solches Token, wenn du sie verbindest. Es gilt für die Scopes transcriptions:read und transcriptions:write.
ScopeErlaubte Aufrufe
transcriptions:readGET /v1/transcriptions, GET /v1/transcriptions/:id, GET /v1/transcriptions/:id/upload und GET /v1/account
transcriptions:writePOST /v1/transcriptions, DELETE /v1/transcriptions/:id und POST /v1/transcriptions/:id/upload/complete
  • Fehlt dem Token der erforderliche Scope, antwortet die API mit 403 insufficient_scope.
  • Fehlen die Zugangsdaten oder sind sie ungültig, bekommst du 401 unauthorized.

Für PUT /v1/transcriptions/:id/upload/chunks/:index verwendest du stattdessen X-Upload-Token. Dieses Token bekommst du beim Erstellen des Uploads. Den Ablauf findest du unter Uploads.

Idempotenz

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"}'

Mit dem Header Idempotency-Key kannst du POST /v1/transcriptions wiederholen, ohne doppelt zu zahlen.

Wähle einen Wert mit 1 bis 255 Zeichen. Er gehört in den Request-Header, nicht in die Query-Parameter.

  • Sendest du denselben Key mit denselben Parametern, bekommst du die ursprüngliche Transkription zurück. Es fallen keine weiteren Minuten an.
  • Änderst du die Parameter, behältst aber den Key bei, antwortet die API mit 409 idempotency_conflict.
  • Wiederholst du den Request zum Erstellen eines Chunk-Uploads mit demselben Key, bekommst du ein neues Upload-Token.

Fehler

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
  }
}
  • Request abgelehnt: Die API hat den Aufruf nicht angenommen.
  • Transkription fehlgeschlagen: Die API hat den Job angenommen, konnte ihn aber nicht abschließen. Sein status steht auf failed.

Aufbau einer Fehlerantwort

Wenn ein /v1-Request scheitert, enthält die Antwort ein error-Objekt mit code, message und retryable.

  • Steuere deine Fehlerbehandlung über code.
  • Nutze message zur Anzeige. Verlasse dich im Code nicht auf den Wortlaut, denn er kann sich ändern.
  • Steht retryable auf true, kann derselbe Request später funktionieren.

Je nach Fehler stehen neben retryable weitere Felder:

FeldFehlercodeInhalt
action_urlinsufficient_minutesLink zum Kauf eines Tarifs oder zusätzlicher Minuten.
minutes_needed, minutes_remaininginsufficient_minutesBenötigte und verfügbare Minuten. Ist der Bedarf noch unbekannt, steht dort null.
supported_platformsunsupported_platformListe der unterstützten Plattformen: ["youtube", "x", "tiktok", "instagram", "facebook", "bluesky", "twitch", "dailymotion", "pinterest", "linkedin", "snapchat"].
missing_chunksupload_incompleteIndizes der noch fehlenden Chunks.
max_bytesmedia_too_largeDeine maximal erlaubte Dateigröße in Bytes.
paramsinvalid_requestBei ungültigen Body- oder Query-Parametern ein Objekt mit den betroffenen Feldern und dem jeweiligen Problem.

Fehler beim Request

HTTP-StatuscodeErneut versuchen?Ursache
400, 422invalid_requestNeinEin Parameter oder Body-Feld fehlt oder ist ungültig. Dazu gehören unzulässige Kombinationen wie diarize mit source: "captions" oder reuse_recent mit webhook_url. Auch ungültiges JSON im Request-Body löst diesen Fehler aus.
422invalid_urlNeinDer Link muss zu YouTube, X, TikTok, Instagram, Facebook, Bluesky oder einer anderen unter Quellen und Einstellungen genannten Plattform führen. Der Fehler tritt auch auf, wenn platform nicht zum Link passt.
422unsupported_platformNeinDer Wert für platform wird nicht unterstützt.
422unsupported_mediaNeinDie Dateiendung des Uploads wird nicht unterstützt.
401unauthorizedNeinDie Zugangsdaten fehlen, sind ungültig, abgelaufen oder widerrufen. Auch ein ungültiges oder abgelaufenes Upload-Token löst diesen Fehler aus.
403insufficient_scopeNeinDem OAuth-Token fehlt der erforderliche Scope transcriptions:read oder transcriptions:write.
403email_not_verifiedNeinDeine E-Mail-Adresse ist noch nicht bestätigt. Bestätige sie, bevor du eine Transkription startest.
402insufficient_minutesNeinDu hast 0 nutzbare Minuten oder dein Guthaben reicht für die Transkription nicht aus.
402no_active_planNeinDu versuchst, ohne aktiven kostenpflichtigen Tarif Minuten aufzuladen. Diesen Code liefert nur der Billing-Endpoint des Dashboards, nicht die Transkriptions-API.
404not_foundNeinEs gibt keine Transkription mit dieser ID oder sie gehört einem anderen Team.
409upload_incompleteNeinChunks fehlen noch. Lade sie hoch und schließe den Upload danach erneut ab.
409invalid_stateNeinDer Job wartet nicht auf einen Upload. Du kannst weder weitere Chunks senden noch den Upload abschließen.
409idempotency_conflictNeinDu hast diesen Idempotency-Key schon mit anderen Parametern verwendet.
413media_too_largeNeinDeine Datei überschreitet das Größenlimit. Details stehen unter Uploads.
413invalid_requestNeinDer JSON-Body ist größer als 1 MB. Bei zu großen Dateien lautet der Code stattdessen media_too_large.
429rate_limitedJaDu hast das Request-Limit pro Minute überschritten. Warte so viele Sekunden, wie Retry-After angibt.
429too_many_active_jobsJaEs laufen zu viele Transkriptionen oder es sind zu viele Uploads offen. Warte die in Retry-After angegebenen Sekunden.
500internal_errorJaBei transcript1 ist ein interner Fehler aufgetreten. Versuche es nach einer kurzen Pause erneut.
503service_unavailableJatranscript1 ist gerade nicht erreichbar. Versuche es nach einer kurzen Pause erneut.

Bei Browser-Requests mit Login-Cookie prüft die API zusätzlich die Herkunft. Kommt der Request von einer anderen Website, antwortet sie mit 403 forbidden_origin.

Für API-Aufrufe mit Authorization-Header gilt diese Prüfung nicht.

Bei jeder 429-Antwort gibt der Header Retry-After die Wartezeit in Sekunden an. Die konkreten Limits findest du unter Tarife und Limits.

Wann du einen Request wiederholen solltest

  • Wiederhole den Request nur bei retryable mit dem Wert true. Das gilt für rate_limited, too_many_active_jobs, internal_error und service_unavailable.
  • Richte dich nach Retry-After, falls der Header vorhanden ist. Verlängere andernfalls die Pause zwischen den Versuchen.
  • Behalte bei einem erneuten POST /v1/transcriptions denselben Idempotency-Key-Header bei. So zahlst du nicht doppelt, falls der erste Request doch erfolgreich war.
  • Bei allen anderen Codes musst du zuerst den Request korrigieren.

Fehler während der Transkription

Scheitert die Verarbeitung, steht status auf failed. Im Job findest du dann ein error-Objekt mit code und message.

Das kann passieren, nachdem die API deinen Request bereits beantwortet hat. Prüfe deshalb beim Polling und bei einem transcription.failed-Webhook das Feld error.

error.codeBedeutungErneut versuchen?
media_unavailableDas Video fehlt oder ist nicht mehr abrufbar.Nein. Kontrolliere die URL.
media_privateDas Video ist privat.Nein. Nimm einen öffentlichen Post oder ein öffentliches bzw. nicht gelistetes YouTube-Video.
login_requiredDie Plattform verlangt eine Anmeldung.Nein. Dauerhafter Fehler, kein automatischer neuer Versuch.
no_audioDas Video enthält keine Tonspur.Nein. Dauerhafter Fehler, kein automatischer neuer Versuch.
age_restrictedFür das Video gilt eine Altersbeschränkung.Nein. Lade stattdessen die Datei hoch.
live_streamDer Stream läuft noch oder hat noch nicht begonnen.Erst nach Ende des Streams.
no_captionsDu hast source auf captions gesetzt, aber es gibt keine verwendbaren Untertitel.Wechsle zu source: "auto" oder "stt".
media_too_longDie Aufnahme überschreitet das Speech-to-Text-Limit von 5 Stunden.Nein. Teile die Aufnahme in kürzere Dateien auf.
unsupported_mediaDie Datei lässt sich nicht lesen oder enthält keine Audiospur.Nein. Lade eine unterstützte Datei hoch.
no_speechIn der Aufnahme wurde keine gesprochene Sprache erkannt.Nein.
unsupported_languageDie Sprache der Aufnahme wird nicht unterstützt.Nein. Gib für language einen unterstützten Sprachcode oder "auto" an.
insufficient_minutesAls die Transkription abgerechnet werden sollte, reichte dein Guthaben nicht mehr.Nach einer Aufladung.
fetch_failedAuch nach mehreren Versuchen konnte transcript1 die Aufnahme nicht abrufen.Ja, zu einem späteren Zeitpunkt.
transcription_failedSpeech-to-Text ist auch nach mehreren Versuchen fehlgeschlagen.Ja, zu einem späteren Zeitpunkt.

Wenn eine Transkription fehlschlägt oder du sie abbrichst, zahlst du nichts. Bereits abgezogene Minuten bekommst du zurück.

Objekt Transcription

Objekt 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."
      }
    ]
  }
}

Felder

  • idstringPflichtfeld
  • objectstringPflichtfeld

    Mögliche Wertetranscription

  • statusstringPflichtfeld

    Mögliche Werteawaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled

  • sourceobjectPflichtfeld
    Felder anzeigen
    With url
    • platformstringPflichtfeld
    • urlstringPflichtfeldnull erlaubt
    • media_idstringPflichtfeldnull erlaubt
    With filename
    • platformstringPflichtfeld

      Mögliche Werteupload

    • filenamestringPflichtfeldnull erlaubt
    • sizenumberPflichtfeldnull erlaubt
  • mediaobjectPflichtfeldnull erlaubt
    Felder anzeigen
    • titlestringoptionalnull erlaubt
    • authorstringoptionalnull erlaubt
    • author_urlstringoptionalnull erlaubt
    • thumbnail_urlstringoptionalnull erlaubt
    • filenamestringoptional
    • mime_typestringoptional
    • sizenumberoptional
    • duration_secondsnumberoptionalnull erlaubt
  • optionsobjectPflichtfeld
    Felder anzeigen
    • sourcestringPflichtfeld

      Mögliche Werteautocaptionsstt

    • languagestringPflichtfeld
    • diarizebooleanPflichtfeld
  • transcript_sourcestringPflichtfeldnull erlaubt

    Mögliche Werteyoutube_captionsx_captionsspeech_to_text

  • caption_kindstringPflichtfeldnull erlaubt

    Mögliche Wertemanualauto_generated

  • languagestringPflichtfeldnull erlaubt
  • billed_minutesintegerPflichtfeldnull erlaubt
  • cachedbooleanPflichtfeld
  • errorobjectPflichtfeldnull erlaubt
    Felder anzeigen
    • codestringPflichtfeld
    • messagestringPflichtfeldnull erlaubt
  • created_atstring · date-timePflichtfeldnull erlaubt
  • completed_atstring · date-timePflichtfeldnull erlaubt
  • deleted_atstring · date-timePflichtfeldnull erlaubt

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

  • transcriptobjectoptional

    Included in GET responses for completed transcriptions.

    Felder anzeigen
    • textstringPflichtfeld
    • speakersarray of stringsPflichtfeld
    • segmentsarray of objectsPflichtfeld
      Felder anzeigen
      • startnumberPflichtfeld
      • endnumberPflichtfeld
      • speakerstringPflichtfeldnull erlaubt
      • languagestringPflichtfeldnull erlaubt
      • textstringPflichtfeld
      • wordsarray of objectsoptionalnull erlaubt
        Felder anzeigen
        • startnumberPflichtfeld
        • endnumberPflichtfeld
        • textstringPflichtfeld
        • confidencenumberoptionalnull erlaubt
        • speakerstringPflichtfeldnull erlaubt

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

  • waitintegeroptionalnull erlaubtStandard: 0

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

  • reuse_recentstringoptionalStandard: 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.

    Mögliche Wertetruefalse

Headers

  • Idempotency-Keystringoptional

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

Body

With url
  • platformstringoptional

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

    Mögliche Werteyoutubextiktokinstagramfacebookblueskytwitchdailymotionpinterestlinkedinsnapchat

  • urlstringPflichtfeld

    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.

  • sourcestringoptional

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

    Mögliche Werteautocaptionsstt

  • languagestringoptional
  • diarizebooleanoptional
  • webhook_urlstring · urioptional
With upload
  • uploadobjectPflichtfeld
    Felder anzeigen
    • filenamestringPflichtfeld
    • sizeintegerPflichtfeld
    • mime_typestringoptional
  • sourcestringoptional

    Mögliche Werteautostt

  • languagestringoptional
  • diarizebooleanoptional
  • webhook_urlstring · urioptional
multipart/form-data
  • filestring · binaryPflichtfeld
  • sourcestringoptional

    Mögliche Werteautostt

  • languagestringoptional
  • diarizebooleanoptional
  • webhook_urlstring · urioptional

Erfolgreiche Antwort

  • 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

Weitere 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

  • idstringPflichtfeld

Query

  • waitintegeroptionalnull erlaubtStandard: 0

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

  • formatstringoptionalStandard: json

    Mögliche Wertejsontextsrtvtt

  • includestringoptional

    Mögliche Wertewords

  • timestampsstringoptionalStandard: false

    Mögliche Wertetruefalse

  • include_deletedstringoptionalStandard: false

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

    Mögliche Wertetruefalse

Erfolgreiche Antwort

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

Weitere 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

  • limitintegeroptionalStandard: 20
  • cursorstringoptional
  • statusstringoptional

    Mögliche Werteawaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled

  • platformstringoptional
  • include_deletedstringoptionalStandard: false

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

    Mögliche Wertetruefalse

Erfolgreiche Antwort

  • 200 OK — A page of transcriptions

Weitere 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"

Antwort ohne Body

Path

  • idstringPflichtfeld

Erfolgreiche Antwort

  • 204 No Content — Canceled or deleted

Weitere 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

  • idstringPflichtfeld
  • indexintegeroptionalnull erlaubt

    Zero-based chunk number from the upload plan

Headers

  • X-Upload-TokenstringPflichtfeld

Body

  • (Raw Body)string · binaryPflichtfeld

Erfolgreiche Antwort

  • 200 OK — The chunk was stored

Weitere 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

  • idstringPflichtfeld

Erfolgreiche Antwort

  • 200 OK — Upload progress

Weitere 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

  • idstringPflichtfeld

Erfolgreiche Antwort

  • 202 Accepted — The transcription is queued

Weitere 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
  }
}

Erfolgreiche Antwort

  • 200 OK — The authenticated user's account

Weitere 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.

Objekt Account

Objekt 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
  }
}

Felder

  • objectstringPflichtfeld

    Mögliche Werteaccount

  • userobjectPflichtfeld
    Felder anzeigen
    • idstringPflichtfeld
    • emailstringPflichtfeld
  • planobjectPflichtfeldnull erlaubt
    Felder anzeigen
    • idstringPflichtfeld
    • namestringPflichtfeld
  • minutesobjectPflichtfeld
    Felder anzeigen
    • remainingnumberPflichtfeld
    • cyclenumberPflichtfeld
    • topupnumberPflichtfeld
    • topup_usablebooleanPflichtfeld
    • resets_atstring · date-timePflichtfeldnull erlaubt
  • renews_atstring · date-timePflichtfeldnull erlaubt
  • limitsobjectPflichtfeld
    Felder anzeigen
    • requests_per_minutenumberPflichtfeld
    • max_active_jobsnumberPflichtfeld

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
  }
}

Gib beim Erstellen eines Jobs webhook_url an. Sobald die Transkription fertig ist oder fehlschlägt, schickt transcript1 einen signierten POST-Request an diese URL.

Webhooks kannst du nur über die REST-API einrichten. Die Tools des MCP-Servers nehmen keinen Webhook-Parameter an.

Die Webhook-URL übergeben

Übergib webhook_url beim Aufruf von POST /v1/transcriptions:

  • Für einen unterstützten Video-Link oder zum Vorbereiten eines Chunk-Uploads gehört die URL in den JSON-Body.
  • Bei einem Upload in einem einzigen Request übergibst du sie als Formularfeld.

Für die URL gelten diese Voraussetzungen:

  • Sie verwendet HTTPS.
  • Sie enthält weder Benutzernamen noch Passwort.
  • Die DNS-Auflösung liefert eine öffentliche Adresse.

Private Adressen, Loopback, Link-Local und andere nicht öffentliche Adressen lehnt die API mit 422 invalid_request ab. transcript1 prüft die Adresse beim Erstellen des Jobs und vor jeder Zustellung.

Du kannst webhook_url nicht zusammen mit reuse_recent=true verwenden.

Events

typeAuslöser
transcription.completedDer Job hat den Status completed.
transcription.failedDer Job hat den Status failed. In data.error stehen code und message.

Wenn du eine Transkription abbrichst, verschickt transcript1 keinen Webhook.

Inhalt des Webhooks

Der Webhook enthält einen JSON-Body:

  • created_at gibt an, wann das Event entstanden ist.
  • In data steht das Transkriptionsobjekt, allerdings ohne transcript.

Den Text holst du mit GET /v1/transcriptions/:id. Nutze dafür die id aus data.

transcript1 sendet diese Header mit:

  • Content-Type: application/json
  • User-Agent: transcript1-webhooks/1.0
  • X-Transcript1-Signature zur Signaturprüfung, siehe den nächsten Abschnitt.

Signatur prüfen

Prüfe bei jedem Webhook den Header X-Transcript1-Signature. Sein Format lautet t=<unix seconds>,v1=<hex digest>.

  • t enthält den Zeitpunkt der Signatur als Unix-Zeit in Sekunden.
  • v1 ist der HMAC-SHA256 von "<t>.<raw body>", hexadezimal kodiert. Setze dafür den Wert von t, einen Punkt und den unveränderten Request-Body zusammen. Als HMAC-Schlüssel nimmst du dein vollständiges Signing Secret, inklusive whsec_.

Berechne die Signatur aus den unveränderten Body-Bytes, bevor du das JSON parst. Wenn du den Body erst parst und wieder serialisierst, können sich Leerzeichen oder die Reihenfolge der Schlüssel ändern. Die Signatur stimmt dann nicht mehr.

  • Verwende für den Signaturvergleich eine Funktion mit konstanter Laufzeit.
  • Lehne Requests ab, wenn t zu weit von der aktuellen Uhrzeit abweicht. In den Beispielen sind 5 Minuten erlaubt.
  • Lies den Body in Express als unverarbeiteten Text ein, ohne ihn vorher zu parsen.
  • In Flask übergibst du request.get_data(as_text=True) als raw_body.

Signing Secret verwalten

Dein Team hat ein gemeinsames Signing Secret mit dem Präfix whsec_. Damit signiert transcript1 die Webhooks für alle Transkriptionen des Teams.

Unter „Webhooks“ im Dashboard kannst du es anzeigen oder durch ein neues ersetzen.

Der Wechsel gilt sofort. Alle danach gesendeten Webhooks verwenden das neue Secret.

Zustellung und erneute Versuche

  • Antwortet dein Server mit 2xx, gilt der Webhook als zugestellt.
  • Bei einem anderen Statuscode, einem Verbindungsfehler oder ohne Antwort innerhalb von 10 Sekunden gilt der Versuch als fehlgeschlagen.
  • Nach einem fehlgeschlagenen Versuch wartet transcript1 mit exponentiellem Backoff und versucht es erneut. Insgesamt gibt es höchstens 6 Versuche. Die Pausen betragen 2, 4, 8, 16 und 32 Minuten. Der letzte Versuch liegt etwa eine Stunde nach dem ersten.
  • Verwende die endgültige Ziel-URL. transcript1 folgt keinen Weiterleitungen. Auch 3xx zählt als fehlgeschlagener Versuch.
  • Dein Server kann denselben Webhook mehrfach erhalten, etwa wenn er erst nach dem Timeout antwortet. Erkenne Duplikate anhand von data.id und type und verarbeite sie nicht erneut.