DokumentacjaDokumentacja API

Dokumentacja API

Sprawdź endpointy /v1, ich parametry i przykłady wywołań. Specyfikację OpenAPI pobierzesz w JSON lub YAML.

Na początek

Adres bazowy API
https://api.transcript1.com/v1

Endpointy API znajdziesz pod adresem https://api.transcript1.com/v1.

  • Wysyłaj body requestów w JSON. W tym samym formacie dostajesz odpowiedzi, z nazwami pól w snake_case.
  • Daty i godziny zapisujemy w ISO 8601, w UTC, np. 2026-10-13T09:30:00.000Z.
  • Długość nagrania oraz czasy w transkrypcji podajemy w sekundach.
  • Błędy mają wspólny format. Sprawdź, jak je obsługiwać.
  • W odpowiedzi na uwierzytelniony request dostajesz nagłówki X-RateLimit-Limit i X-RateLimit-Remaining. Limity opisujemy na stronie o planach i minutach.
  • Przy source=auto najpierw sprawdzamy napisy w języku nagrania na YouTube, X, TikToku, Bluesky, Dailymotion i LinkedIn. Jeśli nie da się z nich skorzystać, przepisujemy audio. Nie każdy film ma napisy. Tryb source=captions (tylko napisy) nie pobiera audio i nie uruchamia STT. Jeśli brakuje odpowiednich napisów, dostaniesz no_captions. Ustawienie source=stt lub podział na rozmówców od razu uruchamia transkrypcję audio. W opisie źródeł sprawdzisz ograniczenia pobierania oraz dostępność czasów całych fragmentów i poszczególnych słów.

Specyfikację OpenAPI do wykorzystania w narzędziach pobierzesz w jednym z formatów:

Uwierzytelnianie

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

Klucz API lub token wstaw do nagłówka Authorization w formacie Authorization: Bearer <token>.

  • Klucz API rozpoznasz po prefiksie t1_. Utwórz go na stronie „API keys”. Daje dostęp do wszystkich endpointów.
  • Token dostępu OAuth ma prefiks t1o_. Dostają go aplikacje MCP, np. Claude i ChatGPT, gdy łączysz je z transcript1. Token ma uprawnienia transcriptions:read i transcriptions:write.
UprawnienieDostępne wywołania
transcriptions:readGET /v1/transcriptions, GET /v1/transcriptions/:id, GET /v1/transcriptions/:id/upload i GET /v1/account
transcriptions:writePOST /v1/transcriptions, DELETE /v1/transcriptions/:id i POST /v1/transcriptions/:id/upload/complete
  • Jeśli token nie ma wymaganego uprawnienia, API zwróci 403 insufficient_scope.
  • Jeśli nie podasz klucza lub tokenu albo podasz nieprawidłowy, dostaniesz 401 unauthorized.

Przy wysyłaniu części pliku do PUT /v1/transcriptions/:id/upload/chunks/:index użyj nagłówka X-Upload-Token. Token otrzymasz, gdy utworzysz upload. Szczegóły znajdziesz w dokumentacji uploadu.

Idempotentność

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

Dodaj Idempotency-Key do POST /v1/transcriptions, żeby przy ponowieniu requestu nie tworzyć drugiej transkrypcji.

Klucz musi mieć od 1 do 255 znaków. Przekaż go w nagłówku, nie w parametrach URL-a.

  • Gdy ponowisz request z tym samym kluczem i parametrami, dostaniesz pierwotną transkrypcję. Nie zapłacisz ponownie.
  • Jeśli zachowasz klucz, ale zmienisz parametry, dostaniesz 409 idempotency_conflict.
  • Jeśli ponawiasz rezerwację uploadu w częściach z tym samym kluczem, dostaniesz nowy token uploadu.

Obsługa błędów

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
  }
}
  • Gdy błąd dotyczy requestu, API nie przyjęło wywołania.
  • Gdy nie udała się sama transkrypcja, API wcześniej przyjęło zadanie, ale przetwarzanie zakończyło się błędem. Pole status ma wtedy wartość failed.

Jak odczytać błąd

Jeśli request do /v1 zakończy się błędem, w odpowiedzi dostaniesz obiekt error z polami code, message i retryable.

  • W kodzie aplikacji rozróżniaj błędy po code.
  • Użytkownikowi wyświetl message. Nie opieraj na nim logiki, bo treść komunikatu może się zmienić.
  • Sprawdź retryable: jeśli to true, ten sam request może się udać przy kolejnej próbie.

Zależnie od błędu obok retryable mogą pojawić się dodatkowe pola:

PoleKod błęduCo zawiera
action_urlinsufficient_minutesLink do zakupu planu lub doładowania.
minutes_needed, minutes_remaininginsufficient_minutesIle minut wymaga request i ile masz na koncie. Jeśli nie znamy jeszcze potrzebnej liczby minut, dostaniesz null.
supported_platformsunsupported_platformLista obsługiwanych platform: ["youtube", "x", "tiktok", "instagram", "facebook", "bluesky", "twitch", "dailymotion", "pinterest", "linkedin", "snapchat"].
missing_chunksupload_incompleteIndeksy brakujących części pliku.
max_bytesmedia_too_largeTwój limit rozmiaru pliku w bajtach.
paramsinvalid_requestObiekt z opisem problemu przy każdym niepoprawnym polu body lub parametrze URL-a.

Gdy API nie przyjmie requestu

Status HTTPcodePonowić request?Przyczyna i dalsze kroki
400, 422invalid_requestNieBrakuje pola w body lub parametru albo ma ono nieprawidłową wartość. Przykłady to diarize razem z source: "captions" i reuse_recent razem z webhook_url. Ten kod dostaniesz też za niepoprawny JSON w body.
422invalid_urlNiePodaj link z YouTube, X, TikToka, Instagrama, Facebooka, Bluesky lub innej obsługiwanej platformy. Sprawdź też, czy platform pasuje do adresu.
422unsupported_platformNieWartości podanej w platform nie ma na liście obsługiwanych platform.
422unsupported_mediaNiePlik ma rozszerzenie, którego nie obsługujemy.
401unauthorizedNieBrakuje klucza lub tokenu albo jest nieprawidłowy, wygasł lub został unieważniony. Ten błąd dostaniesz też za nieprawidłowy lub wygasły token uploadu.
403insufficient_scopeNieToken OAuth nie ma wymaganego uprawnienia transcriptions:read lub transcriptions:write.
403email_not_verifiedNieNajpierw potwierdź e-mail, potem zleć transkrypcję.
402insufficient_minutesNieMasz 0 minut lub za mało na tę transkrypcję.
402no_active_planNieChcesz dokupić minuty, ale nie masz aktywnego płatnego planu. Ten błąd zwraca endpoint rozliczeń panelu, nie endpointy transkrypcji.
404not_foundNieNie ma takiej transkrypcji lub należy ona do innego zespołu.
409upload_incompleteNieNie wszystkie części pliku dotarły. Wyślij brakujące i ponownie zakończ upload.
409invalid_stateNieTo zadanie nie czeka na upload. Nie możesz dosyłać części ani kończyć uploadu.
409idempotency_conflictNieWcześniej użyto tego Idempotency-Key z innymi parametrami.
413media_too_largeNiePlik przekracza twój limit. Sprawdź zasady uploadu.
413invalid_requestNieBody w JSON przekracza 1 MB. Dla zbyt dużego pliku dostaniesz zamiast tego media_too_large.
429rate_limitedTakKonto przekroczyło limit requestów na minutę. Odczekaj liczbę sekund z Retry-After.
429too_many_active_jobsTakMasz za dużo trwających transkrypcji lub otwartych uploadów. Odczekaj liczbę sekund z Retry-After.
500internal_errorTakBłąd po naszej stronie. Spróbuj za chwilę.
503service_unavailableTaktranscript1 chwilowo nie działa. Spróbuj za chwilę.

Gdy przeglądarka korzysta z cookie zalogowanej sesji, sprawdzamy też origin requestu. Jeśli request pochodzi z innej strony, zwrócimy 403 forbidden_origin.

Ta kontrola nie dotyczy wywołań API z nagłówkiem Authorization.

Przy każdym 429 dostajesz Retry-After z liczbą sekund do następnej próby. Sprawdź limity swojego planu.

Kiedy spróbować ponownie

  • Ponawiaj request bez zmian tylko wtedy, gdy retryable to true. Dotyczy to rate_limited, too_many_active_jobs, internal_error i service_unavailable.
  • Jeśli odpowiedź zawiera Retry-After, odczekaj podany czas. Bez tego nagłówka wydłużaj przerwę po każdej próbie.
  • Dla kolejnych prób POST /v1/transcriptions zachowaj ten sam Idempotency-Key. Jeśli pierwsze wywołanie się udało, unikniesz ponownej opłaty.
  • Przy pozostałych kodach najpierw popraw request.

Gdy nie uda się przetworzyć nagrania

Jeśli przetwarzanie się nie uda, transkrypcja ma status równy failed. Jej obiekt error zawiera code i message.

Błąd może wystąpić już po przyjęciu requestu. Sprawdzaj error, gdy pobierasz status lub odbierasz webhook transcription.failed.

error.codeCo się stałoCo zrobić
media_unavailableFilm nie istnieje lub nie da się go już odtworzyć.Nie ponawiaj. Sprawdź URL.
media_privateFilm jest prywatny.Nie ponawiaj. Podaj publiczny post albo film z YouTube: publiczny lub niepubliczny (unlisted).
login_requiredPlatforma wymaga logowania.Nie ponawiaj. To błąd trwały, bez automatycznych ponowień.
no_audioFilm nie ma ścieżki audio.Nie ponawiaj. To błąd trwały, bez automatycznych ponowień.
age_restrictedFilm ma ograniczenie wiekowe.Nie ponawiaj z tym linkiem. Wyślij plik.
live_streamTransmisja jeszcze trwa lub nie zdążyła się rozpocząć.Spróbuj po zakończeniu transmisji.
no_captionsW source podano captions, ale brakuje napisów, z których da się skorzystać.Zmień na source: "auto" lub "stt".
media_too_longNagranie przekracza limit 5 godzin dla transkrypcji audio.Nie ponawiaj w całości. Podziel nagranie.
unsupported_mediaNie możemy odczytać pliku lub plik nie zawiera audio.Nie ponawiaj z tym plikiem. Wyślij plik w obsługiwanym formacie.
no_speechNie wykryto mowy.Nie ponawiaj.
unsupported_languageNie obsługujemy języka nagrania.Nie ponawiaj bez zmian. W language podaj obsługiwany kod lub "auto".
insufficient_minutesZabrakło minut, zanim zdążyliśmy rozliczyć transkrypcję.Dokup minuty i spróbuj ponownie.
fetch_failedMimo kilku prób nie udało się pobrać nagrania.Spróbuj ponownie później.
transcription_failedMimo kilku prób nie udało się przepisać audio.Spróbuj ponownie później.

Jeśli transkrypcja się nie uda albo ją anulujesz, nic nie płacisz. Oddajemy też wszystkie minuty, które już pobraliśmy za to nagranie.

Obiekt Transcription

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

Pola obiektu

  • idstringwymagane
  • objectstringwymagane

    Możliwe wartościtranscription

  • statusstringwymagane

    Możliwe wartościawaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled

  • sourceobjectwymagane
    Rozwiń pola zagnieżdżone
    With url
    • platformstringwymagane
    • urlstringwymaganemoże być null
    • media_idstringwymaganemoże być null
    With filename
    • platformstringwymagane

      Możliwe wartościupload

    • filenamestringwymaganemoże być null
    • sizenumberwymaganemoże być null
  • mediaobjectwymaganemoże być null
    Rozwiń pola zagnieżdżone
    • titlestringopcjonalnemoże być null
    • authorstringopcjonalnemoże być null
    • author_urlstringopcjonalnemoże być null
    • thumbnail_urlstringopcjonalnemoże być null
    • filenamestringopcjonalne
    • mime_typestringopcjonalne
    • sizenumberopcjonalne
    • duration_secondsnumberopcjonalnemoże być null
  • optionsobjectwymagane
    Rozwiń pola zagnieżdżone
    • sourcestringwymagane

      Możliwe wartościautocaptionsstt

    • languagestringwymagane
    • diarizebooleanwymagane
  • transcript_sourcestringwymaganemoże być null

    Możliwe wartościyoutube_captionsx_captionsspeech_to_text

  • caption_kindstringwymaganemoże być null

    Możliwe wartościmanualauto_generated

  • languagestringwymaganemoże być null
  • billed_minutesintegerwymaganemoże być null
  • cachedbooleanwymagane
  • errorobjectwymaganemoże być null
    Rozwiń pola zagnieżdżone
    • codestringwymagane
    • messagestringwymaganemoże być null
  • created_atstring · date-timewymaganemoże być null
  • completed_atstring · date-timewymaganemoże być null
  • deleted_atstring · date-timewymaganemoże być null

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

  • transcriptobjectopcjonalne

    Included in GET responses for completed transcriptions.

    Rozwiń pola zagnieżdżone
    • textstringwymagane
    • speakersarray of stringswymagane
    • segmentsarray of objectswymagane
      Rozwiń pola zagnieżdżone
      • startnumberwymagane
      • endnumberwymagane
      • speakerstringwymaganemoże być null
      • languagestringwymaganemoże być null
      • textstringwymagane
      • wordsarray of objectsopcjonalnemoże być null
        Rozwiń pola zagnieżdżone
        • startnumberwymagane
        • endnumberwymagane
        • textstringwymagane
        • confidencenumberopcjonalnemoże być null
        • speakerstringwymaganemoże być null

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
}

Parametry query

  • waitintegeropcjonalnemoże być nullDomyślnie: 0

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

  • reuse_recentstringopcjonalneDomyślnie: 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.

    Możliwe wartościtruefalse

Nagłówki

  • Idempotency-Keystringopcjonalne

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

Body requestu

With url
  • platformstringopcjonalne

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

    Możliwe wartościyoutubextiktokinstagramfacebookblueskytwitchdailymotionpinterestlinkedinsnapchat

  • urlstringwymagane

    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.

  • sourcestringopcjonalne

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

    Możliwe wartościautocaptionsstt

  • languagestringopcjonalne
  • diarizebooleanopcjonalne
  • webhook_urlstring · uriopcjonalne
With upload
  • uploadobjectwymagane
    Rozwiń pola zagnieżdżone
    • filenamestringwymagane
    • sizeintegerwymagane
    • mime_typestringopcjonalne
  • sourcestringopcjonalne

    Możliwe wartościautostt

  • languagestringopcjonalne
  • diarizebooleanopcjonalne
  • webhook_urlstring · uriopcjonalne
multipart/form-data
  • filestring · binarywymagane
  • sourcestringopcjonalne

    Możliwe wartościautostt

  • languagestringopcjonalne
  • diarizebooleanopcjonalne
  • webhook_urlstring · uriopcjonalne

Odpowiedzi

  • 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

Inne kody statusu

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

Parametry ścieżki

  • idstringwymagane

Parametry query

  • waitintegeropcjonalnemoże być nullDomyślnie: 0

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

  • formatstringopcjonalneDomyślnie: json

    Możliwe wartościjsontextsrtvtt

  • includestringopcjonalne

    Możliwe wartościwords

  • timestampsstringopcjonalneDomyślnie: false

    Możliwe wartościtruefalse

  • include_deletedstringopcjonalneDomyślnie: false

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

    Możliwe wartościtruefalse

Odpowiedzi

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

Inne kody statusu

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

Parametry query

  • limitintegeropcjonalneDomyślnie: 20
  • cursorstringopcjonalne
  • statusstringopcjonalne

    Możliwe wartościawaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled

  • platformstringopcjonalne
  • include_deletedstringopcjonalneDomyślnie: false

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

    Możliwe wartościtruefalse

Odpowiedzi

  • 200 OK — A page of transcriptions

Inne kody statusu

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

Odpowiedź bez body

Parametry ścieżki

  • idstringwymagane

Odpowiedzi

  • 204 No Content — Canceled or deleted

Inne kody statusu

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

Parametry ścieżki

  • idstringwymagane
  • indexintegeropcjonalnemoże być null

    Zero-based chunk number from the upload plan

Nagłówki

  • X-Upload-Tokenstringwymagane

Body requestu

  • (surowe body)string · binarywymagane

Odpowiedzi

  • 200 OK — The chunk was stored

Inne kody statusu

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

Parametry ścieżki

  • idstringwymagane

Odpowiedzi

  • 200 OK — Upload progress

Inne kody statusu

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

Parametry ścieżki

  • idstringwymagane

Odpowiedzi

  • 202 Accepted — The transcription is queued

Inne kody statusu

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

Odpowiedzi

  • 200 OK — The authenticated user's account

Inne kody statusu

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

Obiekt Account

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

Pola obiektu

  • objectstringwymagane

    Możliwe wartościaccount

  • userobjectwymagane
    Rozwiń pola zagnieżdżone
    • idstringwymagane
    • emailstringwymagane
  • planobjectwymaganemoże być null
    Rozwiń pola zagnieżdżone
    • idstringwymagane
    • namestringwymagane
  • minutesobjectwymagane
    Rozwiń pola zagnieżdżone
    • remainingnumberwymagane
    • cyclenumberwymagane
    • topupnumberwymagane
    • topup_usablebooleanwymagane
    • resets_atstring · date-timewymaganemoże być null
  • renews_atstring · date-timewymaganemoże być null
  • limitsobjectwymagane
    Rozwiń pola zagnieżdżone
    • requests_per_minutenumberwymagane
    • max_active_jobsnumberwymagane

Webhooki

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

Przy tworzeniu transkrypcji podaj webhook_url. Gdy tekst będzie gotowy albo przetwarzanie się nie uda, transcript1 wyśle na ten adres request POST z podpisem.

Z webhooków skorzystasz tylko przez REST API. W serwerze MCP nie podasz adresu webhooka.

Gdzie odbierać webhooki

Dodaj webhook_url do wywołania POST /v1/transcriptions:

  • Przy linku do filmu lub rezerwacji uploadu w częściach umieść go w body w JSON.
  • Jeśli wysyłasz cały plik jednym requestem, użyj pola formularza.

Sprawdź adres przed wysłaniem:

  • Musi korzystać z HTTPS.
  • Nie może zawierać nazwy użytkownika ani hasła.
  • Musi wskazywać publiczny adres.

Adres prywatny, loopback, link-local lub inny niepubliczny spowoduje 422 invalid_request. Sprawdzamy go przy tworzeniu transkrypcji i ponownie przed każdym wysłaniem webhooka.

Nie łącz webhook_url z reuse_recent=true.

Kiedy dostaniesz powiadomienie

typeCo wywołuje webhook
transcription.completedZakończenie transkrypcji ze statusem completed.
transcription.failedBłąd przetwarzania i status failed. W data.error znajdziesz code i message.

Jeśli anulujesz transkrypcję, nie wyślemy webhooka.

Co zawiera webhook

W body requestu dostajesz JSON:

  • W created_at znajdziesz czas utworzenia zdarzenia.
  • W data dostaniesz obiekt transkrypcji, ale bez transcript.

Sam tekst pobierz przez GET /v1/transcriptions/:id. Użyj id z obiektu data.

Z każdym requestem wysyłamy nagłówki:

  • Content-Type: application/json
  • User-Agent: transcript1-webhooks/1.0
  • X-Transcript1-Signature z podpisem opisanym poniżej.

Jak sprawdzić podpis

W każdym webhooku znajdziesz X-Transcript1-Signature w formacie t=<unix seconds>,v1=<hex digest>.

  • t podaje czas podpisania requestu jako Unix time w sekundach.
  • v1 to HMAC-SHA256 zapisany szesnastkowo. Oblicz go dla "<t>.<raw body>": połącz wartość t, kropkę i body dokładnie w takiej postaci, w jakiej dotarło. Kluczem jest cały sekret do podpisywania webhooków, łącznie z prefiksem whsec_.

Sprawdź podpis na oryginalnych bajtach body, zanim sparsujesz JSON. Parsowanie i ponowny zapis mogą zmienić białe znaki lub kolejność kluczy. Podpis przestanie wtedy pasować.

  • Do porównania podpisów użyj funkcji działającej w stałym czasie.
  • Odrzuć request, jeśli czas w t zbyt mocno odbiega od bieżącego. W przykładach dopuszczamy różnicę 5 minut.
  • W Expressie odczytaj body jako surowy tekst, bez wcześniejszego parsowania.
  • We Flasku użyj request.get_data(as_text=True) jako raw_body.

Sekret do podpisywania webhooków

Zespół ma wspólny sekret z prefiksem whsec_. Używamy go do podpisywania webhooków wszystkich transkrypcji tego zespołu.

Sekret sprawdzisz lub wymienisz na nowy na stronie „Webhooks”.

Zmiana działa od razu. Każdy webhook wysłany po wymianie sekretu podpisujemy już nowym.

Potwierdzanie odbioru i kolejne próby

  • Odpowiedz dowolnym statusem 2xx, żeby potwierdzić odbiór.
  • Inny status, błąd połączenia lub brak odpowiedzi przez 10 sekund oznacza, że próba się nie udała.
  • Jeśli nie dostaniemy potwierdzenia, ponowimy wysyłkę. Łącznie wykonujemy do 6 prób z przerwami 2, 4, 8, 16 i 32 minuty. Ostatnia wypada około godziny po pierwszej.
  • Podaj docelowy URL, bez przekierowań. transcript1 ich nie obsługuje, więc 3xx oznacza nieudaną próbę.
  • Ten sam webhook może dotrzeć więcej niż raz, np. gdy twój serwer odpowie dopiero po limicie czasu. Rozpoznawaj duplikaty po data.id i type.