Documentación← demo

API de voz

Una sola API para todo lo que suene: síntesis, clonado de voz, conversaciones en el navegador y llamadas telefónicas. Tus sistemas hablan con esta API; las credenciales de Fish Audio y Twilio no salen de aquí.

Autenticación

Todas las rutas menos /health requieren un token en la cabecera. Cada sistema tiene el suyo, así se puede revocar uno sin afectar a los demás.

curl https://voz.bibliolabtech.com/api/v1/tts \
  -H "Authorization: Bearer TU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"text":"Hola, esto es una prueba."}' \
  --output prueba.mp3

Sin token responde 401. Con token inválido, también: no distingue entre ambos casos a propósito.

Síntesis

Convierte texto en audio. Devuelve un mp3 directamente, no un enlace: se puede reproducir o guardar tal cual.

POST/api/v1/tts

Sintetiza texto y devuelve audio mp3.

Cuerpo
{
  "text": "[confident] Buenas, habla Pablo. [break] ¿Tienes cinco minutos?",
  "voiceId": "bed5a1875f2f4f39acad96f35af0e13f",   // opcional
  "speed": 1.15                                     // opcional, 0.5 a 2
}
Respuesta
audio/mpeg · 192 kbps
  • El texto admite etiquetas de dirección entre corchetes: [confident], [empathetic], [excited], [break], [long-break].
  • También acepta descripciones libres, como [energetic Colombian salesman]. El modelo entiende miles de ellas, no solo la lista documentada.
  • Escribe siempre con tildes: el modelo las usa para colocar el acento tónico. «genero» y «generó» no suenan igual.
  • Escribe las cifras como se pronuncian («un millón doscientos mil») para evitar lecturas raras.
  • Máximo 4000 caracteres por petición.

Voces

Catálogo y clonado. Un clon capta el timbre a partir de pocos segundos; la calidad depende casi por completo del material que le des.

GET/api/v1/voices?q=

Lista voces del catálogo. Sin `q` devuelve las de español.

Respuesta
{ "voices": [{ "id": "...", "title": "...", "languages": ["es"] }] }
POST/api/v1/voices

Clona una voz a partir de clips de audio (multipart/form-data).

Cuerpo
title=Pablo Financiero
clips=@nota1.ogg
clips=@nota2.ogg        # hasta 20 archivos
enhance=0               # 1 activa el realce de Fish
Respuesta
{ "voiceId": "bed5a187…", "clips": 6 }
  • Mínimo 10 segundos por clip; entre uno y dos minutos en total da mejor fidelidad.
  • El realce viene apagado a propósito: su reducción de ruido quita brillo a las consonantes, y medimos caídas de 10,4 % a 2,6 % de energía en la banda que hace inteligible el habla.
  • Elige los clips por brillo, no por duración. Una nota de WhatsApp larga suele ser peor que una corta bien grabada.
  • El clonado copia el timbre, no el acento. La prosodia la pone el modelo: para acento regional hay que dirigirlo con etiquetas en el texto.

Conversación en el navegador

Sesiones de voz en tiempo real. El servidor acuña un token efímero; la clave de Fish nunca llega al cliente.

POST/api/v1/sessions

Crea una sesión y devuelve el token de la sala.

Cuerpo
{
  "persona": "marina",          // o "closer": true
  "variables": {                 // reemplazan los {{placeholders}} del prompt
    "nombre": "Andrés",
    "producto_precio": "un millón doscientos mil pesos"
  }
}
Respuesta
{ "token": { "livekit_url": "wss://…", "token": "…", "expires_at": "…" } }
  • El navegador entrega ese token a `AgentSession.start({ sessionToken })` del SDK @fishaudio/agent-react.
  • El token caduca en minutos y la llamada tiene un tope de 10 minutos.
  • Hasta 50 variables por sesión. Una variable vacía deja el marcador «{{así}}» visible al modelo, que puede acabar leyéndolo en voz alta.

Llamadas telefónicas

Marca un número real y conecta la llamada con el agente a través del puente de audio.

POST/api/v1/calls

Lanza una llamada saliente.

Cuerpo
{
  "to": "+573001234567",
  "variables": { "nombre": "Andrés", "producto_precio": "novecientos mil pesos" }
}
Respuesta
{ "callSid": "CA…", "to": "+57…" }
  • El destino va en formato E.164, empezando por «+».
  • Cada país debe estar habilitado en los permisos geográficos de Twilio; si no, devuelve «not authorized to call».
  • Las variables viajan como parámetros del stream y llegan al agente antes de que la persona conteste.
  • Hasta 60 llamadas por hora y por token. Al pasarse responde 429 con la cabecera Retry-After.
GET/api/v1/calls?limit=30

Historial de llamadas con estado, duración y costo.

GET/api/v1/calls/:sid

Detalle de una llamada. Con un id «sess_…» devuelve la transcripción completa.

Servicio

Para monitorización externa.

GET/api/v1/health

Estado del servicio. No requiere token.

Respuesta
{ "ok": true, "fish": "ok", "agente": "…", "puente": "voz.bibliolabtech.com" }

Cómo está montado

tus sistemas ──> API de voz ──> Fish Audio (voz, agente)
                          └──> Twilio     (telefonía)

llamada telefónica:
  Twilio ──(mu-law 8 kHz por WebSocket)──> puente ──> sala del agente
         <──────────────────────────────         <──

El audio de las conversaciones nunca pasa por esta API: el navegador se conecta directo a la sala del agente, y en las llamadas es el puente quien habla con Twilio. Esta API es el plano de control — decide quién puede hacer qué, con qué voz y con qué guion— y por eso no añade latencia a la conversación.

Límites y costos

Síntesis

4000 caracteres por petición

Clonado

20 clips por voz, 10 s mínimo cada uno

Sesión de voz

10 minutos por conversación

Variables

50 por sesión

Llamadas por token

60 por hora

Demo pública

3 llamadas por hora e IP, solo a números verificados

Llamada a móvil colombiano

≈ $0.034 por minuto (Twilio)

Síntesis s2.1-pro

$15 por millón de bytes (≈12 h de audio)