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