ДокументацияСправочник по API

Справочник по API

Параметры и примеры запросов для всех эндпоинтов /v1. Спецификация OpenAPI доступна для скачивания в JSON и YAML.

Об API

Базовый URL
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:readGET /v1/transcriptions, GET /v1/transcriptions/:id, GET /v1/transcriptions/:id/upload и GET /v1/account
transcriptions:writePOST /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.
  • При загрузке по частям можно повторить запрос создания с тем же ключом, чтобы получить свежий токен загрузки.

Ошибки

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
  }
}
  • Ошибка запроса: API не принял вызов. Код и описание придут в HTTP-ответе.
  • Ошибка задачи: API создал транскрибацию, но выполнить её не удалось. У задачи будет status=failed.

Формат ошибки

При ошибке запроса к /v1 API возвращает объект error. В нём всегда есть code, message и retryable.

  • Выбирайте способ обработки по code.
  • Текст message предназначен для пользователя. Не привязывайте к нему логику: формулировка может измениться.
  • При retryable=true можно попробовать тот же запрос позже.

У некоторых ошибок есть дополнительные поля рядом с retryable:

ПолеКод ошибкиЧто содержит
action_urlinsufficient_minutesСсылку для подключения тарифа или покупки минут.
minutes_needed, minutes_remaininginsufficient_minutesСколько минут требуется и сколько осталось. Если длительность ещё неизвестна, в первом поле будет null.
supported_platformsunsupported_platformСписок допустимых платформ: ["youtube", "x", "tiktok", "instagram", "facebook", "bluesky", "twitch", "dailymotion", "pinterest", "linkedin", "snapchat"].
missing_chunksupload_incompleteИндексы недостающих частей файла.
max_bytesmedia_too_largeВаш лимит размера файла в байтах.
paramsinvalid_requestОшибки в полях тела запроса или query-параметрах. Ключ объекта — имя поля, значение — описание проблемы.

Ошибки запроса

HTTP-кодcodeПовторить без изменений?Причина и действие
400, 422invalid_requestНетНе хватает параметра или поля, либо значение недопустимо. Например, нельзя сочетать diarize с source: "captions", а reuse_recent — с webhook_url. Невалидный JSON даёт тот же код.
422invalid_urlНетПроверьте ссылку и её соответствие platform. Подойдут YouTube, X, TikTok, Instagram, Facebook, Bluesky и другие платформы из раздела «Источники и параметры».
422unsupported_platformНетAPI не поддерживает указанное значение platform.
422unsupported_mediaНетРасширение загруженного файла не входит в список поддерживаемых.
401unauthorizedНетКлюч или токен не передан, неверен, истёк или отозван. Для загрузки — токен неверен или истёк.
403insufficient_scopeНетВ OAuth-токене нет нужного разрешения: transcriptions:read или transcriptions:write.
403email_not_verifiedНетДля создания задачи сначала подтвердите почту.
402insufficient_minutesНетНа балансе 0 минут или их не хватает на запись.
402no_active_planНетДля покупки дополнительных минут нужен активный платный тариф. Ошибку возвращает только платёжный эндпоинт личного кабинета, не эндпоинты транскрибации.
404not_foundНетЗадача не найдена или принадлежит другой команде.
409upload_incompleteНетЗагрузите недостающие части файла и снова вызовите завершение загрузки.
409invalid_stateНетЗадача больше не ждёт загрузки. Отправлять части или завершать её уже нельзя.
409idempotency_conflictНетЭтот Idempotency-Key ранее передали с другим набором параметров.
413media_too_largeНетРазмер файла превышает ваш лимит — см. «Загрузка файлов».
413invalid_requestНетТело JSON превышает 1 МБ. Для слишком большого файла используется другой код: media_too_large.
429rate_limitedДаИсчерпан лимит запросов в минуту. Число секунд до повтора указано в Retry-After.
429too_many_active_jobsДаДостигнут лимит выполняющихся задач или открытых загрузок. Подождите столько секунд, сколько указано в Retry-After.
500internal_errorДаОшибка на стороне transcript1. Попробуйте ещё раз чуть позже.
503service_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

Объект 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 null unless the request includes include_deleted=true.

  • transcriptobjectнеобязательный

    Included in GET responses 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/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
}

Параметры запроса

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

    Допустимые значения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 status
  • 201 Created — The transcription is awaiting a chunked upload. upload describes where to send each chunk.
  • 202 Accepted — The transcription is processing

Остальные коды

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

Параметры пути

  • 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_at is set. Defaults to false.

    Допустимые значенияtruefalse

Коды ответа

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

Остальные коды

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

Параметры запроса

  • limitintegerнеобязательныйПо умолчанию: 20
  • cursorstringнеобязательный
  • statusstringнеобязательный

    Допустимые значенияawaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled

  • platformstringнеобязательный
  • include_deletedstringнеобязательныйПо умолчанию: false

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

    Допустимые значенияtruefalse

Коды ответа

  • 200 OK — A page of transcriptions

Остальные коды

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

Ответ без тела

Параметры пути

  • idstringобязательный

Коды ответа

  • 204 No Content — Canceled or deleted

Остальные коды

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

Параметры пути

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

Параметры пути

  • idstringобязательный

Коды ответа

  • 200 OK — Upload progress

Остальные коды

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

Параметры пути

  • idstringобязательный

Коды ответа

  • 202 Accepted — The transcription is queued

Остальные коды

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

Коды ответа

  • 200 OK — The authenticated user's account

Остальные коды

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

Объект Account

Объект 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));
};
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
  }
}

Укажите 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/json
  • User-Agent: transcript1-webhooks/1.0
  • X-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.