# Voizum API v1 API REST para generar audio (texto a voz) desde tu aplicación. Autenticación por API key. Cobra los mismos créditos que la web. Es asíncrona: crea un job y consulta su estado. Base URL: https://voizum.com/api/v1 Documentación completa: https://voizum.com/docs Especificación OpenAPI 3.1 (para importar en ChatGPT Actions, Postman o un generador de clientes): https://voizum.com/openapi.json ## Conector MCP (Claude, ChatGPT, Cursor…) Voizum también se usa desde un asistente, sin escribir código: servidor MCP remoto en https://voizum.com/mcp (OAuth "Conectar con tu cuenta", o esta misma API key como Bearer). Herramientas: list_voices, generate_speech, get_speech, get_account. Pasos para conectarlo: https://voizum.com/conectar ## Autenticación Cabecera: Authorization: Bearer sk_voizum_... La clave se crea (y se ve una sola vez) en la web, en la sección API. ## Endpoints GET /status Salud del servicio. Público (sin key). -> { "status": "operational" } GET /account Saldo y parámetros de precio del usuario de la key. -> { "credits_remaining", "credits_per_1000_chars", "min_credits_per_request", "max_chars_per_request" } GET /voices Voces de TU biblioteca (solo las tuyas; las de la biblioteca publica de Voizum no salen hasta que las guardas en tu cuenta). -> { "voices": [ { "id", "name", "language" } ] } El "id" es lo que se manda como voice_id al generar. También se ve en la web: Voces -> menú ⋯ de la voz -> "ID para la API". ¿Lista vacía? La API NO usa las voces de la biblioteca pública: hay que añadirlas antes a "Mis voces" desde la web (botón Añadir), o clonar una propia. POST /tts Crea una generación. Cabecera opcional: Idempotency-Key (evita doble cobro en reintentos). Body JSON: { "text" (req), "voice_id" (req, de tu biblioteca), "speed" (0.5-2), "pause_ms" (0-800, pausa entre frases), "language" ("auto" | es | en | de | fr | pt | it | ru; sin él o con "auto" se deduce del texto), "webhook_url" (opcional, https público: te hacemos POST al terminar y no necesitas sondear; payload {event:"generation.finished", id, status: "completed"|"error", voice_id, duration_seconds, credits, error}; 3 intentos, timeout 10 s. El aviso NO va firmado: confirma el estado con GET /tts/{job_id} antes de fiarte de él) } -> 202 { "job_id", "status": "queued", "credits_charged", "eta_seconds" } Con Idempotency-Key repetida devuelve 200 y el MISMO job, sin volver a cobrar (la clave es por cuenta y NO compara el cuerpo: usa una clave nueva para cada audio distinto). Límite: 20 creaciones/min. La respuesta trae X-RateLimit-Limit y X-RateLimit-Remaining; el 429 trae además Retry-After (segundos). POST /tts/batch VARIOS AUDIOS DE UNA TIRADA, cada uno en su propio fichero. Pensado para cuando tienes que generar muchos textos cortos (avisos, frases de una app, capítulos). POR QUÉ USARLO: mandarlos uno a uno son N peticiones y N mínimos; aquí es UNA petición y UN SOLO mínimo para todo el lote. 8 avisos cortos: 800 créditos sueltos, 100 en lote. Límites: de 2 a 100 audios; cada texto hasta 600.000 caracteres (~10 h) y la SUMA del lote hasta 1.200.000 (~20 h). Son tres topes distintos porque miden cosas distintas: el fichero, el número de piezas y el conjunto. Body JSON: { "items" (req, de 2 a 100: [{ "text" (req), "voice_id" (opcional) }]), "voice_id" (voz para todos; puedes ponerla aquí, en cada item, o mezclar), "speed", "pause_ms", "language", "loudness_normalization" } -> 202 { "batch_id", "status": "queued", "credits_charged" (total del lote), "minimum_applied_once", "eta_seconds" (lo que falta para el lote ENTERO), "jobs": [ { "job_id", "position" (el orden del audio DENTRO del lote, 1..N), "credits_charged" } ] } Cada job se consulta y se descarga como cualquier otro: GET /tts/{job_id} y GET /tts/{job_id}/audio. Si uno falla, se le devuelven SUS créditos y los demás siguen. Ejemplo: curl -X POST https://voizum.com/api/v1/tts/batch \ -H "Authorization: Bearer sk_voizum_..." \ -H "Content-Type: application/json" \ -d '{"voice_id":"VOZ","items":[{"text":"Su pedido va en camino."}, {"text":"Su pedido ha llegado."}]}' POST /tts/dialogue UNA CONVERSACIÓN entre varias voces, en UN SOLO audio. Para pódcast, escenas, anuncios a dos voces o cualquier guion por turnos. DIFERENCIA CON /tts/batch, que es la duda típica: · batch -> N audios SEPARADOS (N ficheros, N job_id) · dialogue -> UN audio con las voces alternándose (1 fichero, 1 job_id) Los turnos salen en el ORDEN del array. Se cobra como un audio normal: por los caracteres de todo el guion, con UN mínimo (no uno por turno). Body JSON: { "turns" (req, de 2 a 100: [{ "voice_id" (req), "text" (req) }]), "speed", "pause_ms", "language", "loudness_normalization", "match_voice_levels" (por defecto true: iguala el volumen entre voces para que no parezcan grabaciones pegadas), "expressiveness" (0.8-1, por defecto 0.9) } Máximo 5 voces distintas y 100 turnos; el guion entero hasta 600.000 caracteres (~10 h), que es lo que cabe en un audio. -> 202 { "job_id", "status": "queued", "credits_charged", "turns", "voices", "eta_seconds" } Se sondea y se descarga como un audio normal: GET /tts/{job_id} y /tts/{job_id}/audio. Ejemplo: curl -X POST https://voizum.com/api/v1/tts/dialogue \ -H "Authorization: Bearer sk_voizum_..." \ -H "Content-Type: application/json" \ -d '{"turns":[{"voice_id":"ANA","text":"¿Sabes qué me sorprendió?"}, {"voice_id":"LUIS","text":"Ni idea. ¿El ruido?"}, {"voice_id":"ANA","text":"El silencio de madrugada."}]}' GET /tts Tus últimas generaciones, de la más nueva a la más vieja. Parámetros: limit (1-100, por defecto 20), cursor (el next_cursor de la respuesta anterior), status (filtro). -> { "jobs": [ { "job_id", "status", "credits_charged", "duration_seg", "voice_id", "created_at" } ], "next_cursor" } GET /tts/{job_id} Estado del job (solo el tuyo). -> { "job_id", "status", "credits_charged", "progress": { "parts_done", "parts_total", "percent" }, "created_at", "eta_seconds" (mientras no ha terminado: segundos estimados que faltan), "audio_url" y "duration_seg" (cuando status=done) } status: queued | processing | done | error | canceled DELETE /tts/{job_id} Cancela un job que AÚN NO HA EMPEZADO (status "queued"): se devuelven todos sus créditos. Una vez empezado (status "processing") ya no se puede: el audio ya se está generando. -> { "job_id", "status": "canceled" }. Si ya empezó o terminó: 400. GET /tts/{job_id}/audio Descarga/reproduce el MP3 (solo el tuyo). Redirige al fichero. ?download=1 para descargar. El MP3 se guarda 4 días: después da 404 (descárgalo y guárdalo tú). ## Límites 20 creaciones/min (POST /tts, /tts/batch y /tts/dialogue lo comparten) y 300 peticiones/min por clave en total. Las respuestas de crear traen X-RateLimit-Limit y X-RateLimit-Remaining; todo 429 trae Retry-After (segundos). ## Errores Forma: { "error": { "code", "message", ...detalles } } Códigos: 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.