Guías
API de texto a voz: guía con ejemplos en Python y JS
Equipo de Voizum · Actualizada · 11 min de lectura
Una API de texto a voz convierte texto en un archivo de audio desde tu código o tu automatización, sin nadie pulsando botones. En esta guía verás cómo elegir la que encaja con lo que construyes y una integración completa y real: crear el trabajo, consultar su estado y descargar el MP3. También textos largos, lotes, cómo usar tu propia voz clonada y cómo conectarla con n8n, Make o Zapier.
Qué hace una API de texto a voz y cuándo la necesitas
Una API de TTS es una dirección HTTP: le mandas un texto y una voz, y te devuelve audio. Tiene sentido en cuanto el audio pasa a ser parte de un proceso y no una tarea suelta. Si narras un video al mes, el editor web es más rápido. Si narras uno al día, o tu producto tiene que hablar, la API te ahorra el ciclo de copiar, pegar y descargar cada vez.
Los usos que más vemos:
- Canales de YouTube, también los que no muestran la cara: el guion sale de un paso de escritura (a menudo un modelo de IA) y pasa directo a narración y de ahí al editor de video.
- Formación y cursos: cientos de lecciones cortas que se regeneran cada vez que cambia el texto.
- Apps y productos: avisos, bienvenida, accesibilidad, botones de «escuchar este artículo».
- Lotes: fichas de producto, versión en audio de un blog, menús telefónicos, el mismo guion en varios idiomas.
- Automatizaciones sin código: flujos de n8n, Make o Zapier que convierten una fila nueva de una hoja de cálculo en un MP3.
Cómo elegir una API de voz con IA
Empieza por lo que vas a construir, no por la demo de la voz. Lo que divide el mercado es latencia contra duración: un asistente de voz necesita la primera sílaba en unos cientos de milisegundos y recibe el audio a trozos mientras se genera, mientras que un narrador necesita que un guion de 40 minutos salga en un solo archivo limpio. Pocas APIs hacen bien las dos cosas, y las más baratas por carácter suelen ser las menos naturales.
| Criterio | Por qué importa | Qué mirar |
|---|---|---|
| Latencia o audio largo | Un agente en tiempo real necesita streaming; una narración, archivos largos sin costuras | ¿Hay streaming? ¿Cuánto texto admite cada petición? |
| Idiomas | Cada idioma tiene sus propias voces | ¿La misma voz habla todos los idiomas que necesitas? |
| Voces propias y clonadas | Una voz reconocible es parte de tu marca | ¿Puedes usar tu voz clonada por API? ¿Hay tope de voces? |
| Precio por carácter | Es como acaban cobrando casi todos | Precio por 1.000 caracteres, mínimo por petición, si la API se paga aparte |
| Créditos sin usar | Los planes mensuales se reinician: pagas lo que no usaste | ¿Se acumulan, caducan o se pierden al cancelar? |
| Límites | Peticiones por minuto y trabajos a la vez condicionan tu arquitectura | Cabeceras de límite, Retry-After, trabajos simultáneos |
| Formato y almacenamiento | Vas a guardar, editar o emitir el archivo | Formato (MP3, WAV, PCM) y cuánto tiempo lo guardan |
Tu clave y tu voice_id, paso a paso
Todo es REST con JSON, con la dirección base https://voizum.com/api/v1 y autenticación con una clave Bearer que empieza por sk_voizum_. El flujo es siempre el mismo: crear el trabajo, consultar su estado y descargar el MP3.
- 1Entra en Voizum con Google y compra cualquier pack de créditos: la clave se activa con las dos cosas. La API gasta créditos comprados, nunca los gratis del mes.
- 2Abre la página de API y genera tu clave. Se enseña una sola vez: guárdala en ese momento en una variable de entorno (VOIZUM_API_KEY) o en tu gestor de secretos.
- 3Ten una voz en tu biblioteca: clona la tuya o guarda una de la biblioteca pública con Añadir. La API solo trabaja con las voces de tu biblioteca.
- 4Lístalas con GET /voices. Cada una trae id, name y language; el id es el voice_id que mandas al generar. También lo copias desde la web: Voces, menú ⋯, ID para la API.
- 5Opcional: antes de una tanda grande, GET /status (público, sin clave) te dice si el servicio está en marcha, y GET /account te enseña tu saldo y tus límites.
Ejemplos de código: curl, Python y JavaScript
Los ejemplos funcionan tal cual cambiando YOUR_VOICE_ID y JOB_ID. La dirección del audio que devuelve el estado pide la misma cabecera Authorization y redirige al archivo, así que deja que tu cliente HTTP siga las redirecciones.
curl
Crear el trabajo (202 con job_id y eta_seconds), consultarlo y descargar:
# 1. Crear el trabajo
curl -X POST https://voizum.com/api/v1/tts \
-H "Authorization: Bearer $VOIZUM_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: video-042-intro" \
-d '{"text": "Bienvenidos de nuevo al canal.", "voice_id": "YOUR_VOICE_ID"}'
# 2. Consultar el estado (repite hasta "done")
curl https://voizum.com/api/v1/tts/JOB_ID -H "Authorization: Bearer $VOIZUM_API_KEY"
# 3. Descargar el MP3
curl -L -o narracion.mp3 https://voizum.com/api/v1/tts/JOB_ID/audio -H "Authorization: Bearer $VOIZUM_API_KEY"Python (requests)
El mismo flujo, esperando mientras el trabajo está en cola o generándose:
import os, time, requests
API = "https://voizum.com/api/v1"
H = {"Authorization": "Bearer " + os.environ["VOIZUM_API_KEY"]}
# 1. Crear el trabajo
with open("guion.txt", encoding="utf-8") as f:
texto = f.read()
r = requests.post(API + "/tts", headers=H, json={"text": texto, "voice_id": "YOUR_VOICE_ID"})
r.raise_for_status()
job = r.json()["job_id"]
# 2. Esperar mientras está en cola o generándose
while True:
s = requests.get(API + "/tts/" + job, headers=H).json()
if s["status"] not in ("queued", "processing"):
break
time.sleep(5)
if s["status"] != "done":
raise RuntimeError(s.get("error", s["status"]))
# 3. Descargar el MP3
audio = requests.get(s["audio_url"], headers=H)
audio.raise_for_status()
with open("narracion.mp3", "wb") as f:
f.write(audio.content)JavaScript (Node 18 o posterior, módulos ES)
Con el fetch nativo, sin SDK:
import fs from "node:fs";
const API = "https://voizum.com/api/v1";
const H = { Authorization: "Bearer " + process.env.VOIZUM_API_KEY, "Content-Type": "application/json" };
// 1. Crear el trabajo
const crear = await fetch(API + "/tts", {
method: "POST",
headers: H,
body: JSON.stringify({ text: "Bienvenidos de nuevo al canal.", voice_id: "YOUR_VOICE_ID" }),
});
if (!crear.ok) throw new Error(await crear.text());
const { job_id } = await crear.json();
// 2. Esperar mientras está en cola o generándose
let s;
do {
await new Promise((r) => setTimeout(r, 5000));
s = await (await fetch(API + "/tts/" + job_id, { headers: H })).json();
} while (s.status === "queued" || s.status === "processing");
if (s.status !== "done") throw new Error(s.error ?? s.status);
// 3. Descargar el MP3
const audio = await fetch(s.audio_url, { headers: H });
fs.writeFileSync("narracion.mp3", Buffer.from(await audio.arrayBuffer()));Parámetros opcionales
speed (de 0.5 a 2, por defecto 1), pause_ms (la pausa entre frases, de 0 a 800 ms), language ("auto" o es, en, de, fr, pt, it, ru; si no lo mandas, se deduce del texto) y loudness_normalization (true para que todas las voces salgan al mismo volumen). Los estados posibles son queued, processing, done, error y canceled. La referencia completa está en https://voizum.com/docs, con la especificación OpenAPI en https://voizum.com/openapi.json y una versión en texto plano para asistentes de programación con IA en https://voizum.com/llms.txt.
Textos largos, lotes y diálogos
Una petición admite hasta 600.000 caracteres, unas 10 horas de voz, y vuelve como un solo MP3. No hace falta partir el guion y coser los trozos: el trabajo lo hace por dentro y la consulta de estado enseña el avance (parts_done, parts_total, percent).
Para muchas piezas cortas, POST /tts/batch: hasta 100 audios y 1.200.000 caracteres en total (unas 20 horas). Cada uno sale con su job_id y su archivo, pero el mínimo de 100 créditos se cobra una vez para todo el lote y no una por petición. Ocho avisos cortos de una app cuestan 800 créditos mandados de uno en uno y 100 en lote.
Para una conversación en un solo archivo (la intro de un pódcast, un anuncio a dos voces) está POST /tts/dialogue, con los turnos en orden y hasta 5 voces distintas. Se cobra como un audio normal, por los caracteres de todo el guion.
Usar tu voz clonada por API
La clonación se hace una vez en la web y cuesta 199 créditos; a partir de ahí la voz es un voice_id más y cada audio se cobra igual que con cualquier otra. No hay endpoint de clonar en la API a propósito: la grabación es el paso en el que conviene escuchar antes de seguir. Graba de 15 a 60 segundos solo con tu voz, corta en una pausa y no a mitad de palabra, y habla como quieres que suene la narración, porque la entonación también se copia.
Tus voces clonadas hablan los siete idiomas, así que una grabación en español narra también la versión en inglés, alemán o francés de tu canal. Clona solo tu voz o una que tengas permiso para usar.
Conectarla con n8n, Make o Zapier
Ninguna plataforma de automatización necesita un módulo especial de Voizum: las tres tienen un paso HTTP genérico y la API son tres llamadas sencillas. La única decisión es cómo esperar al audio: preguntar en bucle o dejar que la API te avise con webhook_url.
El aviso (solo en POST /tts) manda un POST con event, id, status (completed o error), voice_id, duration_seconds y credits cuando el trabajo termina, con hasta tres intentos. Tiene que ser una dirección https pública, así que un n8n instalado en tu equipo con localhost no lo recibe: en ese caso, pregunta en bucle.
n8n
Nodo HTTP Request con credenciales Header Auth (Authorization, valor Bearer sk_voizum_…) y un bucle para esperar:
- HTTP Request: POST https://voizum.com/api/v1/tts con un cuerpo JSON que lleve text y voice_id.
- Nodo Wait unos segundos y después HTTP Request: GET /tts/{{ $json.job_id }}.
- Nodo If: si status es done, sigue; si es queued o processing, vuelve al Wait; si es error, para.
- HTTP Request a audio_url con las mismas credenciales y el formato de respuesta en File; el binario sigue hacia Drive, S3 o tu paso de video.
Make y Zapier
En Make, el módulo Make a request de la app HTTP manda el POST con la cabecera Authorization. En Zapier, Webhooks by Zapier hace lo mismo con una acción POST o Custom Request. En los dos, la espera más limpia es un segundo escenario o Zap que arranca desde un webhook propio (custom webhook en Make, Catch Hook en Zapier): pasa esa dirección como webhook_url y, cuando llegue el aviso, consulta GET /tts/{id} y descarga audio_url con tu clave.
Errores y buenas prácticas en producción
Todos los errores tienen la misma forma, { error: { code, message } }. Programa contra code, que es estable, nunca contra message, que es texto para personas y puede cambiar.
- Manda una Idempotency-Key en cada POST /tts (el id de tu video o de tu fila sirve). Si un error de red te obliga a reintentar, recibes el mismo trabajo con un 200 y no se cobra dos veces.
- Guarda el job_id en cuanto lo recibas. Si tu proceso se cae, GET /tts lista tus trabajos recientes con un cursor, y puedes filtrar con ?status=done.
- Consulta cada pocos segundos, o espera lo que diga eta_seconds, en vez de preguntar sin pausa.
- Descarga y guarda tu copia: el MP3 se conserva 4 días y después se borra el archivo.
- ¿Te has equivocado? DELETE /tts/{id} cancela un trabajo que sigue en cola y lo devuelve entero. Si ya se está generando, no se puede cancelar. Si un trabajo acaba en error, sus créditos se devuelven solos.
- No llames nunca a la API desde el navegador o desde una app móvil: cualquiera vería la clave. Llámala desde tu servidor y que tu web hable con tu servidor.
- Cambia la clave si sospechas que se ha filtrado. Al generar una nueva, la anterior queda revocada al momento, así que actualiza la variable de entorno justo después.
| code | HTTP | Qué hacer |
|---|---|---|
| no_autorizado | 401 | Falta la clave, es incorrecta o está revocada |
| saldo_insuficiente | 402 | No hay créditos comprados suficientes; la respuesta dice cuántos hacen falta |
| voz_no_encontrada | 404 | Ese voice_id no está en tu biblioteca: añádelo primero |
| texto_demasiado_largo | 400 | Pasa de 600.000 caracteres: pártelo |
| limite_peticiones | 429 | Espera los segundos de Retry-After y reintenta |
| demasiados_en_cola | 429 | Demasiados trabajos en curso: deja que terminen algunos |
| servicio_no_disponible | 503 | Reintenta más tarde, espaciando los intentos |
¿Cuánto cuesta una API de texto a voz?
La API gasta los mismos créditos que la web: 60 créditos por cada 1.000 caracteres (unos 60 por minuto de audio), con un mínimo de 100 por petición. Una narración de 10 minutos para YouTube son unos 9850 caracteres, es decir, 591 créditos. Funciona solo con créditos comprados, que no caducan y no van con suscripción; los créditos gratis del mes que da la cuenta de Google son solo para el generador web.
Debajo, lo que cuesta un minuto de audio con el plan más barato de cada servicio, según lo publicado en septiembre de 2026. Voizum aparece con el pack Máxi, el de mejor precio por crédito. Todo en euros para poder comparar.
| Servicio | Por minuto de audio (plan de entrada) | API incluida en ese plan | Créditos sin usar |
|---|---|---|---|
| Voizum | 0,013 € | Sí | No caducan |
| MiniMax | 0,043 € | No, se paga aparte | Caducan a los 2 meses |
| Fish Audio | 0,067 € | No, se paga aparte | Se pierden cada mes |
| ElevenLabs | 0,171 € | Sí | Se pierden al cancelar |
| Narakeet | 0,173 € | Sí | No caducan |
| TTSMaker | 0,040 € | No, se paga aparte | Se pierden cada mes |
¿Y si no quieres escribir código?
Si lo que quieres es generar audio mientras hablas con Claude o ChatGPT, no necesitas la API: el conector de Voizum le da al asistente herramientas para generar y listar voces, entra con tu cuenta y sigue las reglas de la web, créditos gratis del mes incluidos. Se configura en un par de minutos desde la página Conectar.
Y si solo necesitas que una página lea un texto en voz alta en el navegador de quien la visita, te basta la Web Speech API que traen los navegadores. Es gratis, pero suena robótica, cambia de un dispositivo a otro y no te da ningún archivo. Una API de texto a voz merece la pena cuando necesitas una voz natural en un MP3 que puedas publicar.
Fuentes consultadas
- Documentación de n8n: nodo HTTP Request
- Documentación de n8n: credenciales de HTTP Request (Header Auth)
- Documentación para desarrolladores de Make: hacer peticiones
- Ayuda de Zapier: enviar webhooks en un Zap
- Borrador del IETF: la cabecera HTTP Idempotency-Key
- MDN: cabecera Retry-After (en inglés)
- MDN: Web Speech API
- OWASP: guía de gestión de secretos