📖 Campaign Documentation
| Page | Description |
|---|---|
| Overview | Module overview, workflows, and high-level architecture |
| Models & Constants | Database models, enums, and default templates |
| Routes | API endpoints, request/response formats, and examples |
| Service | Business logic functions and integration points |
| Schemas | Validation schemas and data structures |
Overview
The Campaign module empowers merchants to create, manage, and deliver WhatsApp message templates ("campaigns") to their customers and internal merchant–users.
It encapsulates every step of the life-cycle – from authoring a template, submitting it to Twilio for approval, all the way to personalising and sending the message plus recording engagement metrics.
Cosmo supports two broad classes of campaigns:
- Marketing – one-off or scheduled broadcasts that are subject to WhatsApp marketing rules.
- Service / Utility – transactional or conversational messages (order updates, support tickets, etc.).
Internally a campaign is a versioned template – each update produces a new
Campaignrecord while the previous version is linked vianext_campaign_id.
High-level Responsibilities
- Template Authoring & Validation
- Validates content against Twilio requirements (see
schemas.md). - Extracts & validates variables (
{{lead_name}},{{1}}, …) withfind_and_validate_variables(). - Storage & Versioning – persists the template plus variable map to the DB (
Campaign,CampaignLead,CampaignLeadMessage). - Twilio Content API integration – creates/updates the corresponding Content SID so WhatsApp can render the template.
- Lead Management – stores who the template should be sent to and any per-lead custom variables.
- Sending – hydrates variables, sends with Twilio, records message IDs & delivery state.
- Reporting – calculates reply & conversion rates exposed through
CampaignSchema. - Campaign State Management – enables/disables campaigns for message sending and service automation.
- Type-based Filtering – supports filtering campaigns by type (marketing vs service) for organized management.
WhatsApp Message Types
WhatsApp enforces strict rules about message categories that determine when and how templates can be sent:
Marketing Campaigns
- Purpose: Promotional content, announcements, newsletters
- Restrictions:
- Can only be sent to users who have opted in within the last 24 hours
- Subject to WhatsApp's marketing message limits
- Require explicit user consent
- Current Behavior: All merchant-created campaigns are automatically categorized as
marketing - Examples: Product launches, sales announcements, weekly newsletters
Service/Utility Campaigns
- Purpose: Transactional updates, account notifications, customer service
- Advantages:
- Can be sent anytime without the 24-hour opt-in window
- Higher sending limits
- No explicit consent required for legitimate business updates
- Current Behavior:
- All system-created default templates are
servicetype - Merchants can update existing service templates but cannot create new ones
- Examples: Order confirmations, shipping updates, password resets, support responses
This distinction is enforced by Twilio/WhatsApp and impacts deliverability and compliance.
Campaign State Management
All campaigns have an enabled field that controls their operational state:
Enable/Disable Behavior
Enabled State (enabled = <timestamp>):
- Marketing Campaigns: Can send messages via UI and API endpoints
- Service Campaigns: Automatic service messages are triggered by events (order confirmations, stock alerts, etc.)
- UI Indicators: Shows green circle next to campaign name in frontend
Disabled State (enabled = NULL):
- Marketing Campaigns: Cannot send messages; play button disabled in UI
- Service Campaigns: Automatic service messages are blocked; events don't trigger sends
- UI Indicators: No green circle shown; pause button disabled
State Management Endpoints
| Endpoint | Purpose | Effect |
|---|---|---|
POST /enable |
Enable campaign | Sets enabled = datetime.now() |
POST /pause |
Disable campaign | Sets enabled = NULL |
POST /send?enable=true |
Send with auto-enable | Enables campaign before sending (marketing only) |
Use Cases
Marketing Campaigns: - Merchants manually enable campaigns when ready to send promotional content - Disabled by default to prevent accidental sends - Can be enabled temporarily for specific sends
Service Campaigns: - Merchants can pause service automation without deleting templates - Useful during maintenance, system updates, or when customizing service flows - Enables granular control over which service messages are active
Campaign Type Filtering
The module supports filtering campaigns by type for better organization:
Frontend Filtering
- Default View: Shows "Marketing Campaigns" by default
- Dropdown Toggle: Clickable title with chevron to switch between types
- Separate Lists: Marketing and service campaigns are shown separately
- Auto-Selection: First campaign is automatically selected when switching types
API Filtering
- Query Parameter:
GET /campaign/?campaign_type=marketing|service - Combined Filtering: Works with search, pagination, and other filters
- Type Validation: Invalid campaign types return 400 error
Benefits
- Reduced Clutter: Merchants see only relevant campaigns for their current task
- Clear Separation: Prevents confusion between promotional and transactional messages
- Workflow Optimization: Different campaign types often have different management workflows
Background Jobs Integration
The Campaign module integrates with SAQ (Simple Async Queue) background jobs for template approval monitoring:
Template Status Monitoring
update_message_template_status– Runs every 2 minutes, polls Twilio for status updates onpending/unsubmittedcampaignsupdate_message_template_status_approved– Runs at minutes 5 and 35, specifically monitors already-approved templates for any status changes
Approval Workflow
graph TD
A[Campaign Created] --> B[Status: unsubmitted]
B --> C[Background Job Polls Twilio]
C --> D{Twilio Response}
D -->|Approved| E[Status: approved<br/>Ready to Send]
D -->|Rejected| F[Status: rejected<br/>+ rejection_reason]
D -->|Still Processing| G[Status: pending<br/>Continue Polling]
G --> C
Critical: Campaigns cannot be sent until status = "approved". The sending functions check this status and will log warnings for non-approved sends (though Twilio will likely reject them anyway).
Campaign Leads as Queue & Historical Record
CampaignLead serves a dual purpose in the system:
1. Target Queue Management
- Pre-population: Merchants add leads via
/add-leadsbefore sending - Bulk Operations:
send_campaign_messages()processes allactive = Trueleads - Soft Deletion: Leads can be deactivated (
active = False) without losing historical data - Custom Variables: Each lead can have personalized variables that override defaults
2. Historical Sending Record
- Permanent Audit Trail: Every person who has ever received a campaign version remains in the database
- Marketing Compliance: Ensures one-time sends for marketing campaigns by checking existing
CampaignLeadMessagerecords - Analytics Foundation: Powers reply rates, conversion tracking, and engagement metrics
- Cross-Campaign Insights: Tracks customer journey across multiple campaign touchpoints
Lead Lifecycle Example
graph LR
A[Lead Added] --> B[Active: true]
B --> C[Message Sent]
C --> D[CampaignLeadMessage Created]
D --> E[Lead Remains in DB]
E --> F[Analytics & Compliance]
Even if a lead is later deactivated, their historical engagement data persists for reporting and compliance purposes.
Source Files
| File | Purpose |
|---|---|
models.py |
Database entities & enums (campaign, lead, message, status, type…). |
service.py |
Business logic: validation, Twilio integration, sending, default templates. |
routes.py |
FastAPI routes that expose the module. |
schemas.py |
Pydantic models used by both API and internal validation. |
Typical Workflow
graph TD
A[POST /campaign/create] --> B(create_message_template)
B --> C{Twilio OK?}
C -- yes --> D[Campaign.status = unsubmitted]
C -- error --> E[Campaign.status = rejected]
D --> F[Background Job Polls Status]
F --> G[Campaign.status = approved]
G --> H[POST /campaign/add-leads]
H --> I[POST /campaign/send]
I --> J(send_campaign_messages) --> K[Twilio delivery]
Detailed explanations of each step are provided in Service and Routes.
Related Modules
- Conversation – owns the actual WhatsApp chat and message history.
- Merchant / MerchantUser – producers & internal recipients of certain campaigns.
- Order / Product – supply dynamic variables such as
{{order_id}},{{product_name}}. - SAQ – background job system that monitors template approval status.