Voice Call (plugin)
Scope
Use this page when:
- You want to place an outbound voice call from Moltbot
- You are configuring or developing the voice-call plugin
Voice calls for Moltbot via a plugin. Supports outbound notifications and multi-turn conversations with inbound policies.
Current providers:
twilio(Programmable Voice + Media Streams)telnyx(Call Control v2)plivo(Voice API + XML transfer + GetInput speech)mock(dev/no network)
Quick mental model:
- Install plugin
- Restart Gateway
- Configure under
plugins.entries.voice-call.config - Use
moltbot voicecall ...or thevoice_calltool
Where it runs (local vs remote)
The Voice Call plugin runs inside the Gateway process.
If you use a remote Gateway, install/configure the plugin on the machine running the Gateway, then restart the Gateway to load it.
Install
Option A: install from npm (recommended)
moltbot plugins install @moltbot/voice-callRestart the Gateway afterwards.
Option B: install from a local folder (dev, no copying)
moltbot plugins install ./extensions/voice-call
cd ./extensions/voice-call && pnpm installRestart the Gateway afterwards.
Config
Set config under 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: "..."
},
plivo: {
authId: "MAxxxxxxxxxxxxxxxxxxxx",
authToken: "..."
},
// 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" // notify | conversation
},
streaming: {
enabled: true,
streamPath: "/voice/stream"
}
}
}
}
}
}Notes:
- Twilio/Telnyx require a publicly reachable webhook URL.
- Plivo requires a publicly reachable webhook URL.
mockis a local dev provider (no network calls).skipSignatureVerificationis for local testing only.
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 — it deep‑merges with messages.tts.
{
tts: {
provider: "elevenlabs",
elevenlabs: {
voiceId: "pMsXgVXv3BLzUgSXRplE",
modelId: "eleven_multilingual_v2"
}
}
}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.
More examples
Use core TTS only (no override):
{
messages: {
tts: {
provider: "openai",
openai: { voice: "alloy" }
}
}
}Override to ElevenLabs just for calls (keep core default elsewhere):
{
plugins: {
entries: {
"voice-call": {
config: {
tts: {
provider: "elevenlabs",
elevenlabs: {
apiKey: "elevenlabs_key",
voiceId: "pMsXgVXv3BLzUgSXRplE",
modelId: "eleven_multilingual_v2"
}
}
}
}
}
}
}Override only the OpenAI model for calls (deep‑merge example):
{
plugins: {
entries: {
"voice-call": {
config: {
tts: {
openai: {
model: "gpt-4o-mini-tts",
voice: "marin"
}
}
}
}
}
}
}Inbound calls
Inbound policy defaults to disabled. To enable inbound calls, set:
{
inboundPolicy: "allowlist",
allowFrom: ["+15550001234"],
inboundGreeting: "Hello! How can I help?"
}Auto-responses use the agent system. Tune with:
responseModelresponseSystemPromptresponseTimeoutMs
CLI
moltbot voicecall call --to "+15555550123" --message "Hello from Moltbot"
moltbot voicecall continue --call-id <id> --message "Any questions?"
moltbot voicecall speak --call-id <id> --message "One moment"
moltbot voicecall end --call-id <id>
moltbot voicecall status --call-id <id>
moltbot voicecall tail
moltbot voicecall expose --mode funnelAgent 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)
This repo ships a matching skill doc at skills/voice-call/SKILL.md.
Gateway RPC
voicecall.initiate(to?,message,mode?)voicecall.continue(callId,message)voicecall.speak(callId,message)voicecall.end(callId)voicecall.status(callId)