Documentation / Overview

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 labels column 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
WhatsAppAccountMulti-account credentials
WhatsAppContactContact directory
WhatsAppConversationGrouped chat threads
WhatsAppMessageIndividual messages (text, media, location, etc.)
WhatsAppTemplateMeta-approved message templates
WhatsAppCampaignBulk send campaigns
WhatsAppCampaignRecipientPer-recipient status tracking
WhatsAppMediaUploaded media library
WhatsAppWebhookLogRaw webhook event logs
WhatsAppAPIKeyREST 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

Developer & Author

Rahul Baberwal

Rahul Baberwal

Creator of django-meta-whatsapp. Passionate about building robust tools for developers.

Find this useful?

Support the project by leaving a star or forking it on GitHub!