Saltar al contenido
Transcript Dock
Iniciar sesiónEmpezar gratis

Menú del sitio

Transcript Dock
IntroducciónCómo funciona, guías y qué puedes transcribir.
Inicio rápidoEnvía un enlace, espera el trabajo y exporta la transcripción. Tres solicitudes.
AutenticaciónClaves de API, scopes, Idempotency-Key y X-Request-Id.
TrabajosCrea, espera, lista, cancela y reintenta trabajos.
TranscripcionesEl objeto de transcripción y las exportaciones txt, srt, vtt y json.
LotesHasta 50 videos en una sola solicitud.
CargasTranscribe tus propios archivos de audio y video.
WebhooksRecibe una llamada cuando termina un trabajo o un lote y verifica la firma.
ErroresTodos los códigos de error, qué significan y qué hacer.
Límites de usoEnvíos, trabajos en curso y lecturas por plan, y la respuesta 429.
Precios y créditos1 crédito por transcripción de subtítulos y 2 por minuto de transcripción con IA. Planes y créditos extra.
FuentesYouTube, TikTok, tus archivos y enlaces directos: URL aceptadas y modos.
MCPBusca y transcribe videos desde Claude, Cursor, Windsurf o tu propio agente.
Especificación OpenAPILa especificación OpenAPI 3.1 para generar código y clientes tipados.
Claude CodeUn solo comando agrega Transcript Dock a Claude Code.
App de ClaudeAgrega Transcript Dock como conector personalizado en claude.ai, Claude Desktop o el móvil.
CursorAgrega Transcript Dock como servidor MCP en Cursor.
WindsurfAgrega Transcript Dock a Windsurf para que Cascade pueda buscar y transcribir videos.
OpenClawConecta Transcript Dock a los agentes autónomos de OpenClaw.
19 resultados
API

Referencia de la API

Endpoints, campos, respuestas, créditos, límites y errores.

Actualizado


Cómo funciona#

Cada transcripción es un trabajo. Envías una fuente, el trabajo se ejecuta en segundo plano y, cuando termina con éxito, apunta a una transcripción que puedes leer o exportar tantas veces como quieras. URL base: https://www.transcriptdock.com. Todas las solicitudes y respuestas son JSON.

# 1. Submit
curl -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. Export
curl "https://www.transcriptdock.com/v1/transcripts/22222222-2222-4222-8222-222222222222/export?format=srt" \
-H "Authorization: Bearer td_live_YOUR_KEY"
Nunca llames a la API desde un navegador: tu clave quedaría visible para cualquiera. Llámala desde tu servidor y guarda la clave en una variable de entorno.

Autenticación#

Crea claves en la página de claves de API. Una clave se muestra una sola vez, tiene el aspecto td_live_... y va en el encabezado Authorization de cada solicitud. Las claves llevan permisos que se eligen al crearlas: jobs:read, jobs:write, transcripts:read, uploads:write. Crea una clave por integración para poder revocarla por separado.

encabezado
Authorization: Bearer td_live_YOUR_KEY

Idempotency-Key#

Obligatoria en POST /v1/jobs, /v1/batches, /v1/jobs/{id}/retry, /v1/video-discoveries y /v1/language-discoveries: cualquier cadena de 8 a 128 caracteres ASCII imprimibles. Enviar la misma clave con el mismo cuerpo dentro de 48 horas devuelve el objeto original, así que una solicitud reintentada nunca crea ni cobra dos veces. La misma clave con un cuerpo distinto devuelve 409 IDEMPOTENCY_CONFLICT. Una buena clave es tu propio id de lo que estás transcribiendo.

X-Request-Id#

Todas las respuestas incluyen uno. Cítalo cuando contactes a soporte.

Endpoints#

MétodoRutaQué haceCréditos
POST/v1/jobsTranscribe un video, archivo o enlace1 por transcripción de subtítulos, 2 por minuto de transcripción con IA
GET/v1/jobs/{id}Estado del trabajo, espera hasta 25 sGratis
GET/v1/jobsHistorial de trabajosGratis
POST/v1/jobs/{id}/cancelCancela un trabajo en colaGratis
POST/v1/jobs/{id}/retryReintenta un trabajo fallidoComo un trabajo nuevo
POST/v1/batchesTranscribe muchos videos (tamaño de lote del plan)Por elemento, como arriba
GET/v1/batches/{id}Estado del loteGratis
GET/v1/transcripts/{id}JSON de la transcripciónGratis
GET/v1/transcripts/{id}/exportArchivo txt, srt, vtt o jsonGratis
DELETE/v1/transcripts/{id}Elimina una transcripciónGratis
POST/v1/uploadsObtén una URL para subir un archivoGratis
POST/v1/uploads/{id}/completeMarca la subida como terminadaGratis
POST/v1/video-discoveriesBusca en YouTube o lista un canal, una lista de reproducción o un perfil de TikTok1 por página
GET/v1/video-discoveries/{id}Resultado de la búsquedaGratis
POST/v1/language-discoveriesLista los idiomas de subtítulos de un video de YouTube1
GET/v1/language-discoveries/{id}Lista de idiomasGratis
POST/v1/webhook-endpointsRegistra una URL de webhook (con sesión iniciada)Gratis
GET/v1/webhook-endpointsLista las URL de webhookGratis
DELETE/v1/webhook-endpoints/{id}Desactiva una URL de webhook (con sesión iniciada)Gratis
GET/v1/usageCréditos y planGratis
GET/v1/capabilitiesLo que puede hacer tu claveGratis

Crear un trabajo#

POST/v1/jobs
source.urlstringOpcional
Un video público: YouTube (watch?v=, youtu.be, shorts, live) o TikTok (tiktok.com/@user/video/…, enlaces para compartir vm.tiktok.com). Cualquier otro enlace https a un archivo de audio o video se trata como un enlace directo a medios (transcripción con IA). Es obligatorio uno de url o upload_id.
source.upload_iduuidOpcional
Un archivo que subiste (consulta Subidas). Siempre transcripción con IA.
mode"captions_only" | "auto" | "transcribe"Obligatorio
captions_only: los subtítulos propios del video, 1 crédito; falla con NO_CAPTIONS si no hay ninguno. auto: subtítulos cuando existen (1 crédito); si no, transcripción con IA. transcribe: siempre transcripción con IA del audio, 2 créditos por minuto iniciado, con tiempos por palabra. La transcripción con IA requiere un plan de pago.
caption_languagesstring[]Opcional
Idiomas de subtítulos preferidos, en orden, p. ej. ["en", "es"], hasta 5. Por defecto: la pista predeterminada del video. Solo captions_only y auto.
caption_preference"prefer_creator" | "creator_only" | "automatic_only"Opcional
Si se aceptan los subtítulos que subió el creador, los subtítulos automáticos de YouTube o cualquiera de los dos (por defecto prefer_creator: primero los del creador).
languagestringOpcional
Pista del idioma hablado para la transcripción con IA (BCP 47). Por defecto: detectarlo.
max_creditsintegerOpcional
Tope de gasto para la transcripción con IA. Primero se mide el archivo; si costara más, el trabajo falla con BUDGET_EXCEEDED y no se cobra nada. Por defecto: lo suficiente para 2 horas.
webhook_endpoint_iduuidOpcional
Recibe job.succeeded / job.failed en este webhook.
metadataobjectOpcional
Hasta 10 valores de tipo cadena (claves ≤ 64, valores ≤ 256 caracteres). Se devuelve tal cual en los eventos de webhook. No afecta la caché.

Devuelve 202 con el trabajo. Si tu espacio de trabajo ya tiene una transcripción del mismo video y con las mismas opciones, devuelve 200 con un trabajo terminado, gratis (billing.kind: "cached").

Respuesta 202
{
"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"
}

El objeto de trabajo#

iduuidOpcional
Id del trabajo.
statusstringOpcional
queued → processing (→ awaiting_provider durante la transcripción con IA) → succeeded, failed o cancelled. Los tres últimos son finales.
stagestring | nullOpcional
En qué punto va un trabajo en ejecución: resolve, captions, acquire_audio, submit_asr, wait_asr, finalize. Solo informativo.
result_iduuid | nullOpcional
La transcripción, una vez que el trabajo termina con éxito.
errorobject | nullOpcional
Si falla: code, message, retryable y, opcional, details.detail. Los mismos códigos que en Errores.
billingobjectOpcional
credits_reserved (retenidos mientras se ejecuta, 0 al terminar), credits_charged (final), kind: captions, ai_transcription o cached.
sourceobjectOpcional
platform, media_id, canonical_url, title, upload_id.
optionsobjectOpcional
mode, language, caption_preference tal como se aceptaron.
created_atdate-timeOpcional
UTC.

Obtener un trabajo#

GET/v1/jobs/{id}?wait=25

Devuelve el trabajo. Con wait (de 0 a 25 segundos) la solicitud queda abierta y responde en cuanto el trabajo llega a un estado final, así una sola llamada reemplaza un ciclo de sondeo. Las lecturas tienen su propio límite de 120 por minuto.

Listar trabajos#

GET/v1/jobs?limit=20&cursor=

Del más reciente al más antiguo, con limit de 1 a 100. Pasa el next_cursor de la respuesta como cursor para obtener la página siguiente. Agrega platform y source_id (el source.media_id de un trabajo) juntos para ver solo los trabajos de un video, en cualquier modo. Así es como un cliente comprueba si el espacio de trabajo ya tiene una transcripción antes de volver a enviar.

Cancelar un trabajo#

POST/v1/jobs/{id}/cancel

Cancela un trabajo que todavía no empezó la transcripción con IA; se libera la retención. Después de ese punto devuelve 409 CANCELLATION_NOT_ALLOWED y el trabajo termina.

Reintentar un trabajo#

POST/v1/jobs/{id}/retry

Crea un trabajo nuevo a partir de uno fallido cuyo error era retryable. Requiere un Idempotency-Key nuevo; cuerpo opcional { "max_credits": 40 }. Se cobra como un trabajo nuevo. Los fallos definitivos (video privado, sin subtítulos) devuelven 409 JOB_NOT_RETRYABLE: corrige la entrada y envía de nuevo.

La transcripción#

GET/v1/transcripts/{id}
iduuidOpcional
Igual que el result_id del trabajo.
sourceobjectOpcional
platform, media_id, canonical_url, title.
source_originstringOpcional
creator_captions, platform_captions (subtítulos que generó la plataforma, como los subtítulos automáticos de YouTube) o speech_recognition (transcripción con IA).
languagestring | nullOpcional
Etiqueta BCP 47 del texto.
textstringOpcional
La transcripción completa como texto plano.
segmentsarrayOpcional
Fragmentos del tamaño de un subtítulo: { start, end, text } en segundos.
wordsarray | nullOpcional
{ start, end, text, confidence } por palabra. Solo transcripción con IA.
timing_granularity"word" | "segment" | "none"Opcional
El tiempo más fino disponible.
duration_secondsnumber | nullOpcional
Duración del archivo multimedia.
extraction_versionstringOpcional
Versión del pipeline que produjo el resultado.
recognitionobject | nullOpcional
Solo transcripción con IA: model, profile, quality_status (validated_language: lo evaluamos con pruebas de referencia; provider_supported: el modelo lo incluye en su lista; experimental_language: la calidad puede variar).
created_atdate-timeOpcional
UTC.
Respuesta 200
{
"id": "22222222-2222-4222-8222-222222222222",
"source": { "platform": "youtube", "media_id": "dQw4w9WgXcQ", "canonical_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "title": "Never Gonna Give You Up" },
"source_origin": "creator_captions",
"language": "en",
"text": "Never gonna give you up. Never gonna let you down.",
"segments": [
{ "start": 0, "end": 2.4, "text": "Never gonna give you up" },
{ "start": 2.4, "end": 4.9, "text": "Never gonna let you down" }
],
"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"
}

Las transcripciones se conservan durante el período de retención de tu plan (7 días en la prueba, 30 en Starter y 90 en Pro y Scale). DELETE /v1/transcripts/{id} elimina una antes.

Exportar una transcripción#

GET/v1/transcripts/{id}/export?format=srt
formatQué obtienes
txtTexto plano, un segmento por línea.
srtSubtítulos SubRip.
vttSubtítulos WebVTT.
jsonEl objeto de transcripción de arriba.

Gratis e ilimitado. srt y vtt necesitan tiempos; una transcripción sin ellos devuelve 422 TIMESTAMPS_UNAVAILABLE.

Lotes#

POST/v1/batches

Una solicitud, muchos videos. Cada elemento tiene los mismos campos que Crear un trabajo; el lote completo se acepta o se rechaza en conjunto. Elementos por lote: 1 en la prueba, 10 en Starter, 25 en Pro, 50 en Scale.

itemsJobRequest[]Obligatorio
De 1 a 50 solicitudes de trabajo.
webhook_endpoint_iduuidOpcional
Recibe un solo batch.completed cuando todos los elementos llegan a un estado final.
metadataobjectOpcional
Se devuelve tal cual en el evento batch.completed.
POST /v1/batches
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" }
] }'

El objeto de lote tiene status (queued, processing, succeeded, partial_success, failed, cancelled), conteos (total_items, succeeded_items, failed_items, cancelled_items) e items, cada uno con su job_id. Léelo con GET /v1/batches/{id}; cada elemento es un trabajo normal.

Subidas#

Tu propio audio o video (mp3, wav, m4a, ogg, aac, mp4, webm; hasta 250 MB y 2 horas). Reserva un espacio, haz PUT del archivo a la URL firmada, márcalo como completo y luego envíalo como trabajo con source.upload_id. Las subidas siempre usan transcripción con IA.

subir y transcribir
# 1. Reserve
curl -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. Complete
curl -X POST https://www.transcriptdock.com/v1/uploads/33333333-3333-4333-8333-333333333333/complete \
-H "Authorization: Bearer td_live_YOUR_KEY"
 
# 4. Transcribe it
curl -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" }'
filenamestringObligatorio
Hasta 255 caracteres.
content_typestringObligatorio
El tipo MIME del archivo, p. ej. audio/mpeg o video/mp4. Envía el mismo valor en el PUT.
bytesintegerObligatorio
Tamaño exacto del archivo. El PUT debe coincidir.

La URL firmada es válida por 24 horas; pasado ese tiempo, reserva un espacio nuevo.

Webhooks#

POST/v1/webhook-endpoints

Registra una URL https y pasa su id como webhook_endpoint_id al enviar. Te enviamos un POST con un evento cuando el trabajo o el lote termina. La respuesta incluye el secret de firma una sola vez. Registrar y desactivar endpoints requiere una sesión iniciada, así que hazlo en la página Webhooks del panel; una clave de API recibe 403 FORBIDDEN ahí, pero sí puede listar endpoints.

urlstringObligatorio
URL https, hasta 2048 caracteres.
descriptionstringOpcional
Una etiqueta para tu propia referencia.

Eventos#

job.succeeded
{
"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: obtén o exporta result_id.
  • job.failed: error trae el código.
  • batch.completed: todos los elementos llegaron a un estado final; lee el lote para ver los resultados de cada elemento.

Responde con cualquier 2xx en pocos segundos. Las entregas que fallan se reintentan con espera creciente y se pueden reenviar desde el panel. Un evento puede llegar más de una vez: elimina duplicados con event_id.

Verifica la firma#

Encabezados X-TranscriptDock-Event-Id, X-TranscriptDock-Timestamp y X-TranscriptDock-Signature. La firma es el HMAC-SHA256 (hex) de {event_id}.{timestamp}.{raw_body} con tu secreto. Rechaza todo lo que tenga más de cinco minutos.

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

Encontrar videos#

POST/v1/video-discoveries

Busca en YouTube o lista un canal, una lista de reproducción o un perfil de TikTok, y luego pasa las URL a trabajos. Una búsqueda se ejecuta en segundo plano como un trabajo: léela con GET /v1/video-discoveries/{id} hasta que status sea succeeded. 1 crédito por página; los resultados se conservan 24 horas.

kindstringObligatorio
youtube_search, youtube_channel_videos, youtube_channel_search, youtube_playlist_videos o tiktok_user_videos.
querystringOpcional
Texto de búsqueda (youtube_search, youtube_channel_search).
channelstringOpcional
@handle, id de canal o URL de canal (tipos de canal).
playliststringOpcional
Id o URL de la lista de reproducción (youtube_playlist_videos).
userstringOpcional
@user o URL del perfil (tiktok_user_videos).
limitintegerOpcional
Videos por página, de 1 a 50, por defecto 20. TikTok: máximo 10.
cursorstringOpcional
next_cursor de la página anterior. Solo YouTube.
include_detailsbooleanOpcional
Solo TikTok: además obtiene los me gusta, comentarios, hashtags e idiomas de subtítulos de cada video.
buscar en YouTube
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 }'

El POST responde 202 con status: "queued". Un GET /v1/video-discoveries/{id} terminado se ve así:

Respuesta 200
{
"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"
}

Idiomas de subtítulos de un video#

POST/v1/language-discoveries

Cuerpo { "source": { "url": "https://www.youtube.com/watch?v=..." } } con un Idempotency-Key (solo YouTube, 1 crédito). Lee GET /v1/language-discoveries/{id} para obtener la lista de pistas de subtítulos con sus códigos, si son del creador o automáticas, y cuál es la predeterminada. Usa los códigos en caption_languages.

Uso y capacidades#

GET/v1/usage
Respuesta 200
{
"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 ya excluye credits_reserved (las retenciones de los trabajos en ejecución). prepaid_credits son créditos comprados, que nunca vencen.

subscription es la suscripción de Stripe detrás de un plan de pago y null si no hay ninguna: su status, el interval de facturación (monthly o yearly), cancel_at_period_end y current_period_end, que indica cuándo el plan se renueva o termina. period_end es cuando se renuevan los créditos mensuales, cada mes también en los planes anuales.

GET/v1/capabilities

Lo que tu clave puede hacer ahora mismo: por fuente (youtube, tiktok, instagram, upload, direct), qué modos están disponibles, además de los límites y los precios. Lee esto en lugar de dejarlo fijo en tu código; la prueba, por ejemplo, informa auto y transcribe como false.

Respuesta 200
{
"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"
}

Límites de frecuencia#

PlanEnvíos / minTrabajos en cursoLecturas / min
Prueba1010120
Starter60100120
Pro120500120
Scale3002,000120

Si superas un límite recibes 429 RATE_LIMITED con un encabezado retry-after (en segundos) y details.detail con el nombre del límite. No se cobra nada. Los webhooks y ?wait=25 te mantienen lejos del límite de lecturas.

Errores#

Todos los errores tienen la misma forma. retryable: true significa que la misma solicitud puede funcionar más tarde: espera retry-after segundos si viene en la respuesta; si no, reintenta con una espera creciente de unos segundos, y reutiliza el mismo Idempotency-Key para que nada se duplique. Cualquier otro error requiere un cambio de tu parte.

Respuesta 402
{
"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"
}

Un trabajo que falla después de haberse aceptado sigue siendo 200 en GET /v1/jobs/{id}, con status: "failed" y el mismo objeto de error en error. No se cobra nada por un trabajo fallido.

Códigos#

CódigoHTTPReintentoSignificado y qué hacer
INVALID_REQUEST422NoA field is missing or has the wrong shape. details.detail names it.
INVALID_URL422NoThe URL is not a valid https link (max 2048 characters).
UNSUPPORTED_SOURCE422NoThe link is not a YouTube or TikTok video URL.
UNSAFE_URL422NoThe direct media link points at a private or blocked network address.
INVALID_CURSOR422NoA video discovery cursor expired or is malformed. Start again from the first page. A bad job list cursor returns INVALID_REQUEST.
CAPABILITY_UNAVAILABLE422NoThis mode is not available for this source. GET /v1/capabilities shows what is.
IDEMPOTENCY_CONFLICT409NoThis Idempotency-Key was already used with a different body. Use a new key.
UNAUTHENTICATED401NoNo valid API key or OAuth token in the Authorization header.
FORBIDDEN403NoThe key lacks the scope for this endpoint, or the workspace is disabled.
EMAIL_UNVERIFIED403NoVerify the account email before using the API.
NOT_FOUND404NoNo such object in this workspace.
INSUFFICIENT_BALANCE402NoNot enough credits for this job. Buy credits or upgrade.
PLAN_REQUIRED402NoThis needs a paid plan (AI transcription, larger batches) or the trial credits are used up.
BUDGET_EXCEEDED402NoThe measured cost is above max_credits. Nothing was charged; raise the cap or skip the media.
JOB_NOT_RETRYABLE409NoThe failure was final (private video, no captions). Fix the input and submit a new job.
CANCELLATION_NOT_ALLOWED409NoAI transcription already started; the job will finish.
RATE_LIMITED429SíOver a rate or queue limit. Wait retry-after seconds; details.detail says which limit.
SOURCE_NOT_FOUND422NoThe video does not exist or was removed.
SOURCE_PRIVATE422NoThe video is private. Only public videos work.
SOURCE_AUTH_REQUIRED422NoThe video needs a login, age check or membership.
SOURCE_REGION_RESTRICTED422NoThe video is blocked in the regions we fetch from.
NO_CAPTIONS422NoNo captions on this video and mode was captions_only. Use auto or transcribe.
LANGUAGE_UNAVAILABLE422NoNone of caption_languages exists on this video. Drop the list to take the default track.
LANGUAGE_UNSUPPORTED422NoAI transcription does not support the requested language.
NO_SPEECH422NoAI transcription found no speech in the audio.
NO_AUDIO422NoThe media has no audio track.
INVALID_MEDIA422NoThe file could not be read as audio or video.
UNSUPPORTED_MEDIA422NoNot an audio or video file type.
DURATION_LIMIT_EXCEEDED413NoLonger than 2 hours.
FILE_TOO_LARGE413NoLarger than 250 MB.
TIMESTAMPS_UNAVAILABLE422NoThis transcript has no timings, so srt and vtt exports are unavailable. Use txt or json.
PROVIDER_REJECTED422NoThe AI transcription model could not process this audio.
SOURCE_RATE_LIMITED503SíThe source platform is throttling us. The job retries automatically.
SOURCE_BLOCKED503SíThe source platform blocked the fetch. The job retries automatically.
SOURCE_TIMEOUT503SíThe source platform timed out. The job retries automatically.
SOURCE_CHANGED503SíThe source changed while we read it. The job retries automatically.
PROVIDER_UNAVAILABLE503SíAI transcription is temporarily unavailable. The job retries automatically.
STORAGE_UNAVAILABLE503SíFile storage is temporarily unavailable. Retry the request.
INTERNAL_ERROR500SíOur fault. Retry with the same Idempotency-Key; quote X-Request-Id if it persists.