ДокументацияСправочник по API
Справочник по API
Параметры и примеры запросов для всех эндпоинтов /v1. Спецификация OpenAPI доступна для скачивания в JSON и YAML.
Об API
https://api.transcript1.com/v1Отправляйте запросы на https://api.transcript1.com/v1.
- Тело запроса и ответа имеет формат JSON. Имена полей записаны в
snake_case. - Даты приходят в UTC по ISO 8601: например,
2026-10-13T09:30:00.000Z. - Длительность записи и временные метки транскрипта измеряются в секундах.
- У ошибок единый формат — см. «Ошибки».
- В ответах на запросы с аутентификацией есть заголовки
X-RateLimit-LimitиX-RateLimit-Remaining. Их значения описаны в разделе «Тарифы и лимиты». - При
source=autoсначала ищем подходящие субтитры на языке оригинала в YouTube, X, TikTok, Bluesky, Dailymotion и LinkedIn. Если их нет, распознаём речь. Режимcaptions(только субтитры), то естьsource=captions, не скачивает аудио и не переходит на STT: без подходящей дорожки задача завершится сno_captions. Приsource=sttили определении говорящих субтитры не используем. Какие дорожки доступны, как их получаем и где есть пословные временные метки — в разделе «Источники и параметры».
Спецификацию OpenAPI можно скачать в любом из двух форматов:
Доступ к API
curl https://api.transcript1.com/v1/account \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY"Перед каждым запросом добавьте ключ или токен в заголовок: Authorization: Bearer <token>.
- API-ключ с префиксом
t1_даёт доступ ко всем эндпоинтам. Создайте его в личном кабинете на странице «API keys». - Токен доступа OAuth начинается с
t1o_. Такой токен получают MCP-клиенты, например Claude и ChatGPT, когда вы их подключаете. Доступ ограничен разрешениямиtranscriptions:readиtranscriptions:write.
| Разрешение | Доступные запросы |
|---|---|
transcriptions:read | GET /v1/transcriptions, GET /v1/transcriptions/:id, GET /v1/transcriptions/:id/upload и GET /v1/account |
transcriptions:write | POST /v1/transcriptions, DELETE /v1/transcriptions/:id и POST /v1/transcriptions/:id/upload/complete |
- Если у токена нет нужного разрешения, API ответит
403 insufficient_scope. - Если ключ или токен не передан либо недействителен, вернётся
401 unauthorized.
Для отправки частей файла действует другой токен. В запросах PUT /v1/transcriptions/:id/upload/chunks/:index передавайте X-Upload-Token, полученный при создании загрузки. Подробнее — в разделе «Загрузка файлов».
Идемпотентность
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"}'Добавляйте Idempotency-Key к POST /v1/transcriptions. Тогда запрос можно повторить, не создавая ещё одну транскрибацию.
Длина ключа — от 1 до 255 символов. Он передаётся только в HTTP-заголовке, не в query-параметре.
- Если ключ и параметры не изменились, API вернёт прежнюю задачу и не спишет минуты повторно.
- Если ключ прежний, а параметры другие, API ответит
409 idempotency_conflict. - При загрузке по частям можно повторить запрос создания с тем же ключом, чтобы получить свежий токен загрузки.
Ошибки
{
"error": {
"code": "insufficient_minutes",
"message": "Not enough minutes",
"retryable": false,
"action_url": "https://transcript1.com/dashboard/billing",
"minutes_needed": 20,
"minutes_remaining": 3
}
}- Ошибка запроса: API не принял вызов. Код и описание придут в HTTP-ответе.
- Ошибка задачи: API создал транскрибацию, но выполнить её не удалось. У задачи будет
status=failed.
Формат ошибки
При ошибке запроса к /v1 API возвращает объект error. В нём всегда есть code, message и retryable.
- Выбирайте способ обработки по
code. - Текст
messageпредназначен для пользователя. Не привязывайте к нему логику: формулировка может измениться. - При
retryable=trueможно попробовать тот же запрос позже.
У некоторых ошибок есть дополнительные поля рядом с retryable:
| Поле | Код ошибки | Что содержит |
|---|---|---|
action_url | insufficient_minutes | Ссылку для подключения тарифа или покупки минут. |
minutes_needed, minutes_remaining | insufficient_minutes | Сколько минут требуется и сколько осталось. Если длительность ещё неизвестна, в первом поле будет null. |
supported_platforms | unsupported_platform | Список допустимых платформ: ["youtube", "x", "tiktok", "instagram", "facebook", "bluesky", "twitch", "dailymotion", "pinterest", "linkedin", "snapchat"]. |
missing_chunks | upload_incomplete | Индексы недостающих частей файла. |
max_bytes | media_too_large | Ваш лимит размера файла в байтах. |
params | invalid_request | Ошибки в полях тела запроса или query-параметрах. Ключ объекта — имя поля, значение — описание проблемы. |
Ошибки запроса
| HTTP-код | code | Повторить без изменений? | Причина и действие |
|---|---|---|---|
| 400, 422 | invalid_request | Нет | Не хватает параметра или поля, либо значение недопустимо. Например, нельзя сочетать diarize с source: "captions", а reuse_recent — с webhook_url. Невалидный JSON даёт тот же код. |
| 422 | invalid_url | Нет | Проверьте ссылку и её соответствие platform. Подойдут YouTube, X, TikTok, Instagram, Facebook, Bluesky и другие платформы из раздела «Источники и параметры». |
| 422 | unsupported_platform | Нет | API не поддерживает указанное значение platform. |
| 422 | unsupported_media | Нет | Расширение загруженного файла не входит в список поддерживаемых. |
| 401 | unauthorized | Нет | Ключ или токен не передан, неверен, истёк или отозван. Для загрузки — токен неверен или истёк. |
| 403 | insufficient_scope | Нет | В OAuth-токене нет нужного разрешения: transcriptions:read или transcriptions:write. |
| 403 | email_not_verified | Нет | Для создания задачи сначала подтвердите почту. |
| 402 | insufficient_minutes | Нет | На балансе 0 минут или их не хватает на запись. |
| 402 | no_active_plan | Нет | Для покупки дополнительных минут нужен активный платный тариф. Ошибку возвращает только платёжный эндпоинт личного кабинета, не эндпоинты транскрибации. |
| 404 | not_found | Нет | Задача не найдена или принадлежит другой команде. |
| 409 | upload_incomplete | Нет | Загрузите недостающие части файла и снова вызовите завершение загрузки. |
| 409 | invalid_state | Нет | Задача больше не ждёт загрузки. Отправлять части или завершать её уже нельзя. |
| 409 | idempotency_conflict | Нет | Этот Idempotency-Key ранее передали с другим набором параметров. |
| 413 | media_too_large | Нет | Размер файла превышает ваш лимит — см. «Загрузка файлов». |
| 413 | invalid_request | Нет | Тело JSON превышает 1 МБ. Для слишком большого файла используется другой код: media_too_large. |
| 429 | rate_limited | Да | Исчерпан лимит запросов в минуту. Число секунд до повтора указано в Retry-After. |
| 429 | too_many_active_jobs | Да | Достигнут лимит выполняющихся задач или открытых загрузок. Подождите столько секунд, сколько указано в Retry-After. |
| 500 | internal_error | Да | Ошибка на стороне transcript1. Попробуйте ещё раз чуть позже. |
| 503 | service_unavailable | Да | Сервис временно недоступен. Попробуйте ещё раз чуть позже. |
Если браузерный запрос использует cookie входа, проверяем также источник. Вызов с другого сайта вернёт 403 forbidden_origin.
К API-запросам с заголовком Authorization эта проверка не относится.
В любом ответе 429 есть Retry-After — время ожидания в секундах. Значения лимитов приведены в разделе «Тарифы и лимиты».
Когда повторять запрос
- Автоматический повтор допустим при
retryable=true: дляrate_limited,too_many_active_jobs,internal_errorиservice_unavailable. - Выдержите паузу из
Retry-After. Если заголовка нет, увеличивайте интервал между попытками. - Для повторного
POST /v1/transcriptionsсохраняйте прежнийIdempotency-Key. Если первый запрос успел пройти, новая попытка не приведёт к повторному списанию. - Остальные ошибки требуют исправления запроса. Отправлять его без изменений не стоит.
Если транскрибация завершилась с ошибкой
Если у задачи status=failed, причину можно узнать из объекта error с полями code и message.
Ошибка может возникнуть уже после успешного HTTP-ответа. Проверяйте error, когда запрашиваете статус или получаете вебхук transcription.failed.
error.code | Что случилось | Что делать |
|---|---|---|
media_unavailable | Видео удалено, не существует или недоступно. | Проверьте URL. Повтор без изменений не поможет. |
media_private | Доступ к видео закрыт. | Нужен публичный пост. Для YouTube подойдёт также видео с доступом по ссылке. |
login_required | Для просмотра нужен вход в аккаунт. | Не повторяйте: это постоянная ошибка, автоматических повторов нет. |
no_audio | У видео нет звуковой дорожки. | Не повторяйте: это постоянная ошибка, автоматических повторов нет. |
age_restricted | Просмотр ограничен по возрасту. | Вместо повторного запроса загрузите файл. |
live_stream | Трансляция ещё идёт или не началась. | Попробуйте после её завершения. |
no_captions | В режиме captions не нашлось подходящей дорожки субтитров. | Смените source на "auto" или "stt". |
media_too_long | Запись длиннее 5 часов — лимита распознавания речи. | Разделите запись. Повтор целиком не поможет. |
unsupported_media | Не удалось прочитать файл или в нём нет аудиодорожки. | Отправьте файл в поддерживаемом формате. |
no_speech | Речь не обнаружена. | Не повторяйте. |
unsupported_language | Язык записи не поддерживается. | Укажите в language поддерживаемый код или "auto". Без изменений не повторяйте. |
insufficient_minutes | К моменту списания на балансе не хватило минут. | Пополните баланс и попробуйте снова. |
fetch_failed | Несколько попыток скачать запись не удались. | Попробуйте ещё раз позже. |
transcription_failed | Распознать речь не удалось даже после повторных попыток. | Попробуйте ещё раз позже. |
Если транскрибация завершилась с ошибкой или вы её отменили, платить не нужно. Уже списанные минуты вернём на баланс.
Объект 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."
}
]
}
}Поля
- idstringобязательный
- objectstringобязательный
Допустимые значения
transcription - statusstringобязательный
Допустимые значения
awaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled - sourceobjectобязательный
Показать вложенные поляСкрыть вложенные поля
With
url- platformstringобязательный
- urlstringобязательныйдопускает null
- media_idstringобязательныйдопускает null
With
filename- platformstringобязательный
Допустимые значения
upload - filenamestringобязательныйдопускает null
- sizenumberобязательныйдопускает null
- mediaobjectобязательныйдопускает null
Показать вложенные поляСкрыть вложенные поля
- titlestringнеобязательныйдопускает null
- authorstringнеобязательныйдопускает null
- author_urlstringнеобязательныйдопускает null
- thumbnail_urlstringнеобязательныйдопускает null
- filenamestringнеобязательный
- mime_typestringнеобязательный
- sizenumberнеобязательный
- duration_secondsnumberнеобязательныйдопускает null
- optionsobjectобязательный
Показать вложенные поляСкрыть вложенные поля
- sourcestringобязательный
Допустимые значения
autocaptionsstt - languagestringобязательный
- diarizebooleanобязательный
- transcript_sourcestringобязательныйдопускает null
Допустимые значения
youtube_captionsx_captionsspeech_to_text - caption_kindstringобязательныйдопускает null
Допустимые значения
manualauto_generated - languagestringобязательныйдопускает null
- billed_minutesintegerобязательныйдопускает null
- cachedbooleanобязательный
- errorobjectобязательныйдопускает null
Показать вложенные поляСкрыть вложенные поля
- codestringобязательный
- messagestringобязательныйдопускает null
- created_atstring · date-timeобязательныйдопускает null
- completed_atstring · date-timeобязательныйдопускает null
- deleted_atstring · date-timeобязательныйдопускает null
When the transcription was deleted. Always
nullunless the request includesinclude_deleted=true. - transcriptobjectнеобязательный
Included in
GETresponses for completed transcriptions.Показать вложенные поляСкрыть вложенные поля
- textstringобязательный
- speakersarray of stringsобязательный
- segmentsarray of objectsобязательный
Показать вложенные поляСкрыть вложенные поля
- startnumberобязательный
- endnumberобязательный
- speakerstringобязательныйдопускает null
- languagestringобязательныйдопускает null
- textstringобязательный
- wordsarray of objectsнеобязательныйдопускает null
Показать вложенные поляСкрыть вложенные поля
- startnumberобязательный
- endnumberобязательный
- textstringобязательный
- confidencenumberнеобязательныйдопускает null
- speakerstringобязательныйдопускает 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
}Параметры запроса
- waitintegerнеобязательныйдопускает nullПо умолчанию: 0
Seconds to wait for a final status before responding, up to 60. Defaults to 0.
- reuse_recentstringнеобязательныйПо умолчанию: 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.Допустимые значения
truefalse
Заголовки
- Idempotency-Keystringнеобязательный
Returns the original transcription when you repeat a request with the same key and parameters.
Тело запроса
With url
- platformstringнеобязательный
Optional; detected from the link. If supplied, must match the link.
Допустимые значения
youtubextiktokinstagramfacebookblueskytwitchdailymotionpinterestlinkedinsnapchat - urlstringобязательный
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.
- sourcestringнеобязательный
"auto" uses YouTube or X captions when available, otherwise speech-to-text. "captions" is YouTube/X-only. "stt" always uses speech-to-text.
Допустимые значения
autocaptionsstt - languagestringнеобязательный
- diarizebooleanнеобязательный
- webhook_urlstring · uriнеобязательный
With upload
- uploadobjectобязательный
Показать вложенные поляСкрыть вложенные поля
- filenamestringобязательный
- sizeintegerобязательный
- mime_typestringнеобязательный
- sourcestringнеобязательный
Допустимые значения
autostt - languagestringнеобязательный
- diarizebooleanнеобязательный
- webhook_urlstring · uriнеобязательный
multipart/form-data
- filestring · binaryобязательный
- sourcestringнеобязательный
Допустимые значения
autostt - languagestringнеобязательный
- diarizebooleanнеобязательный
- webhook_urlstring · uriнеобязательный
Коды ответа
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
Остальные коды
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."
}
]
}
}Параметры пути
- idstringобязательный
Параметры запроса
- waitintegerнеобязательныйдопускает nullПо умолчанию: 0
Seconds to wait for a final status before responding, up to 60. Defaults to 0.
- formatstringнеобязательныйПо умолчанию: json
Допустимые значения
jsontextsrtvtt - includestringнеобязательный
Допустимые значения
words - timestampsstringнеобязательныйПо умолчанию: false
Допустимые значения
truefalse - include_deletedstringнеобязательныйПо умолчанию: false
Also returns deleted transcriptions as read-only records without a transcript. Their
deleted_atis set. Defaults tofalse.Допустимые значения
truefalse
Коды ответа
200 OK— The transcription, or the rendered transcript202 Accepted— A rendered format was requested while the transcription is still processing
Остальные коды
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"
}Параметры запроса
- limitintegerнеобязательныйПо умолчанию: 20
- cursorstringнеобязательный
- statusstringнеобязательный
Допустимые значения
awaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled - platformstringнеобязательный
- include_deletedstringнеобязательныйПо умолчанию: false
Also returns deleted transcriptions as read-only records without a transcript. Their
deleted_atis set. Defaults tofalse.Допустимые значения
truefalse
Коды ответа
200 OK— A page of transcriptions
Остальные коды
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"Ответ без тела
Параметры пути
- idstringобязательный
Коды ответа
204 No Content— Canceled or deleted
Остальные коды
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
}Параметры пути
- idstringобязательный
- indexintegerнеобязательныйдопускает null
Zero-based chunk number from the upload plan
Заголовки
- X-Upload-Tokenstringобязательный
Тело запроса
- (исходное тело запроса)string · binaryобязательный
Коды ответа
200 OK— The chunk was stored
Остальные коды
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"
}Параметры пути
- idstringобязательный
Коды ответа
200 OK— Upload progress
Остальные коды
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
}Параметры пути
- idstringобязательный
Коды ответа
202 Accepted— The transcription is queued
Остальные коды
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
}
}Коды ответа
200 OK— The authenticated user's account
Остальные коды
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.
Объект 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
}
}Поля
- objectstringобязательный
Допустимые значения
account - userobjectобязательный
Показать вложенные поляСкрыть вложенные поля
- idstringобязательный
- emailstringобязательный
- planobjectобязательныйдопускает null
Показать вложенные поляСкрыть вложенные поля
- idstringобязательный
- namestringобязательный
- minutesobjectобязательный
Показать вложенные поляСкрыть вложенные поля
- remainingnumberобязательный
- cyclenumberобязательный
- topupnumberобязательный
- topup_usablebooleanобязательный
- resets_atstring · date-timeобязательныйдопускает null
- renews_atstring · date-timeобязательныйдопускает null
- limitsobjectобязательный
Показать вложенные поляСкрыть вложенные поля
- requests_per_minutenumberобязательный
- max_active_jobsnumberобязательный
Вебхуки
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
}
}Укажите webhook_url, когда создаёте задачу. После успешного завершения или ошибки transcript1 отправит на этот адрес подписанный POST.
Настроить вебхук можно только через REST API. Инструменты MCP-сервера не принимают этот параметр.
Куда отправлять уведомления
В POST /v1/transcriptions передайте webhook_url:
- Если отправляете ссылку на видео или создаёте загрузку по частям — в теле JSON.
- Если загружаете файл одним запросом — в поле формы.
Требования к ссылке:
- протокол HTTPS;
- без логина и пароля в URL;
- хост разрешается в публичный адрес.
Частный, loopback, link-local или другой непубличный адрес даст 422 invalid_request. Проверяем адрес и при создании задачи, и перед каждой отправкой вебхука.
В одном запросе нельзя передавать webhook_url и reuse_recent=true.
События
type | Что произошло |
|---|---|
transcription.completed | Транскрипт готов, статус задачи — completed. |
transcription.failed | Задача завершилась с failed. Код и описание ошибки находятся в data.error, в полях code и message. |
Если вы отменили транскрибацию, уведомления не будет.
Тело запроса
Уведомление приходит в формате JSON:
- В
created_atзаписано время создания события. - В
dataнаходится объект транскрибации, но без поляtranscript.
Возьмите id из data и запросите готовый текст через GET /v1/transcriptions/:id.
В запросе будут следующие заголовки:
Content-Type: application/jsonUser-Agent: transcript1-webhooks/1.0X-Transcript1-Signature— подпись для проверки подлинности запроса.
Как проверить подпись
С каждым вебхуком передаём X-Transcript1-Signature в формате t=<unix seconds>,v1=<hex digest>.
t— Unix-время подписания запроса, в секундах.v1— шестнадцатеричный HMAC-SHA256 для строки"<t>.<raw body>". Соберите её изt, точки и исходного тела запроса. Ключ — секрет подписи целиком, с префиксомwhsec_.
Вычисляйте подпись по исходным байтам, до разбора JSON. После разбора и обратной сериализации могут измениться пробелы или порядок ключей — подпись уже не совпадёт.
- Используйте сравнение за постоянное время.
- Проверяйте расхождение
tс текущим временем и отклоняйте запрос при слишком большой разнице. В примерах допустимы 5 минут. - В Express сначала прочитайте тело как текст, без разбора JSON.
- В Flask получите исходное тело через
request.get_data(as_text=True)и передайте его вraw_body.
Где взять секрет подписи
У команды один секрет для вебхуков всех её транскрибаций. Он начинается с whsec_.
Посмотреть или заменить его можно на странице «Webhooks».
После замены старый секрет сразу перестаёт действовать. Все последующие вебхуки подписываем новым.
Доставка и повторные попытки
- Верните любой код
2xx, чтобы подтвердить получение вебхука. - Другой статус, ошибка соединения или отсутствие ответа за 10 секунд означают, что попытка не удалась.
- При неудаче повторяем отправку с растущими паузами: 2, 4, 8, 16 и 32 минуты. Всего будет не больше 6 попыток, последняя — примерно через час после первой.
- Сразу указывайте конечный URL. transcript1 не следует редиректам: ответ
3xxтоже считается неудачей. - Один вебхук может прийти несколько раз — например, если ваш сервер ответил уже после таймаута. Отсеивайте дубликаты по сочетанию
data.idиtype.