Install
openclaw skills install phone-voiceConnect ElevenLabs Agents to your OpenClaw via phone with Twilio. Includes caller ID auth, voice PIN security, call screening, memory injection, and cost tracking.
openclaw skills install phone-voiceTurn your OpenClaw into a phone-callable assistant with ElevenLabs Agents + Twilio.
What you get:
Phone → Twilio → ElevenLabs Agent → Your Bridge → Anthropic Claude → OpenClaw Tools
↓
Memory Context
(MEMORY.md, USER.md)
Flow:
Not needed for this skill — the bridge bypasses OpenClaw and calls Claude directly. This gives you more control over memory injection and cost tracking.
The bridge is a FastAPI server that:
/v1/chat/completions requests from ElevenLabsKey files:
server.py — FastAPI app with /v1/chat/completions endpointfred_prompt.py — System prompt builder (loads memory files).env — Secrets (API keys, tokens, whitelist)contacts.json — Caller whitelist for screeningPermanent, secure alternative to ngrok:
# Install cloudflared
brew install cloudflare/cloudflare/cloudflared
# Login and configure
cloudflared tunnel login
cloudflared tunnel create <tunnel-name>
# Run the tunnel
cloudflared tunnel --url http://localhost:8013 run <tunnel-name>
Add a CNAME in Cloudflare DNS:
voice.yourdomain.com → <tunnel-id>.cfargotunnel.com
Or use ngrok (temporary):
ngrok http 8013
https://voice.yourdomain.com/v1/chat/completionsAuthorization: Bearer <YOUR_BRIDGE_TOKEN># Step 1: Store your bridge auth token as a secret
curl -X POST https://api.elevenlabs.io/v1/convai/secrets \
-H "xi-api-key: YOUR_ELEVENLABS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "new",
"name": "bridge_auth_token",
"value": "YOUR_BRIDGE_AUTH_TOKEN"
}'
# Response: {"secret_id": "abc123..."}
# Step 2: Create the agent
curl -X POST https://api.elevenlabs.io/v1/convai/agents/create \
-H "xi-api-key: YOUR_ELEVENLABS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"conversation_config": {
"agent": {
"language": "en",
"prompt": {
"llm": "custom-llm",
"prompt": "You are a helpful voice assistant.",
"custom_llm": {
"url": "https://voice.yourdomain.com/v1/chat/completions",
"api_key": {"secret_id": "abc123..."}
}
}
}
}
}'
In ElevenLabs agent settings:
Done! Your bot now answers that phone number.
Recognizes whitelisted numbers automatically:
// contacts.json
{
"+12505551234": {
"name": "Alice",
"role": "family"
}
}
For unknown callers or high-security actions:
VOICE_PIN = "banana" # Set in .env
Caller must say the PIN to proceed.
Unknown numbers get a receptionist prompt:
"This is Fred's assistant. I can take a message or help with general questions."
Configurable per-hour limits:
RATE_LIMIT_PER_HOUR = 10
Prevents abuse and runaway costs.
The bridge auto-loads context before each call:
Files read:
MEMORY.md — Long-term facts about user, projects, preferencesUSER.md — User profile (name, location, timezone)Live data injection:
All injected into the system prompt before Claude sees the conversation.
Every call logs to memory/voice-calls/costs.jsonl:
{
"call_sid": "CA123...",
"timestamp": "2026-02-03T10:30:00",
"caller": "+12505551234",
"duration_sec": 45,
"total_cost_usd": 0.12,
"breakdown": {
"twilio": 0.02,
"elevenlabs": 0.08,
"anthropic": 0.02
}
}
Run analytics on the JSONL to track monthly spend.
Call your bot:
Outbound calling (optional):
curl -X POST https://voice.yourdomain.com/call/outbound \
-H "Authorization: Bearer <BRIDGE_TOKEN>" \
-d '{"to": "+12505551234", "message": "Reminder: dentist at 3pm"}'
Environment variables (.env):
ANTHROPIC_API_KEY=sk-ant-...
ELEVENLABS_API_KEY=sk_...
ELEVENLABS_AGENT_ID=agent_...
TWILIO_ACCOUNT_SID=AC...
TWILIO_AUTH_TOKEN=...
TWILIO_NUMBER=+1...
LLM_BRIDGE_TOKEN=<random-secure-token>
VOICE_PIN=<your-secret-word>
CLAWD_DIR=/path/to/clawd
Whitelist (contacts.json):
{
"+12505551234": {"name": "Alice", "role": "family"},
"+12505555678": {"name": "Bob", "role": "friend"}
}
Restrict calls to business hours:
# In server.py
OFFICE_HOURS = {
"enabled": True,
"timezone": "America/Vancouver",
"weekdays": {"start": "09:00", "end": "17:00"},
"weekends": False
}
Outside hours → voicemail prompt.
Test the bridge directly:
curl -X POST https://voice.yourdomain.com/v1/chat/completions \
-H "Authorization: Bearer <BRIDGE_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4",
"messages": [{"role": "user", "content": "Hello!"}],
"stream": false
}'
Check logs:
tail -f ~/clawd/memory/voice-calls/bridge.log
Verify Twilio webhook:
Per-minute breakdown:
Use rate limiting and call screening to control costs.
ElevenLabs official tutorial:
This skill (Phone Voice v2.0):
MIT — use freely, credit appreciated.
Built by Fred (@FredMolty) — running on OpenClaw since 2026.