WAVoice 📞
Let people call your AI voice assistant on WhatsApp.
Connect your WhatsApp Business number to Retell AI, LiveKit, Gemini, or Dograh in under two minutes. No webhook configuration, no media servers, and no headaches with Meta's developer dashboard.
What is this?
If you built an AI voice agent on Retell, LiveKit, or Dograh, you probably want people to be able to call it.
Meta allows voice calling on WhatsApp Business numbers, but getting it connected to your agent is painful: you have to set up WebRTC servers, create public tunnels, register webhooks across multiple menus, and deal with dropped calls.
WAVoice does all of that for you with one command. It connects your WhatsApp number straight to your voice agent so you can test live calls on your phone right away.
Pick your platform
Choose the tool you are using and run the command in your terminal:
| Platform | Command | What it does |
|---|---|---|
| Retell AI | uvx wavoice retell start |
Connects your WhatsApp number to your Retell agent |
| LiveKit | uvx wavoice livekit dev |
Routes WhatsApp calls into a LiveKit voice room |
| Gemini (Built-in) | uvx wavoice init |
Answers calls with Google Gemini 2.0 Flash (no extra setup) |
| Dograh (No-code) | uvx wavoice dograh setup |
Connects your WhatsApp number to your Dograh visual agent |
(Don't have uv? You can also run pip install wavoice and use wavoice directly).
3-step quickstart
1. Have these 3 things ready from Meta
Head over to developers.facebook.com and make sure you have:
- A Meta Developer App with the WhatsApp product added.
- A System User Access Token (with
whatsapp_business_messagingandwhatsapp_business_managementpermissions). - A WhatsApp Business Phone Number (the free test number Meta gives you works fine).
2. Run the command
Pick your platform above and run it. The setup will ask for your Meta token and your platform's API key.
WAVoice automatically:
- Finds your WhatsApp phone number and account ID.
- Turns on WhatsApp Voice Calling for your number.
- Creates a secure connection tunnel so Meta can reach your computer.
- Sets up all required webhooks on Meta.
3. Call your number
Open WhatsApp on your phone, call your WhatsApp Business number, and speak directly to your AI agent!
Trouble? Run wavoice doctor
If a call is just ringing or nobody answers:
uvx wavoice doctor
This runs a quick health check on your setup and tells you exactly what is wrong (like an expired Meta token or a missing permission).
🔧 How it works under the hood (Technical Architecture)
WhatsApp calls do not work like standard phone calls or basic HTTP webhooks:
- When someone calls your number, Meta sends a WebRTC session request (SDP offer) over HTTPS.
- Audio is streamed back and forth via encrypted SRTP packets over UDP.
- Meta often sends duplicate webhooks at the same time, which can trigger multiple bot instances for the same call.
WhatsApp Caller (Mobile App)
│
▼ WebRTC (SDP offer / SRTP audio)
Meta Graph API Webhook
│
▼ Public Tunnel / Ingress
WAVoice
┌─────────┴─────────────────────────────────────────┐
│ • Decodes WebRTC audio stream │
│ • Prevents duplicate call triggers │
│ • Negotiates codecs & manages call state │
└─────────┬─────────────────────────────────────────┘
│
▼
Your AI Platform (Retell / LiveKit / Gemini / Custom Python)
What WAVoice automates:
- Auto-Discovery: Pulls your WABA ID and Phone Number ID directly from your token via the Graph API.
- Calling Activation: Automatically sets
calling.status = "ENABLED"on your phone number so the Call button appears in WhatsApp. - 3-Tier Webhook Sync: Registers Phone overrides, WABA subscriptions, and App subscriptions to ensure calls never get dropped.
- WebRTC Media Plumbing: Handles STUN/TURN traversal, SRTP decryption, and connects audio streams to your chosen provider.
- Call Claim Locks: Uses atomic in-memory claiming per
call_idso calls are answered exactly once.
🐍 Custom Python Pipelines (Pipecat / Deepgram / OpenAI / Cartesia)
If you are a Python developer building a custom pipeline with your own Speech-to-Text, LLM, and Text-to-Speech models, you can use WAVoice with Pipecat:
import os
from wavoice import WhatsAppVoiceApp
from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineParams, PipelineTask
from pipecat.processors.aggregators.llm_context import LLMContext
from pipecat.processors.aggregators.llm_response_universal import (
LLMContextAggregatorPair,
LLMUserAggregatorParams,
)
from pipecat.services.deepgram import DeepgramSTTService
from pipecat.services.openai import OpenAILLMService
from pipecat.services.cartesia import CartesiaTTSService
app = WhatsAppVoiceApp()
@app.on_call
async def handle_incoming_call(transport, call_info):
caller = getattr(call_info, "from_", "caller")
print(f"Incoming call from {caller}")
# Set up your models
stt = DeepgramSTTService(api_key=os.environ["DEEPGRAM_API_KEY"])
llm = OpenAILLMService(api_key=os.environ["OPENAI_API_KEY"], model="gpt-4o-mini")
tts = CartesiaTTSService(api_key=os.environ["CARTESIA_API_KEY"], voice_id="...")
# Set up conversation context
context = LLMContext([{"role": "system", "content": "You are a concise voice assistant."}])
user_agg, assistant_agg = LLMContextAggregatorPair(
context,
user_params=LLMUserAggregatorParams(vad_analyzer=SileroVADAnalyzer()),
)
# Wire the audio from WhatsApp into your pipeline
pipeline = Pipeline([
transport.input(), # WebRTC Audio In from WhatsApp
stt, # Speech-to-Text
user_agg, # Turn Aggregator
llm, # Large Language Model
tts, # Text-to-Speech
transport.output(), # WebRTC Audio Out to WhatsApp
assistant_agg,
])
task = PipelineTask(pipeline=pipeline, params=PipelineParams(allow_interruptions=True))
runner = PipelineRunner()
await runner.run(task)
if __name__ == "__main__":
app.run()
(See examples/custom_stt_llm_tts.py for the complete file).
🚀 Production Deployment & Permanent Domains
- Local testing: By default, WAVoice uses a temporary Cloudflare tunnel (
trycloudflare.com). This is meant for quick local testing and development. - Production (24/7): For live production traffic, host WAVoice on your server with a permanent domain (or behind Nginx / Caddy / Cloudflare) and pass your URL:
wavoice start --public-url https://voice.yourdomain.com # or wavoice livekit dev --public-url https://voice.yourdomain.com
- Dograh Cloud: If you use
wavoice dograh setup, calls route directly to Dograh's cloud infrastructure—no local process or tunnel is needed.
📋 CLI Command Reference
| Command | What it does |
|---|---|
wavoice init |
Complete setup wizard: prompts for credentials, turns on calling, and starts the Gemini voice agent. |
wavoice start |
Starts the local server and begins taking calls with the built-in Gemini agent. |
wavoice doctor |
Checks your Meta credentials, calling status, and webhook health. |
wavoice retell start |
Connects incoming WhatsApp calls directly to your Retell AI agent. |
wavoice retell doctor |
Checks your Retell API key and agent connection health. |
wavoice livekit setup |
Connects your WhatsApp number to LiveKit Cloud. |
wavoice livekit dev |
Runs the LiveKit webhook bridge and starts testing calls. |
wavoice livekit doctor |
Checks your LiveKit Cloud credentials and connection. |
wavoice dograh setup |
Connects WhatsApp directly to Dograh visual studio in the cloud. |
wavoice dograh doctor |
Checks your Dograh API key and telephony sync. |
🔒 Privacy & Telemetry
WAVoice collects anonymous usage statistics (command runs, answered call count, coarse country/timezone) to help improve the project. It never collects personal information, phone numbers, tokens, or audio data.
To disable telemetry, you can:
- Add
--no-telemetryto any command (e.g.,wavoice start --no-telemetry) - Set
WAVOICE_TELEMETRY=falsein your.envfile - Set
DO_NOT_TRACK=1in your system environment
Documentation by platform
Maintainer & License
Created by Amit Bhakt (@amitbhakt).
Released under the MIT License. Contributions and issues are welcome on GitHub.
Metadata
Release files for wavoice 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| wavoice-0.4.0.tar.gz | 47.3 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| wavoice-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 112.4 kB
Release files / wavoice-0.4.0.tar.gz
| Download URL | wavoice-0.4.0.tar.gz |
|---|---|
| Size | 47.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
258cfedfce32053b19524dced5de730a290970ef6befd4f9e7e839dd61379af3
|
|
BLAKE2b-256 checksum How to use checksums |
e7db19b883452426e517d2e0ef058782fd2f6f4ab9609c0bea47bec7c238f691
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / wavoice-0.4.0-py3-none-any.whl
| Download URL | wavoice-0.4.0-py3-none-any.whl |
|---|---|
| Size | 65.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3eaf8c1e3b8e40ee68bfe51d2f5aa7fd036f3f33afcf4d99bec4acf6f4a4c55d
|
|
BLAKE2b-256 checksum How to use checksums |
7b9b6e3e4e5596f45a6ce19d80ef7b43c93809033b5cbed16bdca1857a17e71a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for wavoice 0.4.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.