/webhooks/calls, que las
demás fuentes, con la cabecera X-Zelto-Provider: livekit para identificar las
llamadas como LiveKit.
Crear una clave
- Abre Configuración → Integraciones → LiveKit y haz clic en Crear clave de API.
- Asigna un nombre descriptivo, por ejemplo
livekit-prod-worker. - Copia la clave una sola vez. Zelto solo guarda su hash. Es la misma clave para toda la organización que utilizan la API REST y el servidor MCP.
Enviar una sesión
Guarda la clave comoZELTO_API_KEY en el entorno del worker. Al finalizar
cada sesión, envía su transcripción a https://ingest.zelto.ai/webhooks/calls
con el siguiente ejemplo. Instala aiohttp en el entorno del worker si aún
no está disponible.
Usa un identificador estable para el agente y un identificador único de sala o
sesión para cada llamada. Reutiliza el identificador de llamada al reintentar
una carga.
user, assistant, system y
tool. Todo es opcional salvo call.externalId y una referencia al agente.
También puedes enviar durationSeconds, recordingUrl, endedReason, cost y
un bloque customer.
Una carga correcta devuelve { "received": true }.
Declarar la versión que atendió la sesión
Llama aforward_to_zelto con la etiqueta y el prompt real capturados para esa
sesión. Por ejemplo, conserva agent_id="support-agent" para ambos despliegues
y usa agent_version="support-2026-09-a" o "support-2026-09-b". El parámetro
de Python se envía como version en el nivel superior de la carga.
Cambia la etiqueta al modificar el prompt o el pipeline, aunque el prompt
sea idéntico. Conserva la etiqueta original al reintentar o enviar después de
otro despliegue. No uses un ID de sala como versión ni cambies el ID del agente
con cada despliegue.
La primera llamada procesada crea la versión declarada. Cuando las llamadas de
ambas versiones estén visibles, podrás seleccionarlas para un experimento del
agente. La etiqueta no captura el pipeline completo. Consulta
Versiones de agentes para conocer las capturas, los
límites de la alternativa automática y los pasos de verificación.
Pasa version_config para incluir el contexto completo como versionConfig: LLM, STT, modelo/voz TTS, herramientas, flujos o ajustes propios. Debe ser un objeto JSON de hasta 64 KiB. También puedes registrarlo antes en Agentes → Versiones → Registrar versión o mediante POST /v1/agents/{id}/versions. Consulta el contrato de configuración.
Enviar invocaciones de herramientas
Si el agente invoca herramientas durante una sesión, envía cada llamada para que aparezca en la transcripción, se incluya en el análisis de IA y se registre como una traza de invocación de herramienta consultable. LiveKit guarda las herramientas ensession.history.items como
elementos function_call —la invocación con name, arguments y call_id— y
function_call_output —el resultado asociado al mismo call_id—. Convierte cada
function_call en un turno tool con un objeto toolCall y asócialo con su
resultado mediante call_id:
toolCall.name es obligatorio. arguments y result aceptan cualquier
valor JSON; si reciben una cadena JSON, Zelto la analiza. status puede ser
success, error o pending. El content del turno puede quedar vacío cuando
existe toolCall; Zelto utiliza el nombre de la herramienta como etiqueta.
Envía build_turns(session) como transcript.turns en la solicitud anterior.
Verificar la primera llamada
Envía una sesión y abre Conversaciones. Debería aparecer identificada como LiveKit en pocos segundos. Si no aparece, revisa la respuesta que recibió el worker:{ "received": true } indica que Zelto aceptó la carga y
una respuesta 4xx incluye el motivo del rechazo. Comprueba también que se envían
las cabeceras Authorization y X-Zelto-Provider: livekit. Consulta
Conectar un proveedor de voz.
Identificadores estables
agent.externalIdidentifica al agente. Zelto busca o crea un agente de LiveKit para cada valor distinto, así que utiliza un identificador estable por agente, no por sesión. Elagent.namede la primera sesión le asigna el nombre.call.externalId—el identificador de la sala o sesión— elimina duplicados. Si vuelves a enviar el mismo valor, Zelto actualiza la llamada existente con la transcripción o duración nuevas, o añade una grabación que faltaba, sin cobrar otra vez la llamada. Conserva también la misma referencia del agente. Envía la sesión cuando finalice y reenvía el cuerpo original completo si añades información.
Grabaciones y transcripciones
Este flujo envía la transcripción que el agente ya tiene. Adjunta una grabación agregandocall.recordingUrl al mismo cuerpo de la solicitud. El audio puede
proceder de egress o de tu propio
servicio de grabación, incluido un bucket de S3.
Grabación disponible al finalizar la llamada
Incluye la URL en tu solicitud habitual ahttps://ingest.zelto.ai/webhooks/calls, con los encabezados existentes
Authorization: Bearer $ZELTO_API_KEY, X-Zelto-Provider: livekit y
Content-Type: application/json. Por ejemplo, el objeto call dentro del
cuerpo completo de una sesión podría ser:
Grabación disponible más tarde
Envía la sesión como siempre al finalizar. Cuando termine la carga de la grabación, copia el cuerpo original completo, agrega la URL y vuelve a enviarlo al mismo endpoint con los mismos encabezados:call.externalId, la transcripción,
los metadatos y el contexto de la versión (version, systemPrompt y
versionConfig, si los enviaste). Mantén también los detalles originales de la
llamada: cliente, costo, duración y motivo de finalización. Un reenvío parcial
con solo la grabación puede borrar campos omitidos, como el costo o el motivo
de finalización. Guarda el cuerpo original si la notificación de grabación se
procesa en otro trabajo o proceso.
El reenvío adjunta la grabación a la misma conversación sin cobrar otra vez la
llamada. Esto añade una grabación que faltaba o reemplaza una URL del proveedor
que Zelto aún no ha capturado. Para recuperar una URL vencida o inaccesible,
reenvía el cuerpo original completo con una URL nueva que permita descargar el
audio. Reintentar después de que Zelto haya capturado la grabación conserva la
copia almacenada.
Una URL sin firma de un objeto privado de S3 no es suficiente: envía una URL GET
prefirmada. Las respuestas de acceso denegado o recurso no encontrado reciben
reintentos limitados; una URL cuya caducidad está confirmada requiere una URL
nueva. Zelto no puede renovar las URL firmadas por tu servicio de almacenamiento.
Reproducción y captura
Los usuarios pueden reproducir, pausar y desplazarse por la grabación en el reproductor de audio de la conversación. EnvíastartSeconds / endSeconds de
la transcripción relativos al inicio de la grabación para sincronizar la
reproducción; adjuntar audio no genera ni reemplaza las marcas de tiempo.
Zelto debe poder descargar la URL sin autenticación interactiva. También puedes
usar una URL prefirmada: envíala después de completar la carga y mantenla válida
hasta que termine la captura. Para archivos WAV, utiliza preferentemente un
tipo de contenido de audio como audio/wav. Las URL WAV servidas como
application/octet-stream también se capturan sin modificar los bytes del audio.
Zelto pone la captura en cola de forma asíncrona y vuelve a alojar la grabación
cuando está habilitado el almacenamiento de grabaciones de tu organización. Si
tu organización lo ha desactivado, la reproducción usa tu URL, que debe seguir
accesible y admitir rangos de bytes para desplazarse por el audio. Esta
integración no cambia esa configuración.
Una respuesta 200 con { "received": true } confirma la aceptación, no que
la captura haya terminado. Antes de enviar grabaciones de todas las llamadas,
verifica una en Conversaciones: debe seguir siendo una
sola conversación, conservar su transcripción y sus detalles, y permitir
reproducir y desplazarse por el audio. Si el almacenamiento está habilitado,
confirma con Zelto que la captura terminó antes de dejar que venza la URL de
origen.
Si solo tienes audio y no una transcripción, utiliza el flujo de carga de
archivos de la API REST; adjuntar
call.recordingUrl aquí no solicita una transcripción.
Estado de la conexión
La tarjeta de LiveKit muestra Activo cuando Zelto ha ingerido al menos una llamada de LiveKit. La página de detalles de cada agente indica cuándo llegó la última sesión, para que puedas comprobar si el worker sigue enviando datos.Transmitir trazas (OpenTelemetry)
El flujo anterior alimenta Conversaciones, la vista de transcripción y análisis de una llamada. Además, un agente de LiveKit puede transmitir trazas de OpenTelemetry a Trazas: el árbol de spans de cada llamada —LLM, TTS, STT, herramientas y spans propios— con latencia, tokens y costo. LiveKit instrumenta cada sesión automáticamente; solo debes registrar un exportador OTLP que apunte al endpoint de ingestión de Zelto. Crea una clave de ingestión de observabilidad de solo escritura en Configuración → Integraciones → Observabilidad o en Trazas → Conectar agente. Necesitas el rolowner o admin.
Registra el exportador al principio del entrypoint, antes de session.start().
El código debe ejecutarse, no basta con definirlo:
OTLPSpanExporter() utiliza las variables de entorno estándar de OpenTelemetry y
el SDK añade /v1/traces al endpoint:
pip install opentelemetry-exporter-otlp-proto-http. Este exportador HTTP de Python envía
http/protobuf: mantén ese protocolo. Zelto también acepta JSON OTLP de
exportadores compatibles. No se admite gRPC en
:4317. Este flujo es independiente del envío de transcripciones: las trazas
utilizan la clave de ingestión de solo escritura, no ZELTO_API_KEY, y no
necesitan la cabecera X-Zelto-Provider. Consulta Trazas para
entender qué contiene una traza y cómo leerla.
Usa ZELTO_AGENT_EXTERNAL_ID con el mismo valor estable que agent.externalId
en forward_to_zelto, y ctx.room.name como call.externalId. El ID externo
crea o reutiliza el agente de LiveKit aunque la traza llegue antes que la llamada.
La metadata añade la referencia de sesión a los spans de LiveKit. En tus propios
spans, envía también session.id. Si una sesión contiene varios agentes, pon
el ID externo en cada span en lugar de fijar uno compartido en el recurso.
Consulta Enviar trazas para probar la entrega,
configurar logs y diagnosticar errores, y la documentación de LiveKit
para su integración con OpenTelemetry.
Contenido relacionado
- Trazas — el árbol de spans de OpenTelemetry de una llamada; configúralo en Transmitir trazas.
- Conectar un proveedor de voz — elige un método y verifica la ingestión.
- Proveedores personalizados y otros — el formato canónico de llamada que acepta el endpoint.
- Conversaciones — dónde aparecen las llamadas de LiveKit.
- Referencia de API · MCP — consulta tus datos mediante código.

