CaptionPipe

Una llamada incrusta subtítulos en tu video. Alojado, prepagado, sin suscripción. MP4 más SRT y VTT.

Servidor MCP alojado

npx add-mcp 'https://api.captionpipe.com/mcp'

Se instala en Claude Code, Codex, Cursor y más

Documentación

Conecta y luego subtitula.

Elige la herramienta en la que estás trabajando. Los clientes interactivos inician sesión a través del navegador; las herramientas de automatización usan una clave del panel de control. De cualquier manera, son las mismas cuatro herramientas, y un video en una URL es una sola llamada.

MCP

https://api.captionpipe.com/mcp

REST

https://api.captionpipe.com/v1

Claude Code

Inicia sesión, o usa una clave

Un solo comando añade el servidor. Inicia sesión una vez y estará disponible en todos tus proyectos.

  1. 1 Añade el servidor e inicia sesión
    claude mcp add --transport http captionpipe https://api.captionpipe.com/mcp
    claude
    > /mcp        # choose captionpipe, finish sign-in in the browser
    
  2. 2 Pregunta
    Caption https://cdn.acme.com/clip.mp4 with the highlight preset. Get "Acme" and "SK-7" spelled right, and give me the MP4 and the SRT.
    

Un archivo en tu máquina

Proporciona la ruta. Claude Code llama a create_upload, envía los bytes y luego caption_video. Tú no haces nada de eso manualmente.

Otras formas de acceso

En lugar del comando del paso 1

O haz commit en el repositorio

Claude Code omite una entrada remota sin tipo y advierte que necesita uno. La mayoría de los fragmentos en línea lo omiten.

{
  "mcpServers": {
    "captionpipe": { "type": "http", "url": "https://api.captionpipe.com/mcp" }
  }
}

En lugar de iniciar sesión

Con una clave API en su lugar

Crea una clave en el panel de control en la sección Conectar. Se muestra una sola vez.

claude mcp add --transport http captionpipe https://api.captionpipe.com/mcp \
  --header "Authorization: Bearer $CAPTIONPIPE_API_KEY"

Verificado con Claude Code 2.1.263 el 8 de septiembre de 2026.

Herramientas

Las cuatro herramientas

Las rutas REST son /v1/create_upload, /v1/caption_video, /v1/jobs/{id} y /v1/render_captions. Las herramientas MCP aceptan el mismo JSON como argumentos.

create_upload{ contentLength?, sha256?, idempotencyKey? }

→ { jobId, uploadUrl, expiresAt }

Solo para un archivo en tu lado. Devuelve una URL de solo PUT para un objeto, válida por una hora. Declara contentLength si conoces el tamaño en bytes y la URL está vinculada a él; si lo omites, el límite de 2 GB se verifica cuando se ejecuta caption_video. El objeto se sella cuando se ejecuta caption_video. Si tu video ya está en una URL, omite esta herramienta por completo.

caption_video{ jobId | inputUrl, preset, highlightColor?, dictionary?, language?, idempotencyKey? }

→ { jobId, status: "probing" }

Exactamente una fuente: el jobId de create_upload, o un enlace directo a un archivo de video. Las páginas de plataformas como YouTube o TikTok son rechazadas. preset es highlight, clean o boxed. dictionary admite hasta 1,000 términos de hasta seis palabras cada uno, retenidos para este trabajo y eliminados con sus archivos. language es auto o una etiqueta BCP-47. highlightColor es un RGB hexadecimal para la palabra hablada y se aplica solo al preset highlight; el valor predeterminado es el acento de CaptionPipe.

get_caption_job{ jobId }

→ el trabajo, con artefactos una vez completado

Haz polling. retryAfterSeconds te indica cuándo volver mientras el trabajo está en ejecución. Una vez completado, los artefactos son enlaces firmados válidos hasta expiresAt, 24 horas después de la finalización; después de eso, el trabajo responde job_not_found. Después de una llamada a render_captions, render indica qué versión se solicitó y si aún se está renderizando, está completada o falló; los enlaces siempre pertenecen a la versión finalizada más reciente. Cada respuesta incluye tu saldo, para que un agente nunca descubra un saldo vacío al encontrar un error.

render_captions{ jobId, words, preset?, highlightColor?, idempotencyKey? }

→ el trabajo, con render.status accepted

Envía el words.json editado y volvemos a grabar el video exactamente con esas palabras. No se ejecuta ningún modelo de voz. Opcionalmente cambia el preset o el color de resaltado. Gratis, 3 veces por trabajo en una cuenta de pago y 1 en la de prueba, dentro de las 24 horas posteriores a la finalización; la ventana y los archivos expiran juntos. Haz polling a get_caption_job hasta que render.status sea completed, cuando los enlaces cambien a la nueva versión. Sin idempotencyKey, cada llamada usa un re-render del cupo.

Estado

Estado del trabajo

Una sola forma de respuesta en todas partes: MCP, REST y el panel de control leen el mismo objeto.

upload_pending

create_upload emitió una URL; los bytes aún no han llegado.

probing

Estamos verificando que sea un video dentro de los límites. Aún no se cobra nada.

reserved

Duración conocida; los segundos están retenidos en tu saldo y el habla está a punto de comenzar.

processing

Habla y grabación. retryAfterSeconds indica cuándo hacer polling nuevamente.

completed

Los artefactos están listos. chargedSeconds es definitivo y nunca supera la retención.

failed

Un error tipificado. La retención se libera y no se cobra nada.

{
  "jobId": "job_9f2",
  "status": "completed",
  "preset": "highlight",
  "durationSeconds": 42,
  "chargedSeconds": 42,
  "retryAfterSeconds": null,
  "balance": {
    "remainingSeconds": 258,
    "trialRemainingSeconds": 0,
    "paidRemainingSeconds": 258,
    "reservedSeconds": 0,
    "topUpUrl": null
  },
  "balanceWarning": null,
  "rerendersRemaining": 3,
  "dictionaryCapacityApplied": 1000,
  "artifacts": {
    "mp4":       { "url": "https://...", "expiresAt": "2026-09-04T12:00:00Z" },
    "srt":       { "url": "https://...", "expiresAt": "..." },
    "vtt":       { "url": "https://...", "expiresAt": "..." },
    "ass":       { "url": "https://...", "expiresAt": "..." },
    "wordsJson": { "url": "https://...", "expiresAt": "..." }
  },
  "expiresAt": "2026-09-04T12:00:00Z",
  "error": null,
  "render": null
}

Errores

Errores

Un solo formato, un código legible por máquina y un mensaje escrito para ser la solución. Ningún error se cobra: la retención, si la hubo, se devuelve.

{
  "ok": false,
  "error": {
    "code": "insufficient_balance",
    "message": "This video needs 0:42 and 0:18 is available. No job was started.",
    "retryable": false,
    "details": { "requiredSeconds": 42, "remainingSeconds": 18 }
  },
  "balance": { "remainingSeconds": 18, "reservedSeconds": 0, "topUpUrl": "https://..." }
}
CódigoCuándoReintentarHaz esto
unauthenticatedFalta la clave o el token, o son inválidos. HTTP 401.NoVerifica el encabezado Authorization, o inicia sesión nuevamente en tu cliente.
job_not_foundjobId desconocido, o uno que pertenece a otra cuenta.NoUsa el jobId de la respuesta que lo creó.
invalid_sourceAmbos o ninguno de jobId e inputUrl.NoEnvía exactamente uno.
invalid_requestArgumentos mal formados, o un diccionario o lista de palabras con la forma incorrecta.NoEl mensaje indica el campo.
upload_incompleteSe llamó a caption_video antes de que el PUT terminara.Termina la subida y vuelve a llamar con el mismo jobId.
upload_url_expiredPUT intentado después de la ventana de una hora.NoLlama a create_upload nuevamente para obtener una URL nueva.
checksum_mismatchEnviaste un sha256 y los bytes subidos no coinciden.NoSube el archivo nuevamente u omite el hash.
file_size_limit_exceededMás de 2 GB, en create_upload o a mitad de transmisión.NoComprime o divide el archivo.
invalid_mediaEl archivo no pudo leerse como video con audio utilizable.NoVerifica que se reproduzca y tenga audio, luego envíalo nuevamente.
probe_failedEl archivo no pudo inspeccionarse.NoRe-codifica a H.264 en MP4 e inténtalo de nuevo.
unsupported_ratioCuadrado o una relación de aspecto inusual.NoUsa un video 9:16 o 16:9. Los detalles incluyen ancho y alto.
unsupported_inputCódec no compatible, o velocidad de fotogramas por encima del límite.NoRe-codifica a H.264 a 60 fps o menos.
duration_limit_exceededMás de 30 minutos.NoRecorta el video.
trial_duration_limit_exceededMás de 3 minutos en una cuenta de prueba.NoUsa un video más corto, o compra minutos para subtitular hasta 30:00.
insufficient_balanceEl video cuesta más segundos de los que tienes. Se verifica después de la prueba, antes de cualquier habla.Después de recargartopUpUrl en la respuesta va directo al pago.
trial_concurrency_limitUn segundo trabajo mientras un trabajo de prueba está en ejecución.Espera al trabajo en ejecución.
concurrency_limitMás de 3 de tus trabajos en ejecución, o el servicio está a plena capacidad.Espera a que un trabajo termine y reintenta.
unsupported_source_urlUna página de plataforma en lugar de un archivo de video, contenido que no es video, o una dirección a la que nunca nos conectamos (privada, local, metadatos).NoPasa una URL https pública directa al archivo multimedia, o sube el archivo.
url_fetch_failedEl host no resolvió, no conectó o no respondió 200; demasiado lento para comenzar o terminar; demasiadas redirecciones.Cuando sea transitorioVerifica que la URL sirva el archivo directamente, o súbelo.
rerenders_exhaustedrender_captions más allá del cupo.NoInicia un nuevo trabajo.
rerender_window_expiredrender_captions más de 24 horas después de la finalización.NoInicia un nuevo trabajo.
processing_unavailableAmbos proveedores de voz están caídos, o un trabajo no pudo enviarse.Si la llamada fue rechazada, reinténtala con el mismo idempotencyKey después de retryAfterSeconds. Si un trabajo volvió como fallido, envíalo nuevamente con uno nuevo.

Límites

Límites

Cada uno de estos se verifica antes de que se te cobre, así que un archivo que no podemos aceptar no te cuesta nada.

Duración

Hasta 30 minutos

Tamaño

Hasta 2 GB de entrada

Salida

1080p H.264, máximo 60 fps

Formato

Vertical primero. 16:9 compatible. El cuadrado se rechaza antes de que se te cobre

Archivos

Disponibles durante 24 horas después de que un trabajo termina

Por llamada

Un video

Facturación

Facturación y reembolsos

  • Cada trabajo se cobra por el segundo completo de la duración del video, redondeado hacia arriba, contra un saldo prepagado.
  • Los segundos de prueba se consumen antes que los de pago. Un trabajo puede abarcar ambos.
  • Cuando un trabajo comienza, retenemos los segundos probados; el panel muestra la retención como reservado. Al completarse, la retención se convierte en el cargo, nunca más. Si falla, la retención se devuelve.
  • $10 compran 250 minutos, de 1 a 10 bloques por pago. Sin suscripción, nada se renueva, los minutos pagados nunca expiran.
  • Cada respuesta incluye balance.topUpUrl. Es null hasta que estés bajo o bloqueado, luego es un enlace de pago que un agente puede entregarte.
  • Los minutos pagados no utilizados son reembolsables a solicitud, netos de la comisión de tarjeta que Stripe retiene. La prueba no lo es.

Solución de problemas

Solución de problemas

El trabajo permanece en probing o processing

Haz polling a get_caption_job y respeta retryAfterSeconds. Un trabajo que no puede completarse falla en minutos con la retención devuelta; nunca queda atascado para siempre.

El enlace del artefacto devuelve 403

Los enlaces expiran 24 horas después de la finalización, y también los archivos. Inicia un nuevo trabajo.

Mi cliente no lista herramientas

Recarga o reinicia el cliente después de editar su configuración, y verifica la forma de configuración para ese cliente arriba. Los bloques de Cursor y VS Code no son intercambiables.

El inicio de sesión se abre pero el cliente nunca conecta

Completa el paso del navegador en la misma máquina donde se ejecuta el cliente. Si aún falla, crea una clave API en el panel y usa la forma de clave de la configuración.

Un nombre está mal escrito

Envíalo en dictionary la próxima vez. Para este trabajo, edita words.json y llama a render_captions; el re-render es gratuito.

La respuesta dice dictionaryCapacityApplied: 0

Nuestro proveedor de voz principal no estaba disponible y la alternativa se ejecutó sin el diccionario. Re-renderiza con las palabras corregidas, o vuelve a ejecutar el trabajo más tarde.