Skip to main content

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 14 Django models that store all WhatsApp data locally. Import them from django_meta_whatsapp.models. All models are registered with Django Admin.

Import

from django_meta_whatsapp.models import (
    WhatsAppAccount,
    WhatsAppContact,
    WhatsAppConversation,
    WhatsAppMessage,
    WhatsAppTemplate,
    WhatsAppCampaign,
    WhatsAppCampaignRecipient,
    WhatsAppLabel,
    WhatsAppSignup,
    WhatsAppAPIKey,
    WhatsAppMedia,
    WhatsAppCatalogProduct,
    WhatsAppBlockedUser,
    WhatsAppWebhookLog,
)

WhatsAppAccount

Multi-account support: one row per WhatsApp Business Account. A single Django project can serve multiple businesses, each with their own credentials and phone number.

Fields

FieldTypeDescription
nameCharField(255)Friendly label, e.g. "My Business".
access_tokenTextFieldMeta permanent or system-user access token.
phone_number_idCharField(100)Meta phone number ID.
waba_idCharField(100)WhatsApp Business Account ID (required for templates, signups).
verify_tokenCharField(255)Webhook verification token — auto-generated UUID on creation.
profile_nameCharField(255)Business display name fetched via Graph API.
profile_picture_urlURLFieldProfile picture URL fetched via Graph API.
default_catalog_idCharField(255)Default Meta Commerce Catalog ID for this account.
is_activeBooleanFieldTrue if the account is enabled.
created_atDateTimeFieldAuto-set on creation.

Example

from django_meta_whatsapp.models import WhatsAppAccount

active_accounts = WhatsAppAccount.objects.filter(is_active=True)
account = WhatsAppAccount.objects.get(phone_number_id="1234567890")

WhatsAppContact

Stores every known WhatsApp contact — created automatically on first message or signup, or manually.

Fields

FieldTypeDescription
phoneCharField(30)Phone number, unique across the table.
nameCharField(255)Contact display name.
emailEmailFieldOptional email address.
labelsManyToManyField(WhatsAppLabel)Tags applied to this contact.
notesTextFieldInternal notes.
opted_outBooleanFieldTrue if the contact has opted out of marketing.
is_blockedBooleanFieldSynced from WhatsAppBlockedUser — for fast inbox UI filtering.
subscribed_via_signupForeignKey(WhatsAppSignup)The signup link that brought this contact in (nullable).
subscribed_atDateTimeFieldWhen the contact subscribed (nullable).
created_atDateTimeFieldAuto-set on creation.
updated_atDateTimeFieldAuto-set on every save.

Properties

PropertyReturnsDescription
display_namestrReturns name if set, otherwise falls back to phone.
normalized_phonestrReturns phone with any leading + stripped, for use in API calls.

Example

from django_meta_whatsapp.models import WhatsAppContact

# All reachable contacts
reachable = WhatsAppContact.objects.filter(opted_out=False, is_blocked=False)

# Look up by phone
contact = WhatsAppContact.objects.get(phone="+919876543210")
print(contact.display_name)       # "Rahul" or "+919876543210"
print(contact.normalized_phone)   # "919876543210"

WhatsAppConversation

One row per unique phone number that has had any interaction. Conversations are the top-level entity in the inbox — messages belong to a conversation.

Fields

FieldTypeDescription
accountForeignKey(WhatsAppAccount)The account this conversation belongs to (nullable).
contactForeignKey(WhatsAppContact)Linked contact record (nullable — may not exist for brand-new numbers).
phone_numberCharField(30)Fallback phone number when no contact record exists yet.
labelForeignKey(WhatsAppLabel)Optional label applied to the conversation.
is_resolvedBooleanFieldTrue if the conversation is marked resolved.
assigned_toCharField(255)Agent username or email assigned to this conversation.
last_message_atDateTimeFieldTimestamp of the most recent message.
unread_countPositiveIntegerFieldNumber of unread inbound messages.
created_atDateTimeFieldAuto-set on creation.
Default ordering: -last_message_at (most recent first).

Example

from django_meta_whatsapp.models import WhatsAppConversation

# Open, unresolved conversations
open_convs = WhatsAppConversation.objects.filter(is_resolved=False)

# All messages in a conversation
conv = WhatsAppConversation.objects.get(phone_number="+919876543210")
messages = conv.messages.order_by("timestamp")

WhatsAppMessage

Every message sent or received — both inbound from customers and outbound from your system.

Fields

FieldTypeDescription
conversationForeignKey(WhatsAppConversation)Parent conversation (nullable).
accountForeignKey(WhatsAppAccount)The account this message belongs to (nullable).
phone_numberCharField(30)The remote phone number.
message_idCharField(255)Meta WAMID (unique).
message_typeCharField(20)See message types table below.
message_bodyTextFieldText content of the message.
directionCharField(10)"inbound" or "outbound".
statusCharField(20)"sent", "delivered", "read", or "failed".
media_fileFileFieldLocally stored media file (whatsapp_media/).
media_idCharField(255)Meta media ID.
media_urlURLFieldMeta-hosted media URL.
media_mime_typeCharField(100)MIME type of the media.
media_filenameCharField(255)Original filename (for documents).
location_latitudeFloatFieldLatitude for location messages.
location_longitudeFloatFieldLongitude for location messages.
location_nameCharField(255)Location label for location messages.
location_addressTextFieldAddress text for location messages.
reaction_emojiCharField(10)Emoji for reaction messages.
reaction_to_message_idCharField(255)WAMID of the message being reacted to.
reply_toForeignKey("self")Self-referential FK for threaded replies.
timestampDateTimeFieldMessage timestamp (defaults to timezone.now).
is_deletedBooleanFieldTrue if the message was deleted/revoked.
raw_payloadJSONFieldFull webhook JSON payload for debugging.
Default ordering: timestamp (chronological).

Message Types

ValueDisplay
textText
imageImage
videoVideo
audioAudio
documentDocument
locationLocation
templateTemplate
reactionReaction
stickerSticker
interactiveInteractive
buttonButton
unknownUnknown

Properties

PropertyReturnsDescription
is_locationboolTrue if message_type == "location".
has_mediaboolTrue if message_type is one of image, video, audio, document, or sticker.

Example

from django_meta_whatsapp.models import WhatsAppMessage

# All unread inbound messages
inbound = WhatsAppMessage.objects.filter(direction="inbound", status="sent")

# Media messages from a specific number
media_msgs = WhatsAppMessage.objects.filter(
    phone_number="+919876543210",
    direction="inbound",
).exclude(media_id=None)

for msg in media_msgs:
    if msg.has_media:
        print(msg.media_filename, msg.media_url)

WhatsAppTemplate

Approved message templates, synced from Meta or pushed to Meta for approval.

Fields

FieldTypeDescription
accountForeignKey(WhatsAppAccount)The account this template belongs to (nullable).
nameCharField(512)Template name (must match Meta exactly).
meta_template_idCharField(255)Template ID assigned by Meta.
languageCharField(10)BCP-47 language code, default "en".
categoryCharField(30)"MARKETING", "UTILITY", or "AUTHENTICATION".
statusCharField(20)"APPROVED", "PENDING", "REJECTED", or "DRAFT".
headerJSONFieldHeader component (nullable). See format below.
body_textTextFieldBody text. Use {{1}}, {{2}} for variables.
footer_textCharField(255)Optional footer text.
buttonsJSONFieldList of button dicts. See format below.
created_atDateTimeFieldAuto-set on creation.
updated_atDateTimeFieldAuto-set on every save.
Unique constraint: (account, name, language) Default ordering: -created_at

JSON Field Formats

header:
{"type": "TEXT", "text": "Your order is ready"}
type can be "TEXT", "IMAGE", "VIDEO", or "DOCUMENT". buttons:
[
  {"type": "QUICK_REPLY", "text": "Yes"},
  {"type": "URL", "text": "Track Order", "url": "https://example.com/track/{{1}}"}
]

Example

from django_meta_whatsapp.models import WhatsAppTemplate

approved = WhatsAppTemplate.objects.filter(
    account=account,
    status="APPROVED",
    language="en",
)

WhatsAppCampaign

A bulk send job that sends a template message to a resolved audience.

Fields

FieldTypeDescription
accountForeignKey(WhatsAppAccount)Owning account (nullable).
nameCharField(255)Human-readable campaign name.
templateForeignKey(WhatsAppTemplate)The template to send.
audience_typeCharField(50)"contacts", "csv", or a custom key from WHATSAPP["AUDIENCES"].
audience_filtersJSONFieldExtra filter kwargs passed to the audience provider (e.g. {"labels__name": "VIP"}).
csv_fileFileFieldCSV file upload for audience_type="csv" (whatsapp_campaign_csv/).
parameter_mappingsJSONFieldMaps template variable positions to field names, e.g. {"1": "name", "2": "order_id"}.
statusCharField(20)See campaign statuses below.
scheduled_atDateTimeFieldWhen the campaign is scheduled to run (nullable).
started_atDateTimeFieldWhen run_campaign() began processing (nullable).
completed_atDateTimeFieldWhen run_campaign() finished (nullable).
total_countPositiveIntegerFieldTotal number of resolved recipients.
sent_countPositiveIntegerFieldSuccessfully sent count.
delivered_countPositiveIntegerFieldDelivered count (updated from webhooks).
read_countPositiveIntegerFieldRead count (updated from webhooks).
failed_countPositiveIntegerFieldFailed send count.
created_atDateTimeFieldAuto-set on creation.
updated_atDateTimeFieldAuto-set on every save.

Campaign Statuses

ValueMeaning
draftNot yet started.
scheduledQueued to run at scheduled_at.
runningCurrently sending.
completedAll sends attempted.
failedCampaign encountered a fatal error.
pausedManually paused mid-send.

Example

from django_meta_whatsapp.models import WhatsAppCampaign
from django_meta_whatsapp.utils import run_campaign_async

campaign = WhatsAppCampaign.objects.create(
    account=account,
    name="Summer Sale",
    template=template,
    audience_type="contacts",
    parameter_mappings={"1": "name"},
)
run_campaign_async(campaign.id)

WhatsAppCampaignRecipient

One row per recipient per campaign execution — tracks the per-message outcome.

Fields

FieldTypeDescription
campaignForeignKey(WhatsAppCampaign)Parent campaign.
phone_numberCharField(30)Recipient phone number.
nameCharField(255)Recipient name.
parametersJSONFieldResolved template variables for this recipient.
statusCharField(20)"pending", "sent", "delivered", "read", or "failed".
message_idCharField(255)Meta WAMID returned on send (nullable).
error_messageTextFieldError detail if status is "failed".
sent_atDateTimeFieldTimestamp when the message was sent (nullable).

Example

from django_meta_whatsapp.models import WhatsAppCampaignRecipient

failed = WhatsAppCampaignRecipient.objects.filter(
    campaign=campaign,
    status="failed",
)
for r in failed:
    print(r.phone_number, r.error_message)

WhatsAppLabel

A tag or label for organizing contacts and conversations.

Fields

FieldTypeDescription
nameCharField(50)Label name, unique.
colorCharField(20)Tailwind color name (e.g. "amber") or hex code. Default "gray".
created_atDateTimeFieldAuto-set on creation.
Default ordering: name (alphabetical).

Example

from django_meta_whatsapp.models import WhatsAppLabel

vip_label, _ = WhatsAppLabel.objects.get_or_create(
    name="VIP",
    defaults={"color": "amber"},
)
contact.labels.add(vip_label)

WhatsAppSignup

An In-App Signup deep link (wa.me/<phone>/signup/<id>) that lets users subscribe to your business directly inside WhatsApp.

Fields

FieldTypeDescription
accountForeignKey(WhatsAppAccount)Owning account.
signup_idCharField(100)ID returned by Meta after creation (unique).
display_nameCharField(255)Internal label — not shown to subscribers.
signup_messageTextFieldPre-consent screen text shown to the user in WhatsApp.
confirmation_messageTextFieldSent to the user after they subscribe. Use {{promo_code}} to embed a promo.
privacy_policy_urlURLFieldURL to privacy policy. Immutable after creation on Meta.
website_urlURLFieldOptional website URL.
promo_codeCharField(100)Alphanumeric promo code. Replaces {{promo_code}} in confirmation message.
statusCharField(20)"ACTIVE" or "DISABLED".
auto_add_to_labelForeignKey(WhatsAppLabel)Automatically assign this label to new subscribers (nullable).
subscriber_countPositiveIntegerFieldRunning count of subscribers (updated from webhook).
tos_acceptedBooleanFieldTrue after Terms of Service are accepted on first creation.
created_atDateTimeFieldAuto-set on creation.
updated_atDateTimeFieldAuto-set on every save.
Default ordering: -created_at

Methods

Builds the shareable wa.me deep link for a given phone number.
signup = WhatsAppSignup.objects.get(signup_id="abc123")
link = signup.get_deep_link("+919876543210")
# "https://wa.me/919876543210/signup/abc123"

WhatsAppAPIKey

REST API authentication keys used by the built-in API layer.

Fields

FieldTypeDescription
nameCharField(255)Human-readable key name (e.g. "Mobile App").
keyCharField(64)UUID-based key value, unique. Auto-generated on creation.
is_activeBooleanFieldTrue if the key is active.
created_atDateTimeFieldAuto-set on creation.

Example

from django_meta_whatsapp.models import WhatsAppAPIKey

api_key = WhatsAppAPIKey.objects.create(name="Mobile App")
print(api_key.key)  # e.g. "550e8400-e29b-41d4-a716-446655440000"

WhatsAppMedia

A reusable media library. Files are uploaded to Meta once, and the resulting media_id can be reused in multiple send_media_message() calls.

Fields

FieldTypeDescription
accountForeignKey(WhatsAppAccount)Owning account (nullable).
fileFileFieldThe local file (whatsapp_media_library/).
media_idCharField(255)ID returned by Meta after upload.
media_typeCharField(20)"image", "video", "audio", or "document".
mime_typeCharField(100)MIME type string.
original_filenameCharField(255)Original filename as uploaded.
uploaded_atDateTimeFieldAuto-set on creation.

WhatsAppCatalogProduct

Local mirror of Meta Commerce catalog products. Populated by sync_catalog_products().

Fields

FieldTypeDescription
accountForeignKey(WhatsAppAccount)Owning account (nullable).
catalog_idCharField(255)Meta Commerce catalog ID.
retailer_idCharField(255)Product retailer ID within the catalog.
nameCharField(255)Product name.
priceCharField(100)Price string including currency, e.g. "99.99 USD".
image_urlURLFieldProduct image URL.
is_activeBooleanFieldTrue if the product is active in the catalog.
synced_atDateTimeFieldAuto-updated on every sync.
Unique constraint: (account, catalog_id, retailer_id)

Example

from django_meta_whatsapp.models import WhatsAppCatalogProduct

products = WhatsAppCatalogProduct.objects.filter(
    catalog_id="123456789",
    is_active=True,
)

WhatsAppBlockedUser

Local mirror of Meta’s block list. is_active=True means the user is currently blocked. Unblocked users are retained for audit history with is_active=False.

Fields

FieldTypeDescription
accountForeignKey(WhatsAppAccount)Owning account.
phone_numberCharField(30)Blocked phone number (e.g. "+919876543210").
wa_idCharField(50)Meta’s wa_id (may differ from phone_number).
blocked_atDateTimeFieldAuto-set when the record is created.
blocked_byCharField(255)Username or email of the agent who triggered the block.
reasonTextFieldInternal note (e.g. "spam", "abuse").
is_activeBooleanFieldTrue = currently blocked; False = unblocked (kept for history).
unblocked_atDateTimeFieldTimestamp when the user was unblocked (nullable).
unblocked_byCharField(255)Username or email of the agent who unblocked.
meta_errorTextFieldStores error detail if the Meta block API call failed.
Unique constraint: (account, phone_number) Default ordering: -blocked_at

Example

from django_meta_whatsapp.models import WhatsAppBlockedUser

currently_blocked = WhatsAppBlockedUser.objects.filter(
    account=account,
    is_active=True,
)

WhatsAppWebhookLog

Full log of every webhook payload received from Meta. Useful for debugging delivery issues and replaying events.

Fields

FieldTypeDescription
received_atDateTimeFieldAuto-set when the webhook is received.
payloadJSONFieldFull webhook request body as parsed JSON.
processedBooleanFieldTrue if the webhook was processed without error.
errorTextFieldError text if processing failed.
Default ordering: -received_at

Example

from django_meta_whatsapp.models import WhatsAppWebhookLog

# Find unprocessed webhooks with errors
failed_webhooks = WhatsAppWebhookLog.objects.filter(
    processed=False,
).exclude(error="")

for log in failed_webhooks:
    print(log.received_at, log.error)
    print(log.payload)  # full Meta webhook JSON

Build docs developers (and LLMs) love