Files
zeekayandHanzo Dev 06e4edb152 the CLI's docs links open docs.hanzo.bot, where the bot docs are published
docs.bot.ai does not resolve, so every Docs: line the CLI printed, and the doctor and migrate guide links, went nowhere. DOCS_ROOT and the literal links now point at https://docs.hanzo.bot/docs, which hanzo-docs/docs publishes from this repo's docs/. The docs search command still names the old Mintlify MCP tool; nothing serves an equivalent yet.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-24 21:12:08 -07:00
..
2026-08-29 18:13:28 -07:00

@hanzo/bot-voice-call

Official Voice Call plugin for Hanzo Bot.

Providers:

  • Twilio (Programmable Voice + Media Streams)
  • Telnyx (Call Control v2)
  • Plivo (Voice API + XML transfer + GetInput speech)
  • Mock (dev/no network)

Docs: https://docs.hanzo.ai/plugins/voice-call Plugin system: https://docs.hanzo.ai/plugin

Install (local dev)

hanzo-bot plugins install @hanzo/bot-voice-call

Restart the Gateway afterwards.

Option B: copy into your global extensions folder (dev)

mkdir -p ~/.hanzo-bot/extensions
cp -R extensions/voice-call ~/.hanzo-bot/extensions/voice-call
cd ~/.hanzo-bot/extensions/voice-call && pnpm install

Config

Put under plugins.entries.voice-call.config:

{
  provider: "twilio", // or "telnyx" | "plivo" | "mock"
  fromNumber: "+15550001234",
  toNumber: "+15550005678",

  twilio: {
    accountSid: "ACxxxxxxxx",
    authToken: "your_token",
  },

  telnyx: {
    apiKey: "KEYxxxx",
    connectionId: "CONNxxxx",
    // 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: "your_token",
  },

  // Webhook server
  serve: {
    port: 3334,
    path: "/voice/webhook",
  },

  // Public exposure (pick one):
  // publicUrl: "https://example.ngrok.app/voice/webhook",
  // tunnel: { provider: "ngrok" },
  // tailscale: { mode: "funnel", path: "/voice/webhook" }

  outbound: {
    defaultMode: "notify", // or "conversation"
  },

  streaming: {
    enabled: true,
    streamPath: "/voice/stream",
    preStartTimeoutMs: 5000,
    maxPendingConnections: 32,
    maxPendingConnectionsPerIp: 4,
    maxConnections: 128,
  },
}

Notes:

  • Twilio/Telnyx/Plivo require a publicly reachable webhook URL.
  • mock is a local dev provider (no network calls).
  • Telnyx requires telnyx.publicKey (or TELNYX_PUBLIC_KEY) unless skipSignatureVerification is true.
  • tunnel.allowNgrokFreeTierLoopbackBypass: true allows Twilio webhooks with invalid signatures only when tunnel.provider="ngrok" and serve.bind is loopback (ngrok local agent). Use for local dev only.

Streaming security defaults:

  • streaming.preStartTimeoutMs closes sockets that never send a valid start frame.
  • streaming.maxPendingConnections caps total unauthenticated pre-start sockets.
  • streaming.maxPendingConnectionsPerIp caps unauthenticated pre-start sockets per source IP.
  • streaming.maxConnections caps total open media stream sockets (pending + active).

Stale call reaper

Use staleCallReaperSeconds to end calls that never receive a terminal webhook (for example, notify-mode calls that never complete). The default is 0 (disabled).

Recommended ranges:

  • Production: 120–300 seconds for notify-style flows.
  • Keep this value higher than maxDurationSeconds so normal calls can finish. A good starting point is maxDurationSeconds + 30–60 seconds.

Example:

{
  staleCallReaperSeconds: 360,
}

TTS for calls

Voice Call uses the core messages.tts configuration (OpenAI or ElevenLabs) for streaming speech on calls. You can override it under the plugin config with the same shape — overrides deep-merge with messages.tts.

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

Notes:

  • Edge TTS is ignored for voice calls (telephony audio needs PCM; Edge output is unreliable).
  • Core TTS is used when Twilio media streaming is enabled; otherwise calls fall back to provider native voices.

CLI

hanzo-bot voicecall call --to "+15555550123" --message "Hello from Hanzo Bot"
hanzo-bot voicecall continue --call-id <id> --message "Any questions?"
hanzo-bot voicecall speak --call-id <id> --message "One moment"
hanzo-bot voicecall end --call-id <id>
hanzo-bot voicecall status --call-id <id>
hanzo-bot voicecall tail
hanzo-bot voicecall expose --mode funnel

Tool

Tool name: voice_call

Actions:

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

Gateway RPC

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

Notes

  • Uses webhook signature verification for Twilio/Telnyx/Plivo.
  • Adds replay protection for Twilio and Plivo webhooks (valid duplicate callbacks are ignored safely).
  • Twilio speech turns include a per-turn token so stale/replayed callbacks cannot complete a newer turn.
  • responseModel / responseSystemPrompt control AI auto-responses.
  • Media streaming requires ws and OpenAI Realtime API key.