DokumentacjaDokumentacja API
Dokumentacja API
Sprawdź endpointy /v1, ich parametry i przykłady wywołań. Specyfikację OpenAPI pobierzesz w JSON lub YAML.
Na początek
https://api.transcript1.com/v1Endpointy 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-LimitiX-RateLimit-Remaining. Limity opisujemy na stronie o planach i minutach. - Przy
source=autonajpierw 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. Trybsource=captions(tylko napisy) nie pobiera audio i nie uruchamia STT. Jeśli brakuje odpowiednich napisów, dostanieszno_captions. Ustawieniesource=sttlub 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 uprawnieniatranscriptions:readitranscriptions:write.
| Uprawnienie | Dostępne wywołania |
|---|---|
transcriptions:read | GET /v1/transcriptions, GET /v1/transcriptions/:id, GET /v1/transcriptions/:id/upload i GET /v1/account |
transcriptions:write | POST /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
{
"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
statusma 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 totrue, ten sam request może się udać przy kolejnej próbie.
Zależnie od błędu obok retryable mogą pojawić się dodatkowe pola:
| Pole | Kod błędu | Co zawiera |
|---|---|---|
action_url | insufficient_minutes | Link do zakupu planu lub doładowania. |
minutes_needed, minutes_remaining | insufficient_minutes | Ile minut wymaga request i ile masz na koncie. Jeśli nie znamy jeszcze potrzebnej liczby minut, dostaniesz null. |
supported_platforms | unsupported_platform | Lista obsługiwanych platform: ["youtube", "x", "tiktok", "instagram", "facebook", "bluesky", "twitch", "dailymotion", "pinterest", "linkedin", "snapchat"]. |
missing_chunks | upload_incomplete | Indeksy brakujących części pliku. |
max_bytes | media_too_large | Twój limit rozmiaru pliku w bajtach. |
params | invalid_request | Obiekt z opisem problemu przy każdym niepoprawnym polu body lub parametrze URL-a. |
Gdy API nie przyjmie requestu
| Status HTTP | code | Ponowić request? | Przyczyna i dalsze kroki |
|---|---|---|---|
| 400, 422 | invalid_request | Nie | Brakuje 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. |
| 422 | invalid_url | Nie | Podaj link z YouTube, X, TikToka, Instagrama, Facebooka, Bluesky lub innej obsługiwanej platformy. Sprawdź też, czy platform pasuje do adresu. |
| 422 | unsupported_platform | Nie | Wartości podanej w platform nie ma na liście obsługiwanych platform. |
| 422 | unsupported_media | Nie | Plik ma rozszerzenie, którego nie obsługujemy. |
| 401 | unauthorized | Nie | Brakuje 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. |
| 403 | insufficient_scope | Nie | Token OAuth nie ma wymaganego uprawnienia transcriptions:read lub transcriptions:write. |
| 403 | email_not_verified | Nie | Najpierw potwierdź e-mail, potem zleć transkrypcję. |
| 402 | insufficient_minutes | Nie | Masz 0 minut lub za mało na tę transkrypcję. |
| 402 | no_active_plan | Nie | Chcesz dokupić minuty, ale nie masz aktywnego płatnego planu. Ten błąd zwraca endpoint rozliczeń panelu, nie endpointy transkrypcji. |
| 404 | not_found | Nie | Nie ma takiej transkrypcji lub należy ona do innego zespołu. |
| 409 | upload_incomplete | Nie | Nie wszystkie części pliku dotarły. Wyślij brakujące i ponownie zakończ upload. |
| 409 | invalid_state | Nie | To zadanie nie czeka na upload. Nie możesz dosyłać części ani kończyć uploadu. |
| 409 | idempotency_conflict | Nie | Wcześniej użyto tego Idempotency-Key z innymi parametrami. |
| 413 | media_too_large | Nie | Plik przekracza twój limit. Sprawdź zasady uploadu. |
| 413 | invalid_request | Nie | Body w JSON przekracza 1 MB. Dla zbyt dużego pliku dostaniesz zamiast tego media_too_large. |
| 429 | rate_limited | Tak | Konto przekroczyło limit requestów na minutę. Odczekaj liczbę sekund z Retry-After. |
| 429 | too_many_active_jobs | Tak | Masz za dużo trwających transkrypcji lub otwartych uploadów. Odczekaj liczbę sekund z Retry-After. |
| 500 | internal_error | Tak | Błąd po naszej stronie. Spróbuj za chwilę. |
| 503 | service_unavailable | Tak | transcript1 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
retryabletotrue. Dotyczy torate_limited,too_many_active_jobs,internal_erroriservice_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/transcriptionszachowaj ten samIdempotency-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.code | Co się stało | Co zrobić |
|---|---|---|
media_unavailable | Film nie istnieje lub nie da się go już odtworzyć. | Nie ponawiaj. Sprawdź URL. |
media_private | Film jest prywatny. | Nie ponawiaj. Podaj publiczny post albo film z YouTube: publiczny lub niepubliczny (unlisted). |
login_required | Platforma wymaga logowania. | Nie ponawiaj. To błąd trwały, bez automatycznych ponowień. |
no_audio | Film nie ma ścieżki audio. | Nie ponawiaj. To błąd trwały, bez automatycznych ponowień. |
age_restricted | Film ma ograniczenie wiekowe. | Nie ponawiaj z tym linkiem. Wyślij plik. |
live_stream | Transmisja jeszcze trwa lub nie zdążyła się rozpocząć. | Spróbuj po zakończeniu transmisji. |
no_captions | W source podano captions, ale brakuje napisów, z których da się skorzystać. | Zmień na source: "auto" lub "stt". |
media_too_long | Nagranie przekracza limit 5 godzin dla transkrypcji audio. | Nie ponawiaj w całości. Podziel nagranie. |
unsupported_media | Nie możemy odczytać pliku lub plik nie zawiera audio. | Nie ponawiaj z tym plikiem. Wyślij plik w obsługiwanym formacie. |
no_speech | Nie wykryto mowy. | Nie ponawiaj. |
unsupported_language | Nie obsługujemy języka nagrania. | Nie ponawiaj bez zmian. W language podaj obsługiwany kod lub "auto". |
insufficient_minutes | Zabrakło minut, zanim zdążyliśmy rozliczyć transkrypcję. | Dokup minuty i spróbuj ponownie. |
fetch_failed | Mimo kilku prób nie udało się pobrać nagrania. | Spróbuj ponownie później. |
transcription_failed | Mimo 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
{
"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ści
transcription - statusstringwymagane
Możliwe wartości
awaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled - sourceobjectwymagane
Rozwiń pola zagnieżdżoneZwiń pola zagnieżdżone
With
url- platformstringwymagane
- urlstringwymaganemoże być null
- media_idstringwymaganemoże być null
With
filename- platformstringwymagane
Możliwe wartości
upload - filenamestringwymaganemoże być null
- sizenumberwymaganemoże być null
- mediaobjectwymaganemoże być null
Rozwiń pola zagnieżdżoneZwiń 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żoneZwiń pola zagnieżdżone
- sourcestringwymagane
Możliwe wartości
autocaptionsstt - languagestringwymagane
- diarizebooleanwymagane
- transcript_sourcestringwymaganemoże być null
Możliwe wartości
youtube_captionsx_captionsspeech_to_text - caption_kindstringwymaganemoże być null
Możliwe wartości
manualauto_generated - languagestringwymaganemoże być null
- billed_minutesintegerwymaganemoże być null
- cachedbooleanwymagane
- errorobjectwymaganemoże być null
Rozwiń pola zagnieżdżoneZwiń 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
nullunless the request includesinclude_deleted=true. - transcriptobjectopcjonalne
Included in
GETresponses for completed transcriptions.Rozwiń pola zagnieżdżoneZwiń pola zagnieżdżone
- textstringwymagane
- speakersarray of stringswymagane
- segmentsarray of objectswymagane
Rozwiń pola zagnieżdżoneZwiń 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żoneZwiń 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/transcriptionsTranscribes 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 samesource,languageanddiarize. It must have been created in the last 24 hours and must not befailedorcanceled. Reuses that transcription without creating or charging for a new one.Możliwe wartości
truefalse
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ści
youtubextiktokinstagramfacebookblueskytwitchdailymotionpinterestlinkedinsnapchat - 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ści
autocaptionsstt - languagestringopcjonalne
- diarizebooleanopcjonalne
- webhook_urlstring · uriopcjonalne
With upload
- uploadobjectwymagane
Rozwiń pola zagnieżdżoneZwiń pola zagnieżdżone
- filenamestringwymagane
- sizeintegerwymagane
- mime_typestringopcjonalne
- sourcestringopcjonalne
Możliwe wartości
autostt - languagestringopcjonalne
- diarizebooleanopcjonalne
- webhook_urlstring · uriopcjonalne
multipart/form-data
- filestring · binarywymagane
- sourcestringopcjonalne
Możliwe wartości
autostt - languagestringopcjonalne
- diarizebooleanopcjonalne
- webhook_urlstring · uriopcjonalne
Odpowiedzi
200 OK— The transcription reached a final status201 Created— The transcription is awaiting a chunked upload.uploaddescribes where to send each chunk.202 Accepted— The transcription is processing
Inne kody statusu
400 Bad Request— The JSON request body is malformed401 Unauthorized— Missing or invalid credential402 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 plan409 Conflict—Idempotency-Keywas reused with different parameters.413 Content Too Large— The upload or the JSON request body is too large422 Unprocessable Content— Invalid request, URL, platform or file type429 Too Many Requests— Too many requests or too many active transcriptions. Wait for the number of seconds inRetry-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ści
jsontextsrtvtt - includestringopcjonalne
Możliwe wartości
words - timestampsstringopcjonalneDomyślnie: false
Możliwe wartości
truefalse - include_deletedstringopcjonalneDomyślnie: false
Also returns deleted transcriptions as read-only records without a transcript. Their
deleted_atis set. Defaults tofalse.Możliwe wartości
truefalse
Odpowiedzi
200 OK— The transcription, or the rendered transcript202 Accepted— A rendered format was requested while the transcription is still processing
Inne kody statusu
401 Unauthorized— Missing or invalid credential403 Forbidden— Insufficient scope or a single-member team plan404 Not Found— Transcription not found422 Unprocessable Content— Invalid query parameters429 Too Many Requests— Too many requests. Wait for the number of seconds inRetry-After.
List transcriptions
GET /v1/transcriptionsLists 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ści
awaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled - platformstringopcjonalne
- include_deletedstringopcjonalneDomyślnie: false
Also returns deleted transcriptions as read-only records without a transcript. Their
deleted_atis set. Defaults tofalse.Możliwe wartości
truefalse
Odpowiedzi
200 OK— A page of transcriptions
Inne kody statusu
401 Unauthorized— Missing or invalid credential403 Forbidden— Insufficient scope or a single-member team plan422 Unprocessable Content— Invalid query parameters or cursor429 Too Many Requests— Too many requests. Wait for the number of seconds inRetry-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 credential403 Forbidden— Insufficient scope, cross-site request or a single-member team plan404 Not Found— Transcription not found429 Too Many Requests— Too many requests. Wait for the number of seconds inRetry-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 token404 Not Found— Transcription not found409 Conflict— The transcription is no longer awaiting an upload422 Unprocessable Content— Index outside the chunk plan or wrong body size
Get upload progress
GET /v1/transcriptions/{id}/uploadLists 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 credential403 Forbidden— Insufficient scope or a single-member team plan404 Not Found— Transcription or upload not found429 Too Many Requests— Too many requests. Wait for the number of seconds inRetry-After.
Complete a chunked upload
POST /v1/transcriptions/{id}/upload/completeChecks 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 credential402 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 plan404 Not Found— Transcription or upload not found409 Conflict—upload_incompletemeans chunks are missing.missing_chunkslists them.invalid_statemeans 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 inRetry-After.
Account
Your plan, remaining minutes and rate limits.
Get your account
GET /v1/accountReturns 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 credential403 Forbidden— Insufficient scope or a single-member team plan404 Not Found— No account found429 Too Many Requests— Too many requests. Wait for the number of seconds inRetry-After.
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ści
account - userobjectwymagane
Rozwiń pola zagnieżdżoneZwiń pola zagnieżdżone
- idstringwymagane
- emailstringwymagane
- planobjectwymaganemoże być null
Rozwiń pola zagnieżdżoneZwiń pola zagnieżdżone
- idstringwymagane
- namestringwymagane
- minutesobjectwymagane
Rozwiń pola zagnieżdżoneZwiń 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żoneZwiń 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));
};{
"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
type | Co wywołuje webhook |
|---|---|
transcription.completed | Zakończenie transkrypcji ze statusem completed. |
transcription.failed | Błą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_atznajdziesz czas utworzenia zdarzenia. - W
datadostaniesz obiekt transkrypcji, ale beztranscript.
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/jsonUser-Agent: transcript1-webhooks/1.0X-Transcript1-Signaturez podpisem opisanym poniżej.
Jak sprawdzić podpis
W każdym webhooku znajdziesz X-Transcript1-Signature w formacie t=<unix seconds>,v1=<hex digest>.
tpodaje czas podpisania requestu jako Unix time w sekundach.v1to 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 prefiksemwhsec_.
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
tzbyt 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)jakoraw_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
3xxoznacza 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.iditype.