API de texto a voz: tus voces, desde tu código
Una API REST sencilla: mandas un texto y una de tus voces, y recibes el MP3. Cobra los mismos créditos que la web, sin cuota de desarrollador ni coste por llamada.
- URL base
- https://voizum.com/api/v1
- Autenticación
- Bearer sk_voizum_…
- Salida
- MP3
- Idiomas
- es · en · de · fr · pt · it · ru
- Precio
- 60 créditos / 1.000 caracteres (mín. 100)
Para asistentes de IA y herramientas
Tres puertas, según quién se conecte. Todas llevan a lo mismo: tus voces y tus créditos.
- Claude, ChatGPT, Cursor… sin programar
- El conector MCP: añádelo al asistente y pídele audios en el chat.
- https://voizum.com/mcp
- ChatGPT Actions, Postman, generadores de clientes
- Importa la especificación OpenAPI 3.1: describe todos los endpoints y sus campos.
- https://voizum.com/openapi.json
- Agentes que leen documentación
- llms.txt: el contrato entero en texto plano, pensado para modelos de lenguaje.
- https://voizum.com/llms.txt
Empieza en tres pasos
- Crea tu cuenta y tu clave en la sección API de la web. La clave empieza por sk_voizum_ y se enseña una sola vez: guárdala como un secreto, nunca en el código del navegador.
- Elige una voz: clona la tuya o añade a «Mis voces» una de la biblioteca. GET /voices te da su id.
- Crea el audio con POST /tts, consulta su estado cada pocos segundos y descárgalo cuando esté listo (o recibe un webhook).
Un ejemplo completo
Crear, esperar y descargar. La API es asíncrona: un audio largo tarda en generarse y así no hay que tener la conexión abierta.
curl
# 1. Crear el audio
curl -X POST https://voizum.com/api/v1/tts \
-H "Authorization: Bearer $VOIZUM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"text": "Hola, esto es Voizum.", "voice_id": "VOICE_ID"}'
# → {"job_id": "…", "status": "queued", "credits_charged": 100, "eta_seconds": 20}
# 2. Consultar el estado (hasta "done")
curl https://voizum.com/api/v1/tts/JOB_ID -H "Authorization: Bearer $VOIZUM_API_KEY"
# 3. Descargar el MP3
curl -L -o audio.mp3 "https://voizum.com/api/v1/tts/JOB_ID/audio?download=1" -H "Authorization: Bearer $VOIZUM_API_KEY"Python
import os, time, requests
API = "https://voizum.com/api/v1"
H = {"Authorization": f"Bearer {os.environ['VOIZUM_API_KEY']}"}
job = requests.post(f"{API}/tts", headers=H, json={"text": "Hola, esto es Voizum.", "voice_id": "VOICE_ID"}).json()
while True:
estado = requests.get(f"{API}/tts/{job['job_id']}", headers=H).json()
if estado["status"] in ("done", "error", "canceled"):
break
time.sleep(3)
if estado["status"] == "done":
mp3 = requests.get(f"{API}/tts/{job['job_id']}/audio?download=1", headers=H)
open("audio.mp3", "wb").write(mp3.content)JavaScript (Node 18+)
const API = "https://voizum.com/api/v1";
const H = { Authorization: `Bearer ${process.env.VOIZUM_API_KEY}`, "Content-Type": "application/json" };
const job = await (await fetch(`${API}/tts`, {
method: "POST", headers: H,
body: JSON.stringify({ text: "Hola, esto es Voizum.", voice_id: "VOICE_ID" }),
})).json();
let estado;
do {
await new Promise((r) => setTimeout(r, 3000));
estado = await (await fetch(`${API}/tts/${job.job_id}`, { headers: H })).json();
} while (!["done", "error", "canceled"].includes(estado.status));
if (estado.status === "done") {
const mp3 = await fetch(`${API}/tts/${job.job_id}/audio?download=1`, { headers: H });
await (await import("node:fs/promises")).writeFile("audio.mp3", Buffer.from(await mp3.arrayBuffer()));
}Endpoints
| Método y ruta | Qué hace |
|---|---|
| GET /status | Salud del servicio. Sin clave. |
| GET /account | Tu saldo de créditos y el precio por caracteres. |
| GET /voices | Las voces de tu biblioteca: su id es el voice_id. |
| POST /tts | Crea un audio a partir de un texto. |
| GET /tts/{job_id} | Estado del audio: queued, processing, done, error o canceled. |
| GET /tts/{job_id}/audio | El MP3 terminado (redirige al fichero; ?download=1 para descargar). |
| DELETE /tts/{job_id} | Cancela un audio que aún no ha empezado: se devuelven sus créditos. |
| GET /tts | Tus últimos audios, paginados. |
| POST /tts/batch | Varios audios separados en una petición, con un solo mínimo (de 2 a 100). |
| POST /tts/dialogue | Un audio con varias voces por turnos (hasta 5 voces). |
Qué acepta POST /tts
| Campo | Qué es |
|---|---|
| text | Obligatorio. El texto, hasta 600.000 caracteres. |
| voice_id | Obligatorio. Una voz de tu biblioteca (GET /voices). |
| speed | Opcional. Velocidad, de 0.5 a 2 (1 = el ritmo natural de la voz). |
| pause_ms | Opcional. Pausa entre frases, de 0 a 800 ms. |
| language | Opcional. auto, es, en, de, fr, pt, it, ru. Sin él, se deduce del texto. |
| loudness_normalization | Opcional. Iguala el volumen para que todas las voces suenen igual de fuerte. |
| webhook_url | Opcional. Una URL https pública a la que avisamos con un POST cuando el audio termina. |
| Idempotency-Key | Cabecera opcional. Si reintentas con la misma, recibes el mismo audio y no se cobra dos veces. |
Webhook
Con webhook_url no hace falta sondear: al terminar te mandamos un POST con el evento generation.finished (3 intentos, 10 s de espera cada uno). Si tu servidor contesta con un 4xx, no se reintenta.
El aviso no va firmado: tómalo como una señal para consultar GET /tts/{job_id} con tu clave, que es la fuente de verdad, y no como prueba de que el audio está listo.
{
"event": "generation.finished",
"id": "JOB_ID",
"status": "completed",
"voice_id": "VOICE_ID",
"duration_seconds": 12.4,
"credits": 100,
"error": null
}Límites
20 creaciones por minuto (POST /tts, /tts/batch y /tts/dialogue lo comparten) y 300 peticiones por minuto por clave en total. Las respuestas de crear traen X-RateLimit-Limit y X-RateLimit-Remaining, y todo 429 trae Retry-After con los segundos que hay que esperar.
El MP3 se guarda 4 días; después GET /tts/{job_id}/audio da 404, así que descárgalo y guárdalo tú.
Un audio admite hasta 600.000 caracteres. Un lote, de 2 a 100 audios y 1.200.000 caracteres en total. Un diálogo, hasta 100 turnos y 5 voces distintas.
Errores
Siempre con la misma forma: { "error": { "code", "message" } }, a veces con detalles (por ejemplo, cuántos créditos faltan).
| Código | HTTP | Qué pasa |
|---|---|---|
| no_autorizado | 401 | Falta la API key o no es válida. |
| parametros_invalidos | 400 | Faltan campos o tienen un valor no válido. |
| cuerpo_invalido | 400 | El cuerpo no es un JSON válido. |
| texto_demasiado_largo | 400 | El texto supera el máximo de caracteres. |
| lote_invalido | 400 | Un lote lleva entre 2 y 100 audios. |
| dialogo_invalido | 400 | Un diálogo lleva entre 2 y 100 turnos y hasta 5 voces. |
| webhook_invalido | 400 | La webhook_url no es https o no apunta a un servidor público. |
| voz_sin_muestra | 400 | Esa voz aún no se puede usar. |
| saldo_insuficiente | 402 | No tienes créditos suficientes (la respuesta dice cuántos hacen falta). |
| requiere_compra | 403 | Los lotes necesitan una cuenta que haya comprado créditos. |
| voz_no_encontrada | 404 | La voz no existe en tu biblioteca. |
| no_encontrado | 404 | No existe un job con ese id (o no es tuyo). |
| limite_peticiones | 429 | Demasiadas peticiones: espera lo que diga Retry-After. |
| demasiados_en_cola | 429 | Tienes demasiados trabajos en curso: espera a que terminen algunos. |
| mantenimiento | 503 | Pausa de mantenimiento: reintenta en un rato. |
| servicio_no_disponible | 503 | El servicio no está disponible ahora: reintenta. |
Preguntas
- ¿Hay SDK para Python o JavaScript?
- No hace falta: son unas pocas llamadas REST con JSON y funcionan con cualquier cliente HTTP (requests, fetch, curl). Si quieres un cliente generado, la especificación OpenAPI lo crea en tu lenguaje.
- ¿Hay streaming en tiempo real?
- No. La API es asíncrona: creas el audio, consultas su estado y descargas el MP3 terminado. Está pensada para narraciones, vídeos, cursos y contenido, no para conversación en directo.
- ¿Puedo usar las voces de la biblioteca?
- Sí: añádelas antes a «Mis voces» desde la web y aparecerán en GET /voices. Por la API solo se usan las voces de tu biblioteca.
- ¿Se puede clonar una voz por la API?
- No: se clona desde la web (subes la grabación una vez) y luego la usas por la API con su voice_id.
- ¿Cuánto cuesta?
- Lo mismo que en la web: 60 créditos por cada 1.000 caracteres, con un mínimo de 100 por petición. Sin cuota mensual ni coste por llamada. Si un audio falla, se devuelven sus créditos.
- ¿En qué formato sale el audio?
- MP3.
Escribe tu texto y escúchalo con voz real
La API gasta créditos de un pack (60 por cada 1.000 caracteres) y pide entrar con Google. Packs desde 5,99 €, sin suscripción.