API de Voz en Vivo
Qué es esto
Tres endpoints HTTP bajo /api/live que respaldan al agente de voz en vivo de ComStack. El navegador se autentica, abre una conexión WebSocket con el servicio de voz por IA y reenvía los eventos de llamada a herramientas a través del servidor. El servidor gestiona el aprovisionamiento de sesiones, el despacho de herramientas, la resolución de etiquetas multilingües y la transferencia de llamadas en vivo a un miembro del equipo.
URL base: https://api.comstack.ai
Autenticación
Los tres endpoints requieren los mismos dos encabezados:
| Encabezado | Valor |
|---|---|
Authorization | Bearer <Firebase ID Token> — obtenido mediante getIdToken() del usuario de Firebase autenticado |
x-project-id | El ID del documento de Firestore de tu proyecto |
Este modelo de autenticación es independiente de la autenticación por clave API de MCP utilizada por el endpoint /mcp.
Respuestas de error:
| Estado | Causa |
|---|---|
401 | Falta el encabezado Authorization o es inválido |
400 | Falta el encabezado x-project-id |
POST /api/live/session
Genera un token de sesión de voz efímero. Valida que el usuario sea miembro del proyecto, que el módulo de voz esté habilitado y que no se haya alcanzado la cuota diaria de sesiones.
Solicitud
No requiere cuerpo. Solo encabezados de autenticación.
Respuesta 200
{ "token": "projects/.../ephemeralTokens/...", "greeting": "Hi! How can I help you today?", "voice": "Aoede"}| Campo | Tipo | Descripción |
|---|---|---|
token | string | Token de sesión de voz efímero. Válido por 30 minutos; de un solo uso. |
greeting | string | Frase de apertura que el agente dirá al iniciar la sesión. Obtenida de la configuración del agente en vivo del proyecto. Cadena vacía si no está configurada. |
voice | string | Nombre de la voz obtenido de la configuración del proyecto. |
Condiciones de protección — 403
| Condición | Error |
|---|---|
| Módulo de voz deshabilitado | "Voice web agent not enabled for this project" |
| Usuario no aprovisionado | "This user has not been provisioned. Contact a manager." |
| Usuario no es miembro | "User is not a member of this project" |
Cuota de sesión — 429
El límite diario de sesiones se aplica de forma atómica antes de generar el token. Cuando el conteo diario por usuario alcanza el límite del plan, la llamada devuelve 429 y no se emite ningún token:
{ "error": "Daily live-session limit reached (5/day). Try again tomorrow or upgrade your plan." }El contador es por usuario y por día UTC. Los inicios de sesión concurrentes no pueden superar el límite; la reserva y la generación ocurren en una sola transacción. Consulta Planes y Cuotas para conocer los valores límite por plan.
POST /api/live/session/resume
Genera un nuevo token para reconectar tras una caída del WebSocket (GoAway, error 1007 o similar). Funcionalmente idéntico a POST /api/live/session.
Limpia el gestor de reanudación de la sesión antes de llamar a este endpoint para que el nuevo token inicie una sesión limpia en lugar de intentar reanudar la anterior.
POST /api/live/tools/execute
La IA de voz despacha llamadas a herramientas durante una sesión. El navegador recibe cada evento toolCall del WebSocket y lo reenvía a este endpoint. Todas las herramientas responden de forma síncrona.
Solicitud
{ "tool_name": "update_profile", "args": { "first_name": "María", "phone": "+34 611 22 33 44" }}| Campo | Requerido | Descripción |
|---|---|---|
tool_name | sí | Nombre de la herramienta a ejecutar. Conjunto estándar: update_profile, ask, answer, transfer_to_manager. Conjunto con acceso restringido (cuando el módulo de onboarding está habilitado): search_company, select_company, run_extraction, set_field, confirm. |
args | no | Argumentos de la herramienta. Por defecto {} si está ausente. |
Respuesta 200
{ "result": "Language changed to Spanish. Continue speaking in Spanish from now on.", "widget": { "type": "card", "card_id": "profile_card", "template_id": "profile_v1", "dir": "ltr", "data": { "first_name": "María", "last_name": null, "pronoun": "unspecified", "phone": "+34611223344", "contact_email": null, "language": "es-ES", "language_label": "Spanish" }, "labels": { "profile": "Perfil", "first_name": "Nombre", "pronoun": "Pronombre", "email": "Correo", "phone": "Teléfono", "language": "Idioma" }, "pronoun_labels": { "she_her": "Ella", "he_him": "Él", "they_them": "Elle", "unspecified": "No definido" } }}| Campo | Descripción |
|---|---|
result | Texto que el agente dirá en voz alta. Los resultados de cambio de idioma incluyen el nombre del nuevo idioma y una instrucción para continuar en él. |
widget | Carga útil de la tarjeta para renderizar en pantalla. Presente cuando una tarjeta de perfil debe aparecer o actualizarse. card_id: "profile_card" es estable; siempre se reemplaza en el mismo lugar. |
widget.dir | Dirección del texto: "ltr" o "rtl" para árabe, hebreo, farsi, urdu y otros idiomas RTL. |
widget.labels | Etiquetas traducidas resueltas por el servidor para los campos de la tarjeta. Utiliza inglés si no hay traducción en caché. |
widget.pronoun_labels | Valores de pronombres traducidos resueltos por el servidor. Utiliza inglés si no hay traducción. |
update_profile — manejo de campos
| Arg | Normalización |
|---|---|
first_name / last_name | Recortado; cadena vacía → null |
pronoun | Mapeo difuso; acepta formas naturales como "she", "he/him", "non-binary" |
phone | Analizado a formato E.164; país inferido de la configuración de idioma del usuario |
contact_email | Minúsculas y recortado; debe contener @ |
language | Comparado con el mapa de nombres de idiomas o validado directamente como BCP-47. Cuando el idioma cambia, se esperan los dos ámbitos de traducción críticos del widget antes de devolver la respuesta; los cambios posteriores al mismo idioma son aciertos de caché instantáneos. |
Llamar a update_profile sin argumentos devuelve el perfil actual sin escribir; se usa para mostrar la tarjeta de perfil bajo demanda.
transfer_to_manager
Conecta al interlocutor con un miembro humano del equipo:
- El interlocutor es colocado en una sala de conferencias privada en espera breve.
- El servidor inicia una llamada saliente al número de teléfono del gerente configurado en el proyecto.
- Una vez que el gerente responde, se une a la misma conferencia.
No requiere argumentos. El interlocutor pasa del sitio web a un miembro del equipo en segundos. Las llamadas salientes requieren permisos telefónicos habilitados para el país de destino.
Herramientas de onboarding (acceso restringido)
Disponibles solo en proyectos donde el módulo de onboarding está habilitado. Cada herramienta muta la sesión de onboarding activa del visitante.
| Herramienta | Args | Efecto |
|---|---|---|
search_company | country (ISO-3166-1 alpha-2), query | Búsqueda en registro comercial; devuelve hasta 5 candidatos. |
select_company | country, registry_id?, place_id?, business_url? | Almacena la identidad comercial seleccionada en la sesión. Limpia cualquier perfil extraído previamente si la identidad cambió. |
run_extraction | (ninguno) | Extracción completa sobre la empresa seleccionada. Escribe el perfil resultante en la sesión. |
set_field | path, value | Edición en línea en una ruta de campo de sesión permitida. Rutas permitidas: voice, greeting_draft, primary_language, brand_tone, service_area, opening_hours, summary, industry, target_audience, intent, languages, products_services, unique_selling_points. |
confirm | (ninguno) | Marca el resumen de onboarding como confirmado. |
Todas las herramientas devuelven { result: string } donde result es la frase natural que dice el agente.
Errores
| Estado | Causa |
|---|---|
400 | Falta tool_name en el cuerpo de la solicitud |
500 | El despacho de la herramienta lanzó un error inesperado |
Ubicación del agente en vivo
La ubicación del agente de voz en el sitio publicado se controla mediante el ajuste live_agent_placement en la configuración del sitio de tu proyecto:
PATCH /api/projects/:pid/settings/site{ "live_agent_placement": "widget"}| Valor | Ubicación |
|---|---|
homepage | Agente incrustado en la página de inicio |
destination_page | Agente servido en un slug dedicado (live_agent_slug) |
widget | Widget flotante en todas las páginas |
modal | Modal de pantalla completa |
none | Agente deshabilitado en el sitio |
En el modo destination_page, una página cuyo slug colisiona con live_agent_slug es rechazada al momento de crearla o actualizarla. El slug se desbloquea automáticamente cuando el modo de ubicación cambia fuera de destination_page.
Etiquetas del widget
El navegador no tiene mapas de traducción codificados. Todas las etiquetas de tarjetas y traducciones de pronombres se resuelven en el lado del servidor a partir de los datos de traducción del proyecto y se envían en la carga útil del widget. El navegador solo mantiene constantes de respaldo en inglés para respuestas heredadas.
Cuando un usuario cambia de idioma por primera vez, el servidor espera la traducción antes de responder (aproximadamente 1-2 segundos). Los cambios posteriores al mismo idioma regresan inmediatamente desde la caché.
Errores comunes
401 Unauthorized — el token de ID de Firebase ha expirado o es inválido. Vuelve a autenticar al usuario y llama a getIdToken() para obtener un token nuevo.
403 Voice web agent not enabled — el módulo de voz está deshabilitado en este proyecto. Revisa la configuración de módulos del proyecto o actualiza el plan.
403 User not provisioned — el usuario autenticado no ha sido añadido a este proyecto. Un gerente de proyecto debe aprovisionar la cuenta de usuario primero.
429 Daily live-session limit reached — la cuota diaria por usuario está agotada. El límite se restablece a la medianoche UTC. El mensaje de error incluye el valor del límite. Actualiza el plan para obtener una cuota mayor.
400 tool_name missing — el cuerpo de la solicitud /tools/execute no contiene el campo tool_name.
Relacionado
- Planes y Cuotas — límites de cuota de sesión y aplicación
- Resumen de la API — autenticación e índice de endpoints
- Sistema de Traducción — cómo funciona el contenido multilingüe