A comprehensive Frappe v15 custom app that enables businesses to make and receive voice calls through WhatsApp Business API directly from their ERPNext CRM Lead forms.
- π WhatsApp Voice Calling: Make and receive calls via WhatsApp Business API
- π CRM Integration: Seamless integration with ERPNext Lead doctype
- ποΈ WebRTC Audio: Browser-based calling using WebRTC technology
- π Call Recording: Automatic recording of all calls with configurable retention
- β Permission Management: WhatsApp-compliant call permission system
- π° Cost Tracking: Automatic calculation and tracking of call costs
- π₯ Multi-Tenancy: Support for multiple companies with separate phone numbers
- π Call Analytics: Comprehensive call history and statistics
- π Real-time Notifications: Instant alerts for incoming calls
WhatsApp User β Meta WhatsApp Cloud API β Frappe App β Janus Media Server β Agent Browser (WebRTC)
- Frappe Backend (Python): Handles webhooks, call management, permissions
- Janus Gateway (Media Server): Bridges WhatsApp audio β Browser WebRTC
- Frontend (JavaScript): WebRTC client in Frappe UI
- Database: Frappe Doctypes for call records, numbers, permissions
- Frappe v15 or higher
- ERPNext installed
- Python 3.10+
- MariaDB/PostgreSQL
Quick Docker Installation (Development Only)
docker pull canyan/janus-gateway:latest
docker run -d \
--name janus-gateway \
-p 8088:8088 \
-p 8089:8089 \
-p 8188:8188 \
-p 8989:8989 \
-p 20000-20100:20000-20100/udp \
canyan/janus-gateway:latestVerify Installation
curl http://localhost:8088/janus/infoNote: Docker setup above is for local development only. Production requires proper NAT configuration with public IP.
- Meta Business Account
- WhatsApp Business API access
- Phone Number registered with Meta
- Access Token and Webhook Verify Token
# Navigate to your frappe-bench
cd ~/frappe-bench
# Get the app from repository
bench get-app https://github.com/your-username/whatsapp-calling.git
# Install on your site
bench --site [your-site-name] install-app whatsapp_calling
# Migrate database
bench --site [your-site-name] migrate
# Build assets
bench build --app whatsapp_calling
# Restart bench
bench restart-
Navigate to: Setup > WhatsApp Calling > WhatsApp Settings
-
Configure the following:
WhatsApp API Configuration:
- Default Access Token: Your Meta WhatsApp Business API token
- Webhook Verify Token: Token for webhook verification
Janus Media Server Configuration:
- Janus HTTP API URL:
http://localhost:8088/janus(dev) orhttps://janus.yourdomain.com/janus(prod) - Janus WebSocket URL:
ws://localhost:8188(dev) orwss://janus.yourdomain.com/janus-ws(prod) - Janus API Secret: (from your janus.jcfg file, optional)
NAT & WebRTC Configuration (Production):
- Janus Public IP Address: Your server's public IP (e.g.,
203.0.113.42) - Enable STUN Server: β (enabled by default)
- STUN Server:
stun.l.google.com(Meta recommended) - STUN Port:
19302 - Enable TURN Server: Only if needed for strict firewalls
Note: For production, proper NAT configuration is critical. See JANUS_PRODUCTION_SETUP.md.
Call Recording Settings:
- Enable Call Recording: β
- Recording Storage Path:
/recordings - Recording Format: Opus
- Retention Days: 90
- Click Save
-
Navigate to: WhatsApp Calling > WhatsApp Number > New
-
Fill in details:
- Phone Number:
+919876543210(E.164 format) - Display Name: Your Business Name
- Company: Select your company
- Status: Active
- Phone Number ID: (from Meta Business Manager)
- Access Token: (optional, uses default if blank)
- Click Save
- Go to Meta for Developers
- Select your app
- Navigate to WhatsApp > Configuration
- Add Webhook URL:
https://yoursite.com/api/method/whatsapp_calling.whatsapp_calling.api.webhook.whatsapp_webhook - Add Verify Token: (same as in WhatsApp Settings)
- Subscribe to field:
calls - Save
- Open a Lead record
- Ensure mobile number is filled
- Click "π > WhatsApp Call" button
- Confirm the call
- Allow microphone access when prompted
- Call will be initiated
- Open a Lead record
- Click "π > Request Call Permission"
- Customer receives WhatsApp template message
- Once customer grants permission, you can call
- When a call comes in, you'll see a popup notification
- Click "Answer" to accept the call
- Click "Decline" to reject
During an active call:
- Mute: Toggle microphone on/off
- End Call: Terminate the call
- Timer: Shows call duration
- Navigate to: WhatsApp Calling > WhatsApp Call
- Filter by Lead, Company, Date, etc.
- Click on a call to view details
- Play recordings (if enabled)
Complete Production Setup Guide: See JANUS_PRODUCTION_SETUP.md for:
- NAT configuration (
nat_1_1_mappingin janus.jcfg) - STUN server setup (Meta recommends Google STUN)
- Firewall rules and port configuration
- SSL/TLS certificates
- Systemd service setup
- Performance tuning
- TURN server setup (optional)
- Troubleshooting guide
Quick Production Checklist:
- β Set
nat_1_1_mappingto your public IP in janus.jcfg - β Start Janus with
-S stun.l.google.com:19302 - β Open firewall ports: TCP 8088, 8188 and UDP 10000-10200
- β Configure public IP in WhatsApp Settings > NAT & WebRTC Configuration
- β Enable SSL/TLS for production (HTTPS/WSS required)
- β Test WebRTC connection before going live
Create a template in Meta Business Manager:
Template Name: call_permission_request
Content:
Hello! We'd like to call you to discuss your inquiry.
Do you give us permission to call you on WhatsApp?
[Button: Voice Call Request]
The app includes automated tasks:
- Hourly: Cleanup old recordings, cleanup stale Janus rooms
- Daily: Check expired permissions, reset daily counters, send summary email
- Monthly: Reset monthly usage counters
Configure in hooks.py:
scheduler_events = {
"hourly": [
"whatsapp_calling.whatsapp_calling.tasks.cleanup_old_recordings",
"whatsapp_calling.whatsapp_calling.tasks.cleanup_stale_janus_rooms"
],
"daily": [
"whatsapp_calling.whatsapp_calling.tasks.check_expired_permissions",
"whatsapp_calling.whatsapp_calling.tasks.reset_daily_counters"
]
}whatsapp_calling/
βββ whatsapp_calling/
β βββ whatsapp_calling/
β β βββ doctype/
β β β βββ whatsapp_call/ # Call records
β β β βββ whatsapp_number/ # Business numbers
β β β βββ whatsapp_settings/ # Global settings
β β β βββ call_permission/ # Permission tracking
β β βββ api/
β β β βββ webhook.py # WhatsApp webhook handler
β β β βββ call_control.py # Call operations
β β β βββ permissions.py # Permission management
β β β βββ janus_client.py # Janus integration
β β βββ utils/
β β β βββ whatsapp_api.py # WhatsApp API wrapper
β β β βββ validators.py # Validation utilities
β β βββ tasks.py # Background jobs
β βββ public/
β β βββ js/
β β β βββ whatsapp_call_widget.js # WebRTC client
β β β βββ lead_call_button.js # CRM integration
β β βββ css/
β β βββ whatsapp_calling.css # Styling
β βββ hooks.py # App configuration
βββ requirements.txt
βββ setup.py
βββ README.md
WhatsApp requires explicit permission before making outbound calls:
- Permission Request Limits:
- 1 request per 24 hours
- 2 requests per 7 days
- Permission Validity: 7 days after grant
- Call Limits: 5 calls per 24 hours after permission granted
Configure in Frappe:
System Manager: Full access to all doctypes Sales User: Can make calls, view their company's calls
- Inbound Calls: Free
- Outbound Calls: ~$0.01 - $0.05 per minute (varies by country)
The app automatically calculates and tracks:
- Per-call costs
- Daily usage
- Monthly budgets
- Company-wise spending
Production NAT Issues (most common):
- β Symptoms: "Peer connection state: failed" or "No audio during call"
- β Solution: See JANUS_PRODUCTION_SETUP.md Section 9 (Troubleshooting)
Common causes:
nat_1_1_mappingnot set to public IP in janus.jcfg- Firewall blocking UDP ports (10000-10200)
- No STUN server configured
- Wrong public IP in WhatsApp Settings
Quick fix:
# 1. Verify Janus is running
curl http://localhost:8088/janus
# 2. Check browser console for ICE candidates
# Look for candidates with your public IP
# 3. Verify NAT configuration in janus.jcfg
grep nat_1_1_mapping /usr/share/janus/etc/janus/janus.jcfg
# 4. Check Janus logs
tail -f /var/log/janus.log | grep -i "dtls\|ice\|webrtc"# Check if Janus is running
curl http://localhost:8088/janus
# Check Janus logs
docker logs janus-gateway # if using Docker
tail -f /var/log/janus.log # if native install
# Verify ports are open
netstat -tulpn | grep 8088- Verify webhook URL is accessible publicly
- Check Meta webhook configuration
- Verify webhook verify token matches
- Check Frappe error logs:
bench --site [site] logs
- Verify WhatsApp template is approved in Meta
- Check template name matches exactly
- Verify business number is verified with Meta
- Check error logs for API errors
frappe.call({
method: 'whatsapp_calling.whatsapp_calling.api.call_control.make_call',
args: {
lead_name: 'LEAD-001',
mobile_number: '+919876543210'
}
})frappe.call({
method: 'whatsapp_calling.whatsapp_calling.api.call_control.answer_call',
args: {
call_id: 'wamid.xxxxx'
}
})frappe.call({
method: 'whatsapp_calling.whatsapp_calling.api.call_control.end_call',
args: {
call_id: 'wamid.xxxxx'
}
})frappe.call({
method: 'whatsapp_calling.whatsapp_calling.api.permissions.request_call_permission',
args: {
lead_name: 'LEAD-001',
mobile_number: '+919876543210'
}
})curl -X POST http://localhost:8088/janus \
-H "Content-Type: application/json" \
-d '{"janus": "create", "transaction": "test123"}'curl -X GET "https://yoursite.com/api/method/whatsapp_calling.whatsapp_calling.api.webhook.whatsapp_webhook?hub.mode=subscribe&hub.verify_token=YOUR_TOKEN&hub.challenge=test"curl -X POST "https://graph.facebook.com/v18.0/PHONE_NUMBER_ID/calls" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"to": "+919876543210", "type": "voice"}'Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch:
git checkout -b feature-name - Commit your changes:
git commit -am 'Add feature' - Push to the branch:
git push origin feature-name - Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
- Frappe Framework: https://frappeframework.com
- Janus Gateway: https://janus.conf.meetecho.com
- WhatsApp Business API: https://developers.facebook.com/docs/whatsapp
For issues and questions:
- GitHub Issues: Create an issue
- Email: support@example.com
- Documentation: Wiki
- β Basic calling from CRM Lead
- β Call recording
- β Permission management
- β Janus integration
- Call queue management
- IVR (Interactive Voice Response)
- Call transfers
- Conference calls
- SMS integration
- AI-powered call insights
- Automatic transcription
- Sentiment analysis
- Integration with other CRM modules
- Initial release
- Basic calling functionality
- CRM Lead integration
- Permission management
- Call recording
- Janus Gateway integration
Made with β€οΈ for the Frappe/ERPNext community