Welcome to django-meta-whatsapp
A production-ready WhatsApp Cloud Platform engine tailored exclusively for Django. Build CRM flows, blast campaigns, and chat with users natively.
Unified Inbox
Chat with customers in real-time. Full multimedia support.
Campaigns
Send bulk templated messages and track delivery/read rates.
Contacts & Labels
Manage audiences with colored labels and CSV imports.
Webhooks
Plug-and-play secure webhooks for the WhatsApp Cloud API.
Installation
This package is built for modern Python environments and is best managed via uv.
# Using uv
uv add django-meta-whatsapp
# Or using pip
pip install django-meta-whatsapp
After installation, add the package to your INSTALLED_APPS in Django:
INSTALLED_APPS = [
# ...
"django_meta_whatsapp",
]
Mount the dashboard URLs in your project's urls.py:
from django.urls import path, include
urlpatterns = [
# ...
path("whatsapp/", include("django_meta_whatsapp.urls", namespace="django_meta_whatsapp")),
]
Configuration
Configure the package by adding the following variables to your settings.py file. You can obtain these from the Meta Developer Portal.
Required Settings
WHATSAPP_API_TOKEN = "EAA..."
WHATSAPP_PHONE_NUMBER_ID = "1234567890"
WHATSAPP_WEBHOOK_VERIFY_TOKEN = "your_secure_random_string"
Optional UI Overrides
WHATSAPP_DASHBOARD_NAME = "My Business CRM"
WHATSAPP_DASHBOARD_LOGO = "https://yourwebsite.com/logo.png"
Finally, run migrations to set up the database schemas:
python manage.py migrate
Webhooks Engine
The package automatically exposes a secure webhook endpoint to receive incoming messages, read receipts, and status updates from Meta.
In your Meta App Dashboard, set your Webhook URL to:
https://yourdomain.com/whatsapp/webhook/
And use the WHATSAPP_WEBHOOK_VERIFY_TOKEN you defined in settings.
When messages arrive, they are instantly recorded in the WhatsAppMessage database and surface in the real-time Unified Inbox.
Contacts & Labels
The Contacts module acts as a mini-CRM for your WhatsApp audience. You can create contacts manually or import them via CSV.
Label Management
Group your contacts using Labels. Labels support custom hexadecimal colors or Tailwind presets. You can create a label directly from the Contact creation form simply by typing it into the dropdown and pressing Enter.
- CSV Import: Include a
labelscolumn in your CSV (comma-separated). Missing labels are auto-created! - Filtering: Use the dashboard to filter your contacts by label to easily prepare targeted campaigns.
Unified Inbox
A beautiful, real-time interface designed specifically for support and sales agents.
- Conversation Threads: Messages are cleanly grouped by Contact.
- Read Receipts: See exactly when your messages are delivered and read.
- Labeling: Assign labels directly to specific conversation threads.
Campaigns & Templates
Marketing on WhatsApp requires pre-approved Templates. The platform seamlessly syncs with Meta to pull down your templates.
Syncing Templates
Navigate to the Templates tab in the dashboard and click "Sync from Meta". All approved templates will be instantly available for your campaigns.
Running a Campaign
Create a new Campaign, select a synced template, and attach an audience by selecting specific Contacts or a specific Label. The engine will dispatch the messages via API and update the Campaign's status to reflect Deliveries, Reads, and Bounces.
In-App Signups
Utilize Graph API v22+ In-App Signups to easily build an audience. Create a "Signup Link" in the dashboard.
Share the wa.me/.../signup/... deep link on your website. When users tap it, WhatsApp opens and asks them to opt-in. When they do, the webhook automatically creates a WhatsAppContact record and links it to the signup source.
Blocked Users Sync
Stop wasting API calls and getting flagged for spam. When a user blocks your business on WhatsApp, the webhook detects the blocked status and automatically updates the Contact record as `is_blocked = True`.
These users are automatically excluded from future Campaigns, keeping your account health in pristine condition.
Python Utility Functions
You can use the built-in django_meta_whatsapp.utils module to programmatically send messages from anywhere in your Django backend (e.g., in signals, Celery tasks, or custom views).
Send Text Message
Sends a plain text message to a user. Pass an optional WhatsAppAccount instance if using multi-account mode.
from django_meta_whatsapp.utils import send_text_message
response = send_text_message(
phone_number="919876543210",
text="Hello from Django!",
account=my_account_instance # optional
)
Send Location Pin
Sends a map location pin with an optional name and address.
from django_meta_whatsapp.utils import send_location_message
send_location_message(
phone_number="919876543210",
latitude=28.6139,
longitude=77.2090,
name="Our Store",
address="New Delhi, India"
)
Upload & Send Media
First upload the media to Meta's servers, then dispatch the media message.
from django_meta_whatsapp.utils import upload_media, send_media_message
# 1. Upload Media
with open("invoice.pdf", "rb") as f:
media_id = upload_media(f, mime_type="application/pdf")
# 2. Send Document
send_media_message(
phone_number="919876543210",
media_id=media_id,
media_type="document",
filename="invoice.pdf",
caption="Here is your requested invoice."
)
Send Template Message
Dispatch an approved WhatsApp template with dynamic variables and buttons using the build_template_components helper.
from django_meta_whatsapp.utils import send_template_message, build_template_components
# Build the dynamic variables (e.g. for {{1}} and {{2}} in the body)
components = build_template_components(
body_params=["Rahul", "Tomorrow 5 PM"]
)
send_template_message(
phone_number="919876543210",
template_name="appointment_reminder",
language_code="en",
components=components
)
Template Management
Programmatically interact with Meta to fetch, push, or delete your message templates.
from django_meta_whatsapp.utils import (
sync_templates_from_meta,
push_template_to_meta,
delete_template_from_meta
)
# Fetch all templates from Meta
templates = sync_templates_from_meta()
# Delete a template from Meta
response = delete_template_from_meta(template_name="holiday_sale")
Campaign Execution
Trigger marketing campaigns from code. You can run them synchronously, or asynchronously via Celery if configured.
from django_meta_whatsapp.utils import run_campaign, run_campaign_async
# Run a campaign synchronously
results = run_campaign(campaign_id=1)
print(f"Sent: {results['sent']}, Failed: {results['failed']}")
# Or trigger it via Celery (requires WHATSAPP_USE_CELERY = True)
run_campaign_async(campaign_id=2)
Block Users API
Block users at the API level so you don't receive webhooks from them or accidentally message them.
from django_meta_whatsapp.utils import block_users
# Block up to 1,000 phone numbers in a single call
block_users(phone_numbers=["919876543210", "1234567890"])
Dashboard UI Customization
You can customize the look and feel of the WhatsApp Dashboard directly from your settings.py. All of these settings are optional!
# Replace the text name in the sidebar (default: "WhatsApp")
META_WHATSAPP_DASHBOARD_NAME = "My Custom App"
# Change the Lucide icon used in the sidebar (default: "message-circle")
META_WHATSAPP_DASHBOARD_ICON = "building-2"
# Or, use a complete custom image logo instead of the icon
META_WHATSAPP_DASHBOARD_LOGO = "/static/logo.png"
# Change the primary accent color of the entire dashboard! (Provide an HSL triplet)
META_WHATSAPP_ACCENT_COLOR = "142, 72%, 45%" # Emerald green
Multi-Account Support
Add accounts in the Settings → Accounts dashboard. Each account has its own:
- Access Token
- Phone Number ID
- WABA ID
- Verify Token
The webhook endpoint (/whatsapp/webhook/) auto-routes to the correct account by phone_number_id.
Pluggable Audience System
The package never assumes your user model. You control who receives campaigns by injecting your own logic.
Option 1: Named Audience Providers
Provide a function that returns a queryset of recipients.
# myapp/whatsapp_audiences.py
from myapp.models import Customer
def vip_customers():
return Customer.objects.filter(total_orders__gt=10)
# settings.py
WHATSAPP = {
"PHONE_FIELD": "mobile", # field on your model that holds the phone number
"NAME_FIELD": "full_name", # field for the display name
"AUDIENCES": {
"VIP Customers": "myapp.whatsapp_audiences.vip_customers",
},
}
Option 2: Full Campaign Resolver
# settings.py
WHATSAPP = {
"CAMPAIGN_RESOLVER": "myapp.whatsapp_audiences.resolve_campaign",
}
# myapp.whatsapp_audiences.py
def resolve_campaign(campaign):
if campaign.audience_type == "vip":
qs = Customer.objects.filter(total_orders__gt=10)
return [{"phone": c.mobile, "name": c.full_name, "params": {}} for c in qs]
return []
REST API Endpoints
You can interact with the package using standard HTTP REST APIs. All endpoints require an X-API-Key header (generate these in the dashboard under Settings → API Keys).
Endpoints
- POST
/whatsapp/api/send-message/- Send text message - POST
/whatsapp/api/send-location/- Send location pin - POST
/whatsapp/api/send-template/- Send approved template - GET
/whatsapp/api/chats/- List recent conversations - GET
/whatsapp/api/campaigns/- List campaigns
Send Text (cURL)
curl -X POST http://yourdomain.com/whatsapp/api/send-message/ \
-H "X-API-Key: your-key" \
-H "Content-Type: application/json" \
-d '{"phone": "919876543210", "message": "Hello!"}'
Send Template (cURL)
curl -X POST http://yourdomain.com/whatsapp/api/send-template/ \
-H "X-API-Key: your-key" \
-H "Content-Type: application/json" \
-d '{
"phone": "919876543210",
"template_name": "order_confirmation",
"language": "en",
"body_params": ["Rakesh", "ORD-1234"]
}'
Django Signals
Hook into the WhatsApp lifecycle directly in your Django app.
from django.dispatch import receiver
from django_meta_whatsapp.signals import (
whatsapp_message_received,
whatsapp_message_sent,
whatsapp_campaign_completed,
)
@receiver(whatsapp_message_received)
def on_inbound(sender, message, **kwargs):
print(f"New message from {message.phone_number}: {message.message_body}")
@receiver(whatsapp_campaign_completed)
def on_campaign_done(sender, campaign, sent, failed, **kwargs):
print(f"Campaign '{campaign.name}' finished: {sent} sent, {failed} failed")
Management Commands
# Sync templates from Meta
python manage.py wa_sync_templates
# Sync for a specific account (if multi-account)
python manage.py wa_sync_templates --account-id 1
Models Reference
| Model | Purpose |
|---|---|
| WhatsAppAccount | Multi-account credentials |
| WhatsAppContact | Contact directory |
| WhatsAppConversation | Grouped chat threads |
| WhatsAppMessage | Individual messages (text, media, location, etc.) |
| WhatsAppTemplate | Meta-approved message templates |
| WhatsAppCampaign | Bulk send campaigns |
| WhatsAppCampaignRecipient | Per-recipient status tracking |
| WhatsAppMedia | Uploaded media library |
| WhatsAppWebhookLog | Raw webhook event logs |
| WhatsAppAPIKey | REST API authentication keys |
Environment Variables
If you prefer 12-factor app architecture, you can configure the package using environment variables instead of settings.py.
META_WA_ACCESS_TOKEN=EAAx...
META_WA_PHONE_NUMBER_ID=1234567890
META_WABA_ID=9876543210
META_WA_VERIFY_TOKEN=my_secret_verify_token