Ir al contenido

Configura llamadas de voz en OpenClaw: Guía rápida

¿Alguna vez has intentado integrar llamadas de voz en una aplicación y has terminado perdido entre documentación de webhooks y configuraciones de red imposibles? Todos hemos pasado por ese dolor de cabeza donde algo tan “simple” como hacer que el sistema hable por teléfono se convierte en un proyecto de semanas.

Con el plugin de Voice Call para OpenClaw, puedes gestionar notificaciones salientes y conversaciones multi-turno de forma directa. Actualmente soporta Twilio, Telnyx, Plivo y un modo mock para que hagas pruebas en local sin gastar ni un céntimo ni configurar redes.

El plugin Voice Call se ejecuta dentro del proceso del Gateway.

Si utilizas un Gateway remoto, debes instalar y configurar el plugin en la máquina que ejecuta el Gateway. Después, reinicia el Gateway para que cargue los cambios.

Ventana de terminal
openclaw plugins install @openclaw/voice-call

Reinicia el Gateway al terminar.

Opción B: instalar desde una carpeta local (desarrollo)

Sección titulada «Opción B: instalar desde una carpeta local (desarrollo)»
Ventana de terminal
PLUGIN_SRC=./path/to/local/voice-call-plugin
openclaw plugins install "$PLUGIN_SRC"
cd "$PLUGIN_SRC" && pnpm install

Reinicia el Gateway al terminar.

Define la configuración bajo plugins.entries.voice-call.config:

{
plugins: {
entries: {
"voice-call": {
enabled: true,
config: {
provider: "twilio", // or "telnyx" | "plivo" | "mock"
fromNumber: "+15550001234",
toNumber: "+15550005678",
twilio: {
accountSid: "ACxxxxxxxx",
authToken: "...",
},
telnyx: {
apiKey: "...",
connectionId: "...",
// Telnyx webhook public key from the Telnyx Mission Control Portal
// (Base64 string; can also be set via TELNYX_PUBLIC_KEY).
publicKey: "...",
},
plivo: {
authId: "MAxxxxxxxxxxxxxxxxxxxx",
authToken: "...",
},
// Webhook server
serve: {
port: 3334,
path: "/voice/webhook",
},
// Webhook security (recommended for tunnels/proxies)
webhookSecurity: {
allowedHosts: ["voice.example.com"],
trustedProxyIPs: ["100.64.0.1"],
},
// Public exposure (pick one)
// publicUrl: "https://example.ngrok.app/voice/webhook",
// tunnel: { provider: "ngrok" },
// tailscale: { mode: "funnel", path: "/voice/webhook" }
outbound: {
defaultMode: "notify", // notify | conversation
},
streaming: {
enabled: true,
streamPath: "/voice/stream",
preStartTimeoutMs: 5000,
maxPendingConnections: 32,
maxPendingConnectionsPerIp: 4,
maxConnections: 128,
},
},
},
},
},
}

Notas importantes:

  • Twilio, Telnyx y Plivo requieren una URL de webhook accesible públicamente.
  • mock es un proveedor para desarrollo local que no realiza llamadas de red.
  • Telnyx necesita telnyx.publicKey (o la variable TELNYX_PUBLIC_KEY) a menos que skipSignatureVerification sea true.
  • Si usas el plan gratuito de ngrok, configura publicUrl con la URL exacta; la verificación de firma es obligatoria.
  • Para producción, te recomiendo usar un dominio estable o Tailscale funnel en lugar de URLs temporales.
  • La seguridad del streaming incluye límites de conexiones por IP y tiempos de espera para proteger tu Gateway.

Limpieza de llamadas inactivas (Stale call reaper)

Sección titulada «Limpieza de llamadas inactivas (Stale call reaper)»

Usa staleCallReaperSeconds para finalizar llamadas que nunca reciben un webhook de terminación. Por defecto está en 0 (desactivado).

Configuraciones recomendadas:

  • Producción: entre 120 y 300 segundos para flujos de notificación.
  • Mantén este valor por encima de maxDurationSeconds para que las llamadas normales terminen correctamente. Un buen punto de partida es maxDurationSeconds + 30–60 segundos.

Ejemplo:

{
plugins: {
entries: {
"voice-call": {
config: {
maxDurationSeconds: 300,
staleCallReaperSeconds: 360,
},
},
},
},
}

Cuando usas un proxy o túnel frente al Gateway, el plugin reconstruye la URL pública para verificar la firma. Estas opciones controlan en qué cabeceras confiamos.

webhookSecurity.allowedHosts define una lista de hosts permitidos.

webhookSecurity.trustForwardingHeaders confía en las cabeceras reenviadas sin lista de permitidos.

webhookSecurity.trustedProxyIPs solo confía en las cabeceras si la IP remota coincide con la lista.

El plugin incluye protección contra ataques de replicación (replay protection) para Twilio y Plivo. Además, las peticiones de webhook no autenticadas se rechazan antes de leer el cuerpo si faltan las firmas requeridas.

Ejemplo con un host público estable:

{
plugins: {
entries: {
"voice-call": {
config: {
publicUrl: "https://voice.example.com/voice/webhook",
webhookSecurity: {
allowedHosts: ["voice.example.com"],
},
},
},
},
},
}

Voice Call utiliza la configuración messages.tts del núcleo para el streaming de voz. Puedes sobrescribirla dentro de la configuración del plugin y se fusionará (deep-merge) con la global.

{
tts: {
provider: "elevenlabs",
providers: {
elevenlabs: {
voiceId: "pMsXgVXv3BLzUgSXRplE",
modelId: "eleven_multilingual_v2",
},
},
},
}

Notas:

  • Ignora las voces de Microsoft para llamadas de voz, ya que la telefonía requiere PCM y el transporte actual de Microsoft no lo soporta.
  • Si el streaming de Twilio está activo, se usa el TTS del núcleo; de lo contrario, se vuelve a las voces nativas del proveedor.
  • Cuando el TTS falla y pasa a un proveedor secundario, verás un aviso en los logs con la cadena de intentos para facilitar el debugging.

Usar solo el TTS del núcleo (sin sobrescribir):

{
messages: {
tts: {
provider: "openai",
providers: {
openai: { voice: "alloy" },
},
},
},
}

Sobrescribir con ElevenLabs solo para llamadas:

{
plugins: {
entries: {
"voice-call": {
config: {
tts: {
provider: "elevenlabs",
providers: {
elevenlabs: {
apiKey: "elevenlabs_key",
voiceId: "pMsXgVXv3BLzUgSXRplE",
modelId: "eleven_multilingual_v2",
},
},
},
},
},
},
},
}

Sobrescribir solo el modelo de OpenAI para llamadas:

{
plugins: {
entries: {
"voice-call": {
config: {
tts: {
providers: {
openai: {
model: "gpt-4o-mini-tts",
voice: "marin",
},
},
},
},
},
},
},
}

Por defecto, la política de entrada está en disabled. Para activarla, configura lo siguiente:

{
inboundPolicy: "allowlist",
allowFrom: ["+15550001234"],
inboundGreeting: "Hello! How can I help?",
}

La política allowlist filtra por el ID del llamante. Ten en cuenta que esto es un filtrado básico y no una prueba de identidad fuerte. Las respuestas automáticas usan el sistema de agentes, que puedes ajustar con responseModel y responseTimeoutMs.

Para las respuestas automáticas, Voice Call añade una instrucción estricta al prompt del sistema:

  • {"spoken":"..."}

El plugin extrae el texto de forma defensiva, ignorando contenido de razonamiento o errores, y eliminando párrafos de planificación para que el usuario solo escuche lo que debe escuchar.

Comportamiento al inicio de la conversación

Sección titulada «Comportamiento al inicio de la conversación»

En llamadas salientes de tipo conversation, el manejo del primer mensaje depende del estado de reproducción:

  • Si el saludo inicial falla, la llamada vuelve a estado listening y reintenta el mensaje.
  • El streaming de Twilio comienza en cuanto se conecta el stream, sin retrasos extra.

Si un stream de Twilio se desconecta, Voice Call espera 2000ms antes de colgar:

  • Si el stream se reconecta en ese tiempo, se cancela el cierre.
  • Si no hay reconexión, la llamada termina para evitar sesiones fantasma activas.
Ventana de terminal
openclaw voicecall call --to "+15555550123" --message "Hello from OpenClaw"
openclaw voicecall start --to "+15555550123" # alias for call
openclaw voicecall continue --call-id <id> --message "Any questions?"
openclaw voicecall speak --call-id <id> --message "One moment"
openclaw voicecall end --call-id <id>
openclaw voicecall status --call-id <id>
openclaw voicecall tail
openclaw voicecall latency # summarize turn latency from logs
openclaw voicecall expose --mode funnel

El comando latency analiza el archivo calls.jsonl. Puedes usar --last <n> para limitar el análisis a los últimos registros. Obtendrás métricas p50/p90/p99 sobre la latencia de respuesta y tiempos de espera.

Nombre de la herramienta: voice_call

Acciones disponibles:

  • initiate_call (message, to?, mode?)
  • continue_call (callId, message)
  • speak_to_user (callId, message)
  • end_call (callId)
  • get_status (callId)

Puedes encontrar la documentación de la skill en skills/voice-call/SKILL.md.

  • voicecall.initiate (to?, message, mode?)
  • voicecall.continue (callId, message)
  • voicecall.speak (callId, message)
  • voicecall.end (callId)
  • voicecall.status (callId)

¿Necesitas ayuda para configurar tu proveedor de voz? Prueba nuestro AI Setup Assistant.

OpenClaw

OpenClaw Expert

Sigues atascado?

Si esta pagina no resolvio tu caso, pregunta a OpenClaw Expert para pasos concretos.