Documentation Index
Fetch the complete documentation index at: https://mintlify.com/rahul-baberwal/django-meta-whatsapp/llms.txt
Use this file to discover all available pages before exploring further.
django-meta-whatsapp defines four Django signals. Two are dispatched automatically by the built-in WebhookView; two are defined in the library but not dispatched by any built-in code — they are provided as hooks for you to fire from your own views or tasks. Connect to any of them in your app’s AppConfig.ready(). All signals are importable from django_meta_whatsapp.signals.
Import
from django_meta_whatsapp.signals import (
whatsapp_message_received,
whatsapp_message_sent,
whatsapp_campaign_completed,
whatsapp_user_subscribed,
)
whatsapp_message_received
Fired by: WebhookView._process() when an inbound message is ingested and saved.
kwargs:
| Name | Type | Description |
|---|
message | WhatsAppMessage | The newly created inbound message instance. |
from django.dispatch import receiver
from django_meta_whatsapp.signals import whatsapp_message_received
@receiver(whatsapp_message_received)
def on_message_received(sender, message, **kwargs):
# message.phone_number — who sent it
# message.message_body — text content (if text message)
# message.message_type — "text", "image", "document", etc.
# message.direction — always "inbound" here
print(f"New message from {message.phone_number}: {message.message_body}")
whatsapp_message_sent
Fired by: Not dispatched by any built-in library code. This signal is defined and exported so that your project can fire it from a custom outbound send view or Celery task after successfully calling send_text_message(), send_template_message(), or any other send util.
kwargs:
| Name | Type | Description |
|---|
message | WhatsAppMessage | The outbound message instance that was just sent. |
# Example: fire the signal yourself after saving an outbound message
from django_meta_whatsapp.signals import whatsapp_message_sent
from django_meta_whatsapp.models import WhatsAppMessage
msg = WhatsAppMessage.objects.create(
phone_number="919876543210",
direction="outbound",
message_type="text",
message_body="Hello!",
message_id=resp["messages"][0]["id"],
)
whatsapp_message_sent.send(sender=None, message=msg)
# Example: receive the signal in a handler
from django.dispatch import receiver
from django_meta_whatsapp.signals import whatsapp_message_sent
@receiver(whatsapp_message_sent)
def on_message_sent(sender, message, **kwargs):
print(f"Message {message.message_id} sent to {message.phone_number}")
whatsapp_campaign_completed
Fired by: Not dispatched by any built-in library code. run_campaign() and run_campaign_async() in utils.py do not emit this signal. Define a receiver and fire it yourself at the end of a custom campaign runner or Celery task if you need post-campaign hooks.
kwargs:
| Name | Type | Description |
|---|
campaign | WhatsAppCampaign | The completed campaign instance. |
sent | int | Number of messages successfully sent. |
failed | int | Number of messages that failed to send. |
# Example: fire the signal yourself after run_campaign() returns
from django_meta_whatsapp.signals import whatsapp_campaign_completed
from django_meta_whatsapp.utils import run_campaign
result = run_campaign(campaign.id, account=account)
whatsapp_campaign_completed.send(
sender=None,
campaign=campaign,
sent=result["sent"],
failed=result["failed"],
)
# Example: receive the signal in a handler
from django.dispatch import receiver
from django_meta_whatsapp.signals import whatsapp_campaign_completed
@receiver(whatsapp_campaign_completed)
def on_campaign_done(sender, campaign, sent, failed, **kwargs):
print(
f"Campaign '{campaign.name}' finished: "
f"{sent} sent, {failed} failed out of {campaign.total_count} total."
)
whatsapp_user_subscribed
Fired by: WebhookView._process() when a user subscribes through an In-App Signup link (in_app_signup webhook event).
kwargs:
| Name | Type | Description |
|---|
contact | WhatsAppContact | The contact record for the new subscriber (created or updated). |
signup | WhatsAppSignup | The signup link the user subscribed through. |
from django.dispatch import receiver
from django_meta_whatsapp.signals import whatsapp_user_subscribed
@receiver(whatsapp_user_subscribed)
def on_user_subscribed(sender, contact, signup, **kwargs):
# contact.phone — subscriber's phone number
# contact.name — subscriber's name (if available)
# signup.display_name — internal label for the signup link
# signup.promo_code — promo code attached to the link (if any)
print(
f"{contact.phone} subscribed via '{signup.display_name}' "
f"(promo: {signup.promo_code or 'none'})"
)
Connecting Receivers
The recommended pattern is to define all receiver functions in a handlers.py (or signals.py) module inside your app, then import it inside AppConfig.ready() to ensure the decorators are registered at startup.
from django.apps import AppConfig
class MyAppConfig(AppConfig):
name = "myapp"
def ready(self):
import myapp.handlers # noqa — triggers @receiver decorators
from django.dispatch import receiver
from django_meta_whatsapp.signals import (
whatsapp_message_received,
whatsapp_campaign_completed,
whatsapp_user_subscribed,
)
@receiver(whatsapp_message_received)
def handle_inbound(sender, message, **kwargs):
# Auto-reply to any inbound text message
if message.message_type == "text":
from django_meta_whatsapp.utils import send_text_message
send_text_message(
message.phone_number,
"Thanks for your message! We'll get back to you shortly.",
reply_message_id=message.message_id,
)
@receiver(whatsapp_campaign_completed)
def notify_on_campaign_complete(sender, campaign, sent, failed, **kwargs):
# Send an internal Slack/email notification, log to analytics, etc.
pass
@receiver(whatsapp_user_subscribed)
def welcome_new_subscriber(sender, contact, signup, **kwargs):
from django_meta_whatsapp.utils import send_template_message
send_template_message(
contact.phone,
"welcome_message",
language_code="en",
)
Signal handlers run synchronously inside the webhook request/response cycle. Keep receivers fast — avoid database-heavy queries, external HTTP calls, or file I/O directly inside a handler. Use Celery tasks (triggered from the handler) for any heavy processing.