WhatsApp Notifications
WhatsApp is the primary communication channel — not email, not push. 98% of customers interact via WhatsApp. Automating notifications is the #1 business priority.
Architecture
All notifications flow through a job queue and are delivered via a primary/fallback provider pattern.
Primary Delivery Flow
Fallback Delivery Flow
WAHA (Primary)
Self-hosted WhatsApp HTTP API. Zero per-message cost. Runs as a Docker container alongside the application. All notifications attempt WAHA first.
Twilio (Fallback)
Automatic fallback when WAHA delivery fails after all retry attempts. Per-message cost, but guarantees delivery when the primary channel is down.
Background Job Queue (Hangfire or IHostedService)
Never send notifications synchronously. Every notification is enqueued as a background job via Hangfire or a .NET IHostedService. This decouples booking creation from message delivery and enables retries.
Delivery Status Webhooks
WAHA sends delivery status callbacks via webhooks. The system tracks each message from pending through delivered or failed.
4 Core Templates
All templates are written in Arabic. Each template uses variable interpolation for customer and booking details.
| Template | Trigger | When |
|---|---|---|
| booking_created | Booking is created | Immediately |
| booking_confirmed | Status changes to confirmed | On confirmation |
| 24h_reminder | 24 hours before session | Scheduled job |
| booking_cancelled | Booking is cancelled | Immediately |
Template Variables
Every template has access to the following variables, injected at send time:
| Variable | Description | Example |
|---|---|---|
customer_name |
Customer's display name | Ahmed |
field_name |
Name of the booked field (Arabic) | ملعب 1 |
location_name |
Location name (Arabic) | ملاعب النجمة |
date |
Booking date | 2024-03-15 |
time |
Session start time | 18:00 |
price |
Booking price in SAR | 150 SAR |
notification_templates table with name_ar and body_ar columns. Variables are interpolated using placeholder syntax within the Arabic text.
Delivery Status Tracking
Happy Path
Failure Path
| Status | Meaning |
|---|---|
| pending | Queued, not yet sent |
| sent | Sent to provider (WAHA or Twilio) |
| delivered | Confirmed delivered to recipient |
| failed | Delivery failed after all retries |
Webhook Endpoints
Two webhook endpoints receive callbacks from WAHA:
| Method | Endpoint | Purpose |
|---|---|---|
| POST | /webhooks/whatsapp/messages |
Incoming messages from customers via WAHA |
| POST | /webhooks/whatsapp/status |
Delivery status updates from WAHA |
Retry Logic
| Attempt | Provider | Delay |
|---|---|---|
| 1st attempt | WAHA | Immediate |
| 2nd attempt | WAHA | 30 seconds |
| 3rd attempt | WAHA | 2 minutes |
| 4th attempt (fallback) | Twilio | 10 minutes |
- Max 3 delivery attempts via WAHA with exponential backoff: 30s, 2min, 10min
- After 3 WAHA failures, automatically switch to Twilio
- If Twilio also fails, mark notification as failed and log the error
Incoming Messages (Future)
incoming_messages table but not processed automatically. Bidirectional WhatsApp (auto-responses, booking confirmation via reply) is a post-launch feature.
The incoming_messages table captures:
from_phone— sender's phone numberbody— message text contentreceived_at— timestamp of receiptis_processed— alwaysfalseat launch
Analytics Events
The following PostHog events are dispatched for notification tracking:
| Event | Properties |
|---|---|
notification_sent |
template, channel, provider |
notification_delivered |
template, delivery_time_ms |
notification_failed |
template, error_code, provider |
customer_message_received |
is_reply, contains_booking_ref |