Справочник API
Эндпоинты, поля, ответы, кредиты, лимиты и ошибки.
Обновлено
Как это работает#
Каждый транскрипт создаётся как задача. Вы отправляете источник, задача выполняется в фоновом режиме, и после успешного завершения она указывает на транскрипт, который можно читать и экспортировать сколько угодно раз. Базовый URL: https://www.transcriptdock.com. Все запросы и ответы в формате JSON.
# 1. Submitcurl -X POST https://www.transcriptdock.com/v1/jobs \-H "Authorization: Bearer td_live_YOUR_KEY" \-H "Idempotency-Key: video-7680721699171601694" \-H "Content-Type: application/json" \-d '{ "source": { "url": "https://www.tiktok.com/@tiktok/video/7680721699171601694" }, "mode": "captions_only" }'# 2. Wait (returns as soon as the job finishes, up to 25 s per call)curl "https://www.transcriptdock.com/v1/jobs/11111111-1111-4111-8111-111111111111?wait=25" \-H "Authorization: Bearer td_live_YOUR_KEY"# 3. Exportcurl "https://www.transcriptdock.com/v1/transcripts/22222222-2222-4222-8222-222222222222/export?format=srt" \-H "Authorization: Bearer td_live_YOUR_KEY"
Аутентификация#
Создайте ключ на странице API-ключей. Ключ показывается один раз, выглядит как td_live_... и передаётся в заголовке Authorization в каждом запросе. Области доступа задаются при создании ключа: jobs:read, jobs:write, transcripts:read, uploads:write. Создавайте отдельный ключ для каждой интеграции, чтобы отозвать его по отдельности.
Authorization: Bearer td_live_YOUR_KEY
Idempotency-Key#
Обязателен для POST /v1/jobs, /v1/batches, /v1/jobs/{id}/retry, /v1/video-discoveries и /v1/language-discoveries. Это любая строка длиной от 8 до 128 печатных символов ASCII. Повторный запрос с тем же ключом и тем же телом в течение 48 часов возвращает исходный объект, поэтому повторный запрос никогда не создаст задачу и не спишет кредиты дважды. Тот же ключ с другим телом возвращает 409 IDEMPOTENCY_CONFLICT. Удобно использовать в качестве ключа собственный идентификатор того, что вы транскрибируете.
X-Request-Id#
Каждый ответ содержит его. Укажите его, когда пишете в поддержку.
Эндпоинты#
| Метод | Путь | Что делает | Кредиты |
|---|---|---|---|
| POST | /v1/jobs | Транскрибировать одно видео, файл или ссылку | 1 за транскрипт по субтитрам, 2 за минуту ИИ-транскрипции |
| GET | /v1/jobs/{id} | Статус задачи, ожидание до 25 с | Бесплатно |
| GET | /v1/jobs | История задач | Бесплатно |
| POST | /v1/jobs/{id}/cancel | Отменить задачу в очереди | Бесплатно |
| POST | /v1/jobs/{id}/retry | Повторить неудачную задачу | Как новая задача |
| POST | /v1/batches | Транскрибировать много видео (размер пакета зависит от тарифа) | За каждый элемент, как выше |
| GET | /v1/batches/{id} | Статус пакета | Бесплатно |
| GET | /v1/transcripts/{id} | Транскрипт в JSON | Бесплатно |
| GET | /v1/transcripts/{id}/export | Файл txt, srt, vtt или json | Бесплатно |
| DELETE | /v1/transcripts/{id} | Удалить транскрипт | Бесплатно |
| POST | /v1/uploads | Получить URL для загрузки файла | Бесплатно |
| POST | /v1/uploads/{id}/complete | Отметить загрузку завершённой | Бесплатно |
| POST | /v1/video-discoveries | Поиск на YouTube, список видео канала, плейлиста или профиля TikTok | 1 за страницу |
| GET | /v1/video-discoveries/{id} | Результат поиска видео | Бесплатно |
| POST | /v1/language-discoveries | Список языков субтитров видео YouTube | 1 |
| GET | /v1/language-discoveries/{id} | Список языков | Бесплатно |
| POST | /v1/webhook-endpoints | Зарегистрировать URL вебхука (нужен вход в аккаунт) | Бесплатно |
| GET | /v1/webhook-endpoints | Список URL вебхуков | Бесплатно |
| DELETE | /v1/webhook-endpoints/{id} | Отключить URL вебхука (нужен вход в аккаунт) | Бесплатно |
| GET | /v1/usage | Кредиты и тариф | Бесплатно |
| GET | /v1/capabilities | Что может ваш ключ | Бесплатно |
Создание задачи#
/v1/jobsВозвращает 202 с задачей. Если в вашем рабочем пространстве уже есть транскрипт того же видео с теми же параметрами, возвращается 200 с успешно завершённой задачей, бесплатно (billing.kind: "cached").
{"id": "11111111-1111-4111-8111-111111111111","status": "queued","stage": "resolve","result_id": null,"error": null,"billing": { "credits_reserved": 2, "credits_charged": 0, "kind": "captions" },"source": { "platform": "tiktok", "media_id": "7680721699171601694", "canonical_url": "https://www.tiktok.com/@tiktok/video/7680721699171601694", "title": null, "upload_id": null },"options": { "mode": "auto", "language": null, "caption_preference": "prefer_creator" },"created_at": "2026-09-16T10:00:00.000Z"}
Объект задачи#
Получение задачи#
/v1/jobs/{id}?wait=25Возвращает задачу. С параметром wait (от 0 до 25 секунд) запрос остаётся открытым и возвращает ответ, как только задача завершится окончательно, поэтому один вызов заменяет цикл опроса. Чтения имеют собственный лимит: 120 в минуту.
Список задач#
/v1/jobs?limit=20&cursor=Сначала новые, limit от 1 до 100. Передайте next_cursor из ответа обратно как cursor, чтобы получить следующую страницу. Чтобы увидеть только задачи одного видео в любом режиме, укажите platform и source_id (source.media_id задачи) вместе. Так клиент проверяет, есть ли уже в рабочем пространстве транскрипт, прежде чем отправлять задачу снова.
Отмена задачи#
/v1/jobs/{id}/cancelОтменяет задачу, которая ещё не начала ИИ-транскрипцию. Резерв кредитов снимается. Если ИИ-транскрипция уже началась, возвращается 409 CANCELLATION_NOT_ALLOWED, и задача доводится до конца.
Повтор задачи#
/v1/jobs/{id}/retryСоздаёт новую задачу на основе неудачной, у которой ошибка помечена как retryable. Нужен новый Idempotency-Key. Необязательное тело запроса: { "max_credits": 40 }. Оплата такая же, как у новой задачи. Окончательные ошибки (приватное видео, нет субтитров) возвращают 409 JOB_NOT_RETRYABLE: исправьте входные данные и отправьте задачу заново.
Транскрипт#
/v1/transcripts/{id}{"id": "22222222-2222-4222-8222-222222222222","source": { "platform": "youtube", "media_id": "dQw4w9WgXcQ", "canonical_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "title": "Пример видео" },"source_origin": "creator_captions","language": "ru","text": "Добро пожаловать на канал. Сегодня мы разберём субтитры.","segments": [{ "start": 0, "end": 2.4, "text": "Добро пожаловать на канал" },{ "start": 2.4, "end": 4.9, "text": "Сегодня мы разберём субтитры" }],"words": null,"timing_granularity": "segment","duration_seconds": 212.0,"recognition": null,"extraction_version": "worker-0.1.0","created_at": "2026-09-16T10:00:14.000Z"}
Транскрипты хранятся в течение срока хранения вашего тарифа: 7 дней на пробном тарифе, 30 дней на Starter, 90 дней на Pro и Scale. Чтобы удалить транскрипт раньше, используйте DELETE /v1/transcripts/{id}.
Экспорт транскрипта#
/v1/transcripts/{id}/export?format=srt| format | Вы получаете |
|---|---|
| txt | Простой текст, один сегмент на строку. |
| srt | Субтитры SubRip. |
| vtt | Субтитры WebVTT. |
| json | Объект транскрипта выше. |
Бесплатно, без ограничений. Для srt и vtt нужны тайминги. Если их нет, возвращается 422 TIMESTAMPS_UNAVAILABLE.
Пакеты#
/v1/batchesОдин запрос, много видео. Каждый элемент содержит те же поля, что и Создание задачи. Пакет принимается или отклоняется целиком. Количество элементов в пакете: 1 на пробном тарифе, 10 на Starter, 25 на Pro, 50 на Scale.
curl -X POST https://www.transcriptdock.com/v1/batches \-H "Authorization: Bearer td_live_YOUR_KEY" \-H "Idempotency-Key: playlist-2026-09-16" \-H "Content-Type: application/json" \-d '{ "items": [{ "source": { "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ" }, "mode": "captions_only" },{ "source": { "url": "https://www.tiktok.com/@tiktok/video/7680721699171601694" }, "mode": "captions_only" }] }'
Объект пакета содержит status (queued, processing, succeeded, partial_success, failed, cancelled), счётчики (total_items, succeeded_items, failed_items, cancelled_items) и items, где у каждого элемента есть свой job_id. Читайте пакет через GET /v1/batches/{id}. Каждый элемент является обычной задачей.
Загрузки#
Ваши аудио- или видеофайлы (mp3, wav, m4a, ogg, aac, mp4, webm; до 250 МБ и 2 часов). Зарезервируйте место для файла, отправьте файл методом PUT на подписанный URL, отметьте загрузку как завершённую, затем создайте задачу с source.upload_id. Загрузки всегда обрабатываются через ИИ-транскрипцию.
# 1. Reservecurl -X POST https://www.transcriptdock.com/v1/uploads \-H "Authorization: Bearer td_live_YOUR_KEY" \-H "Content-Type: application/json" \-d '{ "filename": "interview.mp3", "content_type": "audio/mpeg", "bytes": 48213920 }'# -> { "id": "33333333-...", "signed_upload_url": "https://...", "expires_at": "...", "status": "pending" }# 2. Upload the bytes (same Content-Type you declared)curl -X PUT "SIGNED_UPLOAD_URL" -H "Content-Type: audio/mpeg" --data-binary @interview.mp3# 3. Completecurl -X POST https://www.transcriptdock.com/v1/uploads/33333333-3333-4333-8333-333333333333/complete \-H "Authorization: Bearer td_live_YOUR_KEY"# 4. Transcribe itcurl -X POST https://www.transcriptdock.com/v1/jobs \-H "Authorization: Bearer td_live_YOUR_KEY" \-H "Idempotency-Key: interview-01" \-H "Content-Type: application/json" \-d '{ "source": { "upload_id": "33333333-3333-4333-8333-333333333333" }, "mode": "transcribe" }'
Подписанный URL действителен 24 часа. После этого зарезервируйте новое место.
Вебхуки#
/v1/webhook-endpointsЗарегистрируйте URL по https и передайте его id как webhook_endpoint_id при отправке задачи. Мы отправляем POST-запрос с событием, когда задача или пакет завершаются. Ответ один раз содержит секрет для подписи (secret). Регистрация и отключение эндпоинтов требуют входа в аккаунт, поэтому делайте это на странице «Вебхуки» в панели управления. API-ключ получит ответ 403 FORBIDDEN, но может просматривать список эндпоинтов.
События#
{"event_id": "44444444-4444-4444-8444-444444444444","type": "job.succeeded","created_at": "2026-09-16T10:00:14.000Z","job_id": "11111111-1111-4111-8111-111111111111","batch_id": null,"result_id": "22222222-2222-4222-8222-222222222222","metadata": { "order": "8812" },"error": null}
job.succeeded: получите или экспортируйтеresult_id.job.failed: вerrorсодержится код.batch.completed: все элементы завершены окончательно. Результаты по каждому элементу читайте в пакете.
Ответьте любым кодом 2xx в течение нескольких секунд. Неудачные доставки повторяются с нарастающими паузами, и их можно отправить повторно из панели управления. Событие может прийти больше одного раза, поэтому отсекайте дубликаты по event_id.
Проверка подписи#
Заголовки X-TranscriptDock-Event-Id, X-TranscriptDock-Timestamp и X-TranscriptDock-Signature. Подпись вычисляется как HMAC-SHA256 (hex) от строки {event_id}.{timestamp}.{raw_body} с вашим секретом. Отклоняйте всё, что старше пяти минут.
import crypto from "node:crypto";export function verify(eventId: string, timestamp: string, rawBody: string, signature: string, secret: string): boolean {if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;const expected = crypto.createHmac("sha256", secret).update(`${eventId}.${timestamp}.${rawBody}`).digest("hex");return expected.length === signature.length && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));}
Поиск видео#
/v1/video-discoveriesИщите видео на YouTube или получайте список видео канала, плейлиста или профиля TikTok, затем передавайте ссылки в задачи. Поиск выполняется в фоновом режиме, как задача: читайте его через GET /v1/video-discoveries/{id}, пока status не станет succeeded. 1 кредит за страницу; результаты хранятся 24 часа.
curl -X POST https://www.transcriptdock.com/v1/video-discoveries \-H "Authorization: Bearer td_live_YOUR_KEY" \-H "Idempotency-Key: search-async-rust-1" \-H "Content-Type: application/json" \-d '{ "kind": "youtube_search", "query": "async rust", "limit": 5 }'
POST-запрос отвечает 202 со статусом status: "queued". Готовый ответ GET /v1/video-discoveries/{id} выглядит так:
{"id": "55555555-5555-4555-8555-555555555555","kind": "youtube_search","status": "succeeded","request": { "kind": "youtube_search", "query": "async rust", "limit": 5 },"videos": [{"platform": "youtube","video_id": "wXtngLBkK4Q","url": "https://www.youtube.com/watch?v=wXtngLBkK4Q","title": "Async Rust explained in 20 minutes","channel_id": "UCSp-OaMpsO8K0KkOqyBl7_w","channel_title": "Let's Get Rusty","duration_s": 1155,"published_at": null,"published_text": "5 months ago","view_count": 83635,"view_count_text": "83,635 views","thumbnail_url": "https://i.ytimg.com/vi/wXtngLBkK4Q/hq720.jpg","tiktok": null}],"profile": null,"next_cursor": "opaque-token","error": null,"created_at": "2026-09-16T12:00:00.000Z","updated_at": "2026-09-16T12:00:03.000Z","expires_at": "2026-09-17T12:00:00.000Z"}
Языки субтитров видео#
/v1/language-discoveriesТело запроса: { "source": { "url": "https://www.youtube.com/watch?v=..." } } с заголовком Idempotency-Key (только для YouTube, 1 кредит). Читайте GET /v1/language-discoveries/{id}, чтобы получить список дорожек субтитров с их кодами, признаком «автор» или «автоматические» и языком по умолчанию. Используйте коды в caption_languages.
Использование и возможности#
/v1/usage{"plan": "pro","period_end": "2026-10-16T00:00:00.000Z","credits_remaining": 5840,"credits_total": 6000,"credits_reserved": 4,"prepaid_credits": 0,"transcribe_credits_per_minute": 2,"minimum_billable_seconds": 60,"subscription": {"status": "active","interval": "yearly","cancel_at_period_end": false,"current_period_end": "2027-09-16T00:00:00.000Z"}}
credits_remaining уже не учитывает credits_reserved (резервы для выполняющихся задач). prepaid_credits: купленные кредиты, которые не сгорают.
subscription содержит подписку Stripe, на которой основан платный тариф, а без тарифа равен null. В нём есть status, интервал оплаты interval (monthly или yearly), cancel_at_period_end и current_period_end: когда тариф продлится или закончится. period_end показывает, когда обновляются ежемесячные кредиты. На годовых тарифах это тоже происходит каждый месяц.
/v1/capabilitiesЧто ваш ключ может делать прямо сейчас: по каждому источнику (youtube, tiktok, instagram, upload, direct) доступные режимы, а также лимиты и цены. Не зашивайте эти значения в код, читайте их отсюда. Например, на пробном тарифе для auto и transcribe возвращается значение false.
{"youtube": { "enabled": true, "captions_only": true, "auto": true, "transcribe": true, "social_acquisition_fee": true },"tiktok": { "enabled": true, "captions_only": true, "auto": true, "transcribe": true, "social_acquisition_fee": true },"instagram": { "enabled": false, "captions_only": false, "auto": false, "transcribe": false, "social_acquisition_fee": true, "native_captions": "unverified_disabled" },"upload": { "enabled": true, "captions_only": false, "auto": true, "transcribe": true, "social_acquisition_fee": false },"direct": { "enabled": true, "captions_only": false, "auto": true, "transcribe": true, "social_acquisition_fee": false },"max_duration_ms": 7200000,"max_media_bytes": 262144000,"export_formats": ["txt", "json", "srt", "vtt"],"recognition_profiles": ["standard"],"transcribe_credits_per_minute": 2,"minimum_billable_seconds": 60,"price_version": "2026-09-14","asr_enabled": true,"instagram_enabled": false,"free_caption_credits": 50,"free_caption_credits_period": "month"}
Лимиты запросов#
| Тариф | Отправки / мин | Задач в работе | Чтение / мин |
|---|---|---|---|
| Пробный | 10 | 10 | 120 |
| Starter | 60 | 100 | 120 |
| Pro | 120 | 500 | 120 |
| Scale | 300 | 2 000 | 120 |
Если превышен лимит, вы получите 429 RATE_LIMITED с заголовком retry-after (в секундах) и details.detail, где назван лимит. Кредиты не списываются. Вебхуки и ?wait=25 помогают держаться далеко от лимита чтения.
Ошибки#
Все ошибки имеют одинаковый формат. retryable: true означает, что тот же запрос может пройти позже: подождите столько секунд, сколько указано в retry-after (если он есть), иначе сделайте паузу на несколько секунд, и используйте тот же Idempotency-Key, чтобы ничего не дублировалось. Любой другой ошибке нужно исправление с вашей стороны.
{"error": {"code": "INSUFFICIENT_BALANCE","message": "Not enough credits. Buy credits or upgrade your plan to continue.","retryable": false,"details": { "detail": "This job needs more credits than you have left. Buy credits or upgrade your plan." },"doc_url": "https://www.transcriptdock.com/docs/api-reference#error-codes"},"request_id": "66666666-6666-4666-8666-666666666666"}
Задача, которая завершилась ошибкой после принятия, всё равно возвращает 200 на GET /v1/jobs/{id}, со статусом status: "failed" и тем же объектом ошибки в error. За неудачную задачу кредиты не списываются.
Коды#
| Код | HTTP | Повтор | Значение и что делать |
|---|---|---|---|
INVALID_REQUEST | 422 | Нет | Поле отсутствует или имеет неверный формат. В details.detail указано, какое именно. |
INVALID_URL | 422 | Нет | Ссылка не является корректным URL по https (до 2048 символов). |
UNSUPPORTED_SOURCE | 422 | Нет | Ссылка не является URL видео YouTube или TikTok. |
UNSAFE_URL | 422 | Нет | Прямая ссылка на медиа ведёт на закрытый или заблокированный сетевой адрес. |
INVALID_CURSOR | 422 | Нет | Курсор поиска видео истёк или повреждён. Начните заново с первой страницы. Некорректный курсор списка задач возвращает INVALID_REQUEST. |
CAPABILITY_UNAVAILABLE | 422 | Нет | Этот режим недоступен для данного источника. Что доступно, показывает GET /v1/capabilities. |
IDEMPOTENCY_CONFLICT | 409 | Нет | Этот Idempotency-Key уже использовался с другим телом запроса. Используйте новый ключ. |
UNAUTHENTICATED | 401 | Нет | В заголовке Authorization нет действительного API-ключа или токена OAuth. |
FORBIDDEN | 403 | Нет | У ключа нет области доступа для этого эндпоинта, или рабочее пространство отключено. |
EMAIL_UNVERIFIED | 403 | Нет | Подтвердите email аккаунта, прежде чем использовать API. |
NOT_FOUND | 404 | Нет | Такого объекта нет в этом рабочем пространстве. |
INSUFFICIENT_BALANCE | 402 | Нет | Недостаточно кредитов для этой задачи. Купите кредиты или перейдите на другой тариф. |
PLAN_REQUIRED | 402 | Нет | Нужен платный тариф (ИИ-транскрипция, большие пакеты) или пробные кредиты закончились. |
BUDGET_EXCEEDED | 402 | Нет | Измеренная стоимость выше max_credits. Кредиты не списаны. Повысьте лимит или пропустите медиафайл. |
JOB_NOT_RETRYABLE | 409 | Нет | Ошибка окончательная (приватное видео, нет субтитров). Исправьте входные данные и отправьте новую задачу. |
CANCELLATION_NOT_ALLOWED | 409 | Нет | ИИ-транскрипция уже началась, задача будет завершена. |
RATE_LIMITED | 429 | Да | Превышен лимит запросов или очереди. Подождите столько секунд, сколько указано в retry-after. В details.detail написано, какой лимит превышен. |
SOURCE_NOT_FOUND | 422 | Нет | Видео не существует или было удалено. |
SOURCE_PRIVATE | 422 | Нет | Видео приватное. Работают только публичные видео. |
SOURCE_AUTH_REQUIRED | 422 | Нет | Для видео нужен вход в аккаунт, подтверждение возраста или членство в канале. |
SOURCE_REGION_RESTRICTED | 422 | Нет | Видео заблокировано в регионах, из которых мы его получаем. |
NO_CAPTIONS | 422 | Нет | У видео нет субтитров, а режим был captions_only. Используйте auto или transcribe. |
LANGUAGE_UNAVAILABLE | 422 | Нет | Ни один язык из caption_languages не найден у этого видео. Уберите список, чтобы взять дорожку по умолчанию. |
LANGUAGE_UNSUPPORTED | 422 | Нет | ИИ-транскрипция не поддерживает запрошенный язык. |
NO_SPEECH | 422 | Нет | ИИ-транскрипция не нашла речи в аудио. |
NO_AUDIO | 422 | Нет | В медиафайле нет аудиодорожки. |
INVALID_MEDIA | 422 | Нет | Не удалось прочитать файл как аудио или видео. |
UNSUPPORTED_MEDIA | 422 | Нет | Это не аудио- или видеофайл. |
DURATION_LIMIT_EXCEEDED | 413 | Нет | Длиннее 2 часов. |
FILE_TOO_LARGE | 413 | Нет | Больше 250 МБ. |
TIMESTAMPS_UNAVAILABLE | 422 | Нет | У этого транскрипта нет таймингов, поэтому экспорт в srt и vtt недоступен. Используйте txt или json. |
PROVIDER_REJECTED | 422 | Нет | Модель ИИ-транскрипции не смогла обработать это аудио. |
SOURCE_RATE_LIMITED | 503 | Да | Платформа-источник ограничивает наши запросы. Задача повторится автоматически. |
SOURCE_BLOCKED | 503 | Да | Платформа-источник заблокировала получение данных. Задача повторится автоматически. |
SOURCE_TIMEOUT | 503 | Да | Платформа-источник не ответила вовремя. Задача повторится автоматически. |
SOURCE_CHANGED | 503 | Да | Источник изменился, пока мы его читали. Задача повторится автоматически. |
PROVIDER_UNAVAILABLE | 503 | Да | ИИ-транскрипция временно недоступна. Задача повторится автоматически. |
STORAGE_UNAVAILABLE | 503 | Да | Хранилище файлов временно недоступно. Повторите запрос. |
INTERNAL_ERROR | 500 | Да | Ошибка на нашей стороне. Повторите запрос с тем же Idempotency-Key. Если ошибка повторяется, укажите X-Request-Id. |