# Cómo crear subtítulos SRT de un vídeo con una API

> Envía el vídeo a POST /transcribe indicando output_format como srt y word_timestamps en false, espera a que termine la tarea y guarda el texto que devuelve en un archivo .srt. Si quieres los subtítulos traducidos a otro idioma, añade translate_to. Aquí veremos qué petición enviar exactamente, qué lleva dentro el SRT, cómo armar líneas a tu medida usando los tiempos por palabra, cómo pasarlo a WebVTT y cómo quemar los subtítulos en el vídeo.

Última actualización: 2026-10-18 · HTML: https://console.kolwrite.com/es/guides/srt-subtitles-api

## La solicitud

Dos llamadas: iniciar el trabajo y consultarlo. El `result` de un trabajo `srt` terminado es una cadena, no JSON. Esta versión solo necesita curl y jq:

```bash
# 1. Start the job. "word_timestamps": false gives one cue per segment.
JOB=$(curl -s https://app.kolwrite.com/transcribe \
  -H "x-api-key: $KOLWRITE_API_KEY" -H "Content-Type: application/json" \
  -d '{"audio_url": "https://example.com/talk.mp3", "model": "oracle", "output_format": "srt", "word_timestamps": false}' \
  | jq -r .jobId)

# 2. Poll until it is done and save the result string as a .srt file.
while true; do
  REPLY=$(curl -s "https://app.kolwrite.com/transcribe/$JOB" -H "x-api-key: $KOLWRITE_API_KEY")
  STATUS=$(echo "$REPLY" | jq -r .status)
  if [ "$STATUS" = "COMPLETED" ]; then echo "$REPLY" | jq -r .result > talk.srt; break; fi
  if [ "$STATUS" = "FAILED" ]; then echo "$REPLY" | jq -r .error; break; fi
  sleep 5
done
```

Puedes mandar el vídeo directamente, porque la API ya se encarga de leer la pista de audio. Si tienes el archivo en local, súbelo antes con `POST /upload` (admite hasta 100 MiB). Para vídeos largos que pesen más, saca primero el audio con ffmpeg. En la [guía de edición de vídeo](https://console.kolwrite.com/es/guides/video-editing-with-ai) tienes una función en Python que hace todo el proceso.

## Qué trae el archivo SRT

Si pasas `"word_timestamps": false`, sale una línea por segmento, igual que en la mayoría de los archivos de subtítulos:

```text
1
00:00:01,000 --> 00:00:03,750
Hello everyone and welcome to the show.

2
00:00:05,000 --> 00:00:07,750
Today we talk about editing video from a transcript.
```

Los tiempos por palabra vienen activados por defecto. En ese modo, la API genera una entrada por palabra donde repite toda la frase y envuelve la palabra activa en una etiqueta `<font>` amarilla. Esto sirve para ir marcando la lectura estilo karaoke, pero no para unos subtítulos normales:

```text
1
00:00:01,000 --> 00:00:01,350
<font color="yellow">Hello</font> everyone and welcome to the show.

2
00:00:01,400 --> 00:00:01,750
Hello <font color="yellow">everyone</font> and welcome to the show.
```

Si quieres subtítulos estándar, pasa `"word_timestamps": false` o arma tú mismo las líneas a partir de las palabras del JSON, como hacemos aquí abajo.

## Armar líneas a medida con los tiempos por palabra

Pide `output_format: "json"` y agrupa tú mismo las palabras con un máximo de 42 caracteres y 6 segundos por línea, abriendo línea nueva después de cada pausa. Así controlas el largo de cada línea, que es importante cuando incrustas los subtítulos en el vídeo.

srt_tools.py

```python
# srt_tools.py — neat subtitle cues from word timings
def srt_time(seconds):
    ms = round(seconds * 1000)
    h, ms = divmod(ms, 3_600_000)
    m, ms = divmod(ms, 60_000)
    s, ms = divmod(ms, 1000)
    return f"{h:02}:{m:02}:{s:02},{ms:03}"


def cues_from_words(words, max_chars=42, max_seconds=6.0, max_gap=0.8):
    """Group timed words into subtitle cues: (start, end, text)."""
    cues, line = [], []
    for word in words:
        text = word["word"].strip()
        if not text:
            continue
        if line:
            length = sum(len(w["word"]) + 1 for w in line) + len(text)
            if (length > max_chars
                    or word["end"] - line[0]["start"] > max_seconds
                    or word["start"] - line[-1]["end"] > max_gap):
                cues.append(line)
                line = []
        line.append({"start": word["start"], "end": word["end"], "word": text})
    if line:
        cues.append(line)
    return [(c[0]["start"], c[-1]["end"], " ".join(w["word"] for w in c)) for c in cues]


def cues_from_result(result):
    """Cues for a whole JSON result; a segment without word times becomes one cue."""
    cues = []
    for segment in result["segments"]:
        if segment.get("words"):
            cues += cues_from_words(segment["words"])
        elif segment["text"].strip():
            cues.append((segment["start"], segment["end"], segment["text"].strip()))
    return cues


def write_srt(cues, path):
    with open(path, "w", encoding="utf-8") as out:
        for number, (start, end, text) in enumerate(cues, 1):
            out.write(f"{number}\n{srt_time(start)} --> {srt_time(end)}\n{text}\n\n")
```

La función `cues_from_result(result)` toma el resultado completo y devuelve tuplas `(start, end, text)`. Si algún modelo no entrega tiempos por palabra, usa los tiempos del segmento como respaldo. Luego, `write_srt(cues, "talk.srt")` guarda el archivo en disco.

## Subtítulos traducidos a otro idioma

Pasa el código del idioma en `translate_to` y elige un modelo Oracle (`oracle_mini` es el más económico con traducción). El texto ya te llegará traducido. Acuérdate de dejar `word_timestamps` en false para tener una línea por segmento.

```json
{
  "audio_url": "https://example.com/lecture-he.mp4",
  "model": "oracle_mini",
  "language": "he",
  "translate_to": "en",
  "output_format": "srt",
  "word_timestamps": false
}
```

Si necesitas el vídeo en varios idiomas, lanza un trabajo por cada idioma. Tómalo como un primer borrador y dale una vuelta a los nombres propios, las cifras y la terminología antes de publicar.

## WebVTT, ASS y otros formatos

La API solo entrega `json`, `txt` o `srt`. Para usar una pista `<video>` de HTML5, convierte el SRT a WebVTT con ffmpeg:

```bash
ffmpeg -i video.srt video.vtt
```

Con ffmpeg puedes convertir entre la mayoría de los formatos de subtítulos siguiendo el mismo paso: basta con cambiar la extensión del archivo de salida.

## Incrusta los subtítulos o adjúntalos

Quemados en el vídeo:

```bash
ffmpeg -i edited.mp4 -vf "subtitles=edited.srt" -c:a copy burned.mp4
```

Como pista opcional dentro de un MP4 (el usuario puede activarla o quitarla):

```bash
ffmpeg -i edited.mp4 -i edited.srt -c copy -c:s mov_text -metadata:s:s:0 language=eng soft.mp4
```

Tanto YouTube Studio como la mayoría de los reproductores y programas de edición aceptan el archivo `.srt` tal cual.

## Subtítulos en hebreo y árabe

- La API devuelve texto en Unicode estándar. De mostrarlo de derecha a izquierda se encarga el reproductor o el filtro de subtítulos de ffmpeg, que se lleva bien con el hebreo y el árabe siempre que la tipografía incluya esos caracteres.
- Elige una fuente que soporte ese alfabeto y saca un fotograma de prueba antes de poner a codificar todo el vídeo. En nuestras pruebas, el hebreo salió bien con Arial, pero con esa misma fuente falló un carácter en una palabra árabe, así que para árabe conviene buscar otra tipografía.

```bash
ffmpeg -i video.mp4 -vf "subtitles=video.he.srt:force_style='FontName=Arial,FontSize=24'" -c:a copy burned.mp4
```

- Si una línea termina en un signo de puntuación o en una palabra en alfabeto latino (como una marca o un número), un reproductor sin soporte para texto bidireccional puede mostrarla en un orden extraño. Haz la prueba en los reproductores que usa tu público.

## Cuánto cuesta

| Trabajo | Modelo | Coste |
| --- | --- | --- |
| Clase de 45 minutos, con subtítulos | `oracle` | 1,08 US$ |
| La misma clase, con subtítulos traducidos | `oracle_mini` | 0,72 US$ |
| Una hora de audio limpio, con subtítulos | `base` | 0,48 US$ |

Se cobra por segundo, sin mínimo. Consulta las tarifas en [/llms/pricing.md](https://console.kolwrite.com/llms/pricing.md).

## Preguntas y respuestas

### ¿Cómo saco un archivo SRT de un vídeo?

Haz una llamada a `POST /transcribe` pasando la URL del vídeo, `output_format: "srt"` y `word_timestamps: false`. Luego consulta el estado del trabajo y guarda el texto de `result` en un archivo `.srt`.

### ¿La API devuelve archivos WebVTT?

No, solo entrega `json`, `txt` o `srt`. Si necesitas pasar el SRT a WebVTT, ejecuta `ffmpeg -i video.srt video.vtt`.

### ¿Por qué me sale una línea por palabra en el SRT?

Porque las marcas de tiempo por palabra están activadas por defecto, lo que genera un SRT con una línea por palabra donde se va resaltando la que suena en ese momento. Pasa `word_timestamps: false` si prefieres una línea por tramo, o arma tú mismo las líneas desde el JSON.

### ¿Puedo sacar los subtítulos directamente en otro idioma?

Sí. Pasa el código del idioma en `translate_to` y usa cualquiera de los modelos Oracle. El texto ya saldrá traducido.

### ¿Qué diferencia hay entre los subtítulos normales y los subtítulos para sordos?

Los subtítulos normales recogen o traducen los diálogos pensando en quien sí oye el audio, mientras que los subtítulos para sordos también indican los ruidos y efectos sonoros. La API te da lo que se dice con sus tiempos; las indicaciones de sonido tendrás que añadirlas aparte.

## Páginas relacionadas

- [Editar vídeo con agentes de IA](https://console.kolwrite.com/es/guides/video-editing-with-ai)
- [API de marcas de tiempo por palabra](https://console.kolwrite.com/es/guides/word-timestamps-api)
- [Subtítulos para pódcasts y YouTube](https://console.kolwrite.com/es/guides/podcast-youtube-captions)
- [Medios, pódcasts y subtítulos](https://console.kolwrite.com/es/use-cases/media)
- [Universidades y estudiantes](https://console.kolwrite.com/es/use-cases/education)
- [Documentación de la API](https://console.kolwrite.com/es/public_api_docs)

---
Obtener una clave de API: https://console.kolwrite.com/auth?lang=es · Documentación de la API: https://console.kolwrite.com/es/public_api_docs · llms.txt: https://console.kolwrite.com/llms.txt
