Caricamento in corso...
Caricamento in corso...
Last synced: Today, 22:00
Technical reference for the OpenClaw framework. Real-time synchronization with the official documentation engine.
Use this file to discover all available pages before exploring further.
Voice calls for OpenClaw via a plugin. Supports outbound notifications, multi-turn conversations, full-duplex realtime voice, streaming transcription, and inbound calls with allowlist policies.
Current providers:
twiliotelnyxplivomocktext<Tab title="From a local folder (dev)"> ```bash} PLUGIN_SRC=./path/to/local/voice-call-plugin openclaw plugins install "$PLUGIN_SRC" cd "$PLUGIN_SRC" && pnpm install ``` </Tab> </Tabs> If npm reports the OpenClaw-owned package as deprecated, that package version is from an older external package train; use a current packaged OpenClaw build or the local folder path until a newer npm package is published. Restart the Gateway afterwards so the plugin loads.
textThe default output is readable in chat logs and terminals. It checks plugin enablement, provider credentials, webhook exposure, and that only one audio mode (`streaming` or `realtime`) is active. Use `--json` for scripts.
textBoth are dry runs by default. Add `--yes` to actually place a short outbound notify call: ```bash} openclaw voicecall smoke --to "+15555550123" --yes ```
If
enabled: truejson5{ plugins: { entries: { "voice-call": { enabled: true, config: { provider: "twilio", // or "telnyx" | "plivo" | "mock" fromNumber: "+15550001234", // or TWILIO_FROM_NUMBER for Twilio toNumber: "+15550005678", twilio: { accountSid: "ACxxxxxxxx", authToken: "...", }, telnyx: { apiKey: "...", connectionId: "...", // Telnyx webhook public key from the Mission Control Portal // (Base64; 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 /* see Streaming transcription */ }, realtime: { enabled: false /* see Realtime voice */ }, }, }, }, }, }
realtimestreamingCurrent runtime behaviour:
realtime.enabledrealtime.providergoogleopenairealtime.providers.<providerId>openclaw_agent_consultrealtime.providerrealtime.toolPolicy| Policy | Behavior |
|---|---|
text safe-read-only | Expose the consult tool and limit the regular agent to text readtext web_searchtext web_fetchtext x_searchtext memory_searchtext memory_get |
text owner | Expose the consult tool and let the regular agent use the normal agent tool policy. |
text none | Do not expose the consult tool. Custom text realtime.tools |
text```json5} { plugins: { entries: { "voice-call": { config: { provider: "twilio", inboundPolicy: "allowlist", allowFrom: ["+15550005678"], realtime: { enabled: true, provider: "google", instructions: "Speak briefly. Call openclaw_agent_consult before using deeper tools.", toolPolicy: "safe-read-only", providers: { google: { apiKey: "${GEMINI_API_KEY}", model: "gemini-2.5-flash-native-audio-preview-12-2025", voice: "Kore", }, }, }, }, }, }, }, } ```
See Google provider and OpenAI provider for provider-specific realtime voice options.
streamingCurrent runtime behavior:
streaming.providerdeepgramelevenlabsmistralopenaixaistreaming.providers.<providerId>startstreaming.providertext```json5} { plugins: { entries: { "voice-call": { config: { streaming: { enabled: true, provider: "openai", streamPath: "/voice/stream", providers: { openai: { apiKey: "sk-...", // optional if OPENAI_API_KEY is set model: "gpt-4o-transcribe", silenceDurationMs: 800, vadThreshold: 0.5, }, }, }, }, }, }, }, } ```
text```json5} { plugins: { entries: { "voice-call": { config: { streaming: { enabled: true, provider: "xai", streamPath: "/voice/stream", providers: { xai: { apiKey: "${XAI_API_KEY}", // optional if XAI_API_KEY is set endpointingMs: 800, language: "en", }, }, }, }, }, }, }, } ```
Voice Call uses the core
messages.ttsmessages.ttsjson5{ tts: { provider: "elevenlabs", providers: { elevenlabs: { voiceId: "pMsXgVXv3BLzUgSXRplE", modelId: "eleven_multilingual_v2", }, }, }, }
Behavior notes:
tts.<provider>openaielevenlabsmicrosoftedgeopenclaw doctor --fixtts.providers.<provider><Say>fromtoattemptsInbound policy defaults to
disabledjson5{ inboundPolicy: "allowlist", allowFrom: ["+15550001234"], inboundGreeting: "Hello! How can I help?", }
Auto-responses use the agent system. Tune with
responseModelresponseSystemPromptresponseTimeoutMsFor auto-responses, Voice Call appends a strict spoken-output contract to the system prompt:
text{"spoken":"..."}
Voice Call extracts speech text defensively:
"spoken"This keeps spoken playback focused on caller-facing text and avoids leaking planning text into audio.
For outbound
conversationlistening<Say><Connect><Stream>When a Twilio media stream disconnects, Voice Call waits 2000 ms before auto-ending the call:
Use
staleCallReaperSeconds0Recommended ranges:
120300maxDurationSecondsmaxDurationSeconds + 30–60json5{ plugins: { entries: { "voice-call": { config: { maxDurationSeconds: 300, staleCallReaperSeconds: 360, }, }, }, }, }
When a proxy or tunnel sits in front of the Gateway, the plugin reconstructs the public URL for signature verification. These options control which forwarded headers are trusted:
Additional protections:
<Gather>Example with a stable public host:
json5{ plugins: { entries: { "voice-call": { config: { publicUrl: "https://voice.example.com/voice/webhook", webhookSecurity: { allowedHosts: ["voice.example.com"], }, }, }, }, }, }
bashopenclaw 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 dtmf --call-id <id> --digits "ww123456#" 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
When the Gateway is already running, operational
voicecalllatencycalls.jsonl--file <path>--last <n>Tool name:
voice_call| Action | Args |
|---|---|
text initiate_call | text messagetext to?text mode?text dtmfSequence? |
text continue_call | text callIdtext message |
text speak_to_user | text callIdtext message |
text send_dtmf | text callIdtext digits |
text end_call | text callId |
text get_status | text callId |
This repo ships a matching skill doc at
skills/voice-call/SKILL.md| Method | Args |
|---|---|
text voicecall.initiate | text to?text messagetext mode?text dtmfSequence? |
text voicecall.continue | text callIdtext message |
text voicecall.speak | text callIdtext message |
text voicecall.dtmf | text callIdtext digits |
text voicecall.end | text callId |
text voicecall.status | text callId |
dtmfSequencemode: "conversation"voicecall.dtmfRun setup from the same environment that runs the Gateway:
bashopenclaw voicecall setup openclaw voicecall setup --json
For
twiliotelnyxplivowebhook-exposurepublicUrllocalhost127.0.0.10.0.0.010.x172.16.x172.31.x192.168.x169.254.xfc00::/7fd00::/8publicUrlUse one public exposure path:
json5{ plugins: { entries: { "voice-call": { config: { publicUrl: "https://voice.example.com/voice/webhook", // or tunnel: { provider: "ngrok" }, // or tailscale: { mode: "funnel", path: "/voice/webhook" }, }, }, }, }, }
After changing config, restart or reload the Gateway, then run:
bashopenclaw voicecall setup openclaw voicecall smoke
voicecall smoke--yesCheck the selected provider and the required credential fields:
twilio.accountSidtwilio.authTokenfromNumberTWILIO_ACCOUNT_SIDTWILIO_AUTH_TOKENTWILIO_FROM_NUMBERtelnyx.apiKeytelnyx.connectionIdtelnyx.publicKeyfromNumberplivo.authIdplivo.authTokenfromNumberCredentials must exist on the Gateway host. Editing a local shell profile does not affect an already running Gateway until it restarts or reloads its environment.
Confirm the provider console points at the exact public webhook URL:
texthttps://voice.example.com/voice/webhook
Then inspect runtime state:
bashopenclaw voicecall status --call-id <id> openclaw voicecall tail openclaw logs --follow
Common causes:
publicUrlserve.pathWhen a reverse proxy or tunnel is in front of the Gateway, set
webhookSecurity.allowedHostswebhookSecurity.trustedProxyIPswebhookSecurity.trustForwardingHeadersProvider signatures are checked against the public URL OpenClaw reconstructs from the incoming request. If signatures fail:
publicUrlpublicUrlwebhookSecurity.allowedHostsskipSignatureVerificationGoogle Meet uses this plugin for Twilio dial-in joins. First verify Voice Call:
bashopenclaw voicecall setup openclaw voicecall smoke --to "+15555550123"
Then verify the Google Meet transport explicitly:
bashopenclaw googlemeet setup --transport twilio
If Voice Call is green but the Meet participant never joins, check the Meet dial-in number, PIN, and
--dtmf-sequenceGoogle Meet passes the Meet DTMF sequence and intro text to
voicecall.startUse
openclaw logs --followopenclaw voicecall tailConfirm only one audio mode is enabled.
realtime.enabledstreaming.enabledFor realtime Twilio calls, also verify:
realtime.provideropenclaw logs --follow© 2024 TaskFlow Mirror
Powered by TaskFlow Sync Engine