How Wappa Works (The Simple Version)ΒΆ
Don't worry, this isn't a computer science lecture. You just need to understand how a WhatsApp message gets to your code and back. That's it.
The Big Picture (30 Seconds)ΒΆ
When someone sends a WhatsApp message to your conversational app:
π€ User sends message β π WhatsApp β π‘ Your server β π― Your code β π€ Response back
Your code goes in one place: the event handler. Everything else is handled for you.
That's the whole story. Let's see what happens under the hood.
Message Flow: From WhatsApp to Your CodeΒΆ
Here's exactly what happens when someone sends a message to your conversational app:
1. Incoming Message FlowΒΆ
Info
Zoom in the UML Diagram
sequenceDiagram
participant User as π€ WhatsApp User
participant WA as π WhatsApp API
participant Route as π‘ Webhook Route
participant Middleware as π§ Middleware Layer
participant Controller as π― Webhook Controller
participant Processor as βοΈ Message Processor
participant Dispatcher as πͺ Event Dispatcher
participant Handler as π¨βπ» Your Event Handler
participant Messenger as π€ Messenger Service
User->>WA: Sends WhatsApp message
WA->>Route: POST /webhook/messenger/{tenant_id}/whatsapp
Route->>Middleware: Extract tenant_id & context
Middleware->>Controller: Request with tenant context
Controller->>Processor: Create Universal Webhook
Processor->>Controller: IncomingMessageWebhook
Controller->>Controller: Inject dependencies<br/>(messenger, cache_factory)
Controller->>Dispatcher: dispatch_universal_webhook()
Dispatcher->>Handler: handle_message(webhook)
Handler->>Messenger: send_text() / send_button_message()
Messenger->>WA: WhatsApp API call
WA->>User: Message delivered
What each step does:
- π WhatsApp API receives the user's message and sends it to your webhook URL
- π‘ Webhook Route validates the HTTP request and extracts the tenant ID from the URL
- π§ Middleware Layer sets up security context and request tracking
- π― Webhook Controller creates fresh dependencies for this specific request
- βοΈ Message Processor converts raw WhatsApp JSON into a clean
IncomingMessageWebhook
- πͺ Event Dispatcher routes the webhook to your event handler
- π¨βπ» Your Event Handler processes the message and sends responses
- π€ Messenger Service handles the WhatsApp API calls back to the user
2. Status Update FlowΒΆ
Status updates tell you when messages are delivered, read, or failed:
sequenceDiagram
participant WA as π WhatsApp API
participant Route as π‘ Webhook Route
participant Controller as π― Webhook Controller
participant Processor as βοΈ Status Processor
participant Dispatcher as πͺ Event Dispatcher
participant Handler as π¨βπ» Your Event Handler
WA->>Route: POST /webhook/messenger/{tenant_id}/whatsapp<br/>(status update)
Route->>Controller: Status webhook payload
Controller->>Processor: Create Universal Webhook
Processor->>Controller: StatusWebhook
Controller->>Dispatcher: dispatch_universal_webhook()
Dispatcher->>Handler: handle_status(webhook)
Handler->>Handler: Optional: Update delivery tracking
3. Error Webhook FlowΒΆ
Error webhooks notify you when something goes wrong with message delivery:
sequenceDiagram
participant WA as π WhatsApp API
participant Route as π‘ Webhook Route
participant Controller as π― Webhook Controller
participant Processor as βοΈ Error Processor
participant Dispatcher as πͺ Event Dispatcher
participant Handler as π¨βπ» Your Event Handler
WA->>Route: POST /webhook/messenger/{tenant_id}/whatsapp<br/>(error notification)
Route->>Controller: Error webhook payload
Controller->>Processor: Create Universal Webhook
Processor->>Controller: ErrorWebhook
Controller->>Dispatcher: dispatch_universal_webhook()
Dispatcher->>Handler: handle_error(webhook)
Handler->>Handler: Optional: Error recovery logic
The Magic: Dependency Injection (In Practice)ΒΆ
Here's the cool part: Wappa automatically gives your event handler everything it needs to process messages.
Before Your Code RunsΒΆ
When a webhook arrives, Wappa automatically creates and injects:
# This happens automatically - you don't write this code!
# 1. Create messenger for this specific tenant
messenger = await messenger_factory.create_messenger(
platform=PlatformType.WHATSAPP,
tenant_id=tenant_id # Different per request!
)
# 2. Create cache factory for user state management
cache_factory = create_cache_factory(cache_type)
cache = cache_factory(tenant_id=tenant_id, user_id=user_id)
# 3. Inject into your event handler
your_event_handler.messenger = messenger # Send messages
your_event_handler.cache_factory = cache_factory # Remember things
your_event_handler.logger = logger # Log events
# 4. Now call your code
await your_event_handler.handle_message(webhook)
In Your Event HandlerΒΆ
You just use the injected dependencies - they're ready to go:
from wappa import WappaEventHandler
class MyApp(WappaEventHandler):
async def handle_message(self, webhook):
# These are automatically available:
# β
self.messenger - Send messages back to WhatsApp
await self.messenger.send_text("Hello!", webhook.user.user_id)
# β
self.cache_factory - Remember user conversations
user_cache = self.cache_factory.create_user_cache()
await user_cache.set("last_message", webhook.get_message_text())
# β
self.logger - Log events with context
self.logger.info(f"Processed message from {webhook.user.profile_name}")
That's it! You never create these objects yourself - Wappa handles all the plumbing.
Why This Architecture MattersΒΆ
Multi-Tenant by DefaultΒΆ
Each webhook gets fresh dependencies with the correct tenant context:
# Request 1: Company A's WhatsApp number
# β messenger configured for Company A
# β cache isolated to Company A's data
# Request 2: Company B's WhatsApp number
# β messenger configured for Company B
# β cache isolated to Company B's data
No data leaks, no configuration confusion. Each request is completely isolated.
Performance & ReliabilityΒΆ
- β‘ Immediate Response: WhatsApp gets an instant "200 OK" response
- π Background Processing: Your code runs asynchronously without timeout pressure
- π§ Connection Pooling: Shared HTTP connections for efficiency
- π‘οΈ Error Isolation: One tenant's errors don't affect others
Scalability Without ComplexityΒΆ
# This works for 1 user:
app = Wappa()
# This works for 1,000,000 users:
app = Wappa(cache="redis")
# Same code, same patterns. Just change the cache type.
No architectural changes needed as your app grows.
Your Event Handler: The Star of the ShowΒΆ
Your WappaEventHandler
is where all your business logic lives. It's the only class you need to understand:
from wappa import WappaEventHandler
class MyConversationalApp(WappaEventHandler):
async def handle_message(self, webhook):
"""Handle incoming messages - the main event"""
# Your conversational logic goes here
pass
async def handle_status(self, webhook):
"""Optional: Handle delivery/read status updates"""
# Track message delivery if needed
pass
async def handle_error(self, webhook):
"""Optional: Handle WhatsApp API errors"""
# Error recovery logic if needed
pass
Three methods. That's your entire API.
Most conversational apps only implement handle_message()
. The others are optional for advanced use cases.
What's in a Webhook?ΒΆ
The webhook
parameter contains everything WhatsApp sends you, cleaned up and organized:
# User information
webhook.user.user_id # "1234567890"
webhook.user.profile_name # "John Doe"
webhook.user.tenant_id # Your company/tenant ID
# Message content
webhook.get_message_text() # "Hello app!"
webhook.get_message_type_name() # "text", "image", "audio", etc.
webhook.message.message_id # "wamid.abc123..."
# Interactive responses (when user clicks buttons)
webhook.interactive.button_reply.id # "button_1"
webhook.interactive.button_reply.title # "Yes"
Clean, simple, predictable. No digging through nested JSON structures.
The Complete ArchitectureΒΆ
Here's how all the Wappa components work together as a system:
flowchart TD
subgraph External [π External Services]
User[π€ WhatsApp User]
WA[π± WhatsApp Business API]
end
subgraph WappaFramework [ποΈ Wappa Framework]
subgraph HTTP [π‘ HTTP Layer]
Route["π Webhook Routes<br/><br/>POST /webhook/messenger/<br/>tenant_id/whatsapp<br/><br/>β’ URL Pattern Matching<br/>β’ Request Validation<br/>β’ Tenant Extraction"]
Middleware["π§ FastAPI Middleware<br/><br/>β’ Tenant Context Setup<br/>β’ Security Headers<br/>β’ Request Tracking<br/>β’ Error Boundaries"]
end
subgraph Processing [βοΈ Processing Layer]
Controller["π― WebhookController<br/><br/>β’ Per-Request Dependencies<br/>β’ Multi-tenant Isolation<br/>β’ Async Request Handling<br/>β’ Business Logic Routing"]
Processor["π WhatsApp Processor<br/><br/>β’ Raw JSON -> Universal<br/>Webhook<br/>β’ Schema Validation<br/>β’ Message Type Detection<br/>β’ Context Enrichment"]
end
subgraph Core [πͺ Core Event System]
Dispatcher["πͺ Event Dispatcher<br/><br/>β’ Handler Method Routing<br/>β’ Exception Management<br/>β’ Performance Monitoring<br/>β’ Result Aggregation"]
UW["π Universal Webhook<br/><br/>β’ IncomingMessageWebhook<br/>β’ StatusWebhook<br/>β’ ErrorWebhook<br/>β’ Platform Abstraction"]
end
subgraph Dependencies [π Injected Dependencies]
Messenger["π€ Messenger Service<br/><br/>β’ WhatsApp Business API<br/>β’ Message Composition<br/>β’ Media Upload/Download<br/>β’ Template Management"]
Cache["πΎ Cache Factory<br/><br/>β’ User State Persistence<br/>β’ Session Management<br/>β’ Multi-backend (Memory/Redis)<br/>β’ Tenant Isolation"]
Logger["π Context Logger<br/><br/>β’ Structured JSON Logging<br/>β’ Request Tracing<br/>β’ Performance Metrics<br/>β’ Multi-tenant Context"]
end
end
subgraph UserCode [π¨βπ» Your Application]
Handler["π― Your Event Handler<br/><br/>β’ handle_message()<br/>β’ handle_status()<br/>β’ handle_error()<br/>β’ Business Logic Entry Point"]
Business["π’ Your Business Logic<br/><br/>β’ Conversation Flow<br/>Management<br/>β’ Data Processing & Analysis<br/>β’ External API Integrations<br/>β’ Custom Application Features"]
end
%% Message Flow
User -->|Sends Message| WA
WA -->|Webhook POST| Route
Route --> Middleware
Middleware --> Controller
Controller --> Processor
Processor --> UW
UW --> Dispatcher
Dispatcher --> Handler
Handler --> Business
%% Dependency Injection
Controller -.->|Injects| Messenger
Controller -.->|Injects| Cache
Controller -.->|Injects| Logger
%% Response Flow
Handler -.->|Uses| Messenger
Handler -.->|Uses| Cache
Handler -.->|Uses| Logger
Messenger -->|API Calls| WA
WA -->|Delivers| User
%% Clean outline-only styling for professional appearance
classDef userCode fill:transparent,stroke:#1976d2,stroke-width:3px;
classDef wappaCore fill:transparent,stroke:#7b1fa2,stroke-width:2px;
classDef external fill:transparent,stroke:#f57c00,stroke-width:2px;
classDef dependency fill:transparent,stroke:#388e3c,stroke-width:2px;
class Handler,Business userCode
class Route,Middleware,Controller,Processor,Dispatcher,UW wappaCore
class User,WA external
class Messenger,Cache,Logger dependency
System Architecture Layers:
- π External Services (Orange) - WhatsApp Business API and users outside your control
- ποΈ Wappa Framework (Purple) - Handles all the complex infrastructure automatically
- π Injected Dependencies (Green) - Ready-to-use services provided to your code
- π¨βπ» Your Application (Blue) - Just your event handler and business logic
The flow is simple: Messages come in β Wappa processes them β Your handler gets called with everything ready to use β You send responses back.
What You Need to RememberΒΆ
- π± Messages come in β Wappa converts them to clean webhook objects
- π― Your handler processes them β All dependencies are injected automatically
- π€ You send responses β Using the pre-configured messenger
- β Done β Wappa handles all the HTTP/API complexity
That's literally it. Everything else is handled for you.
Want More Details?ΒΆ
Now that you understand the flow, dive deeper into specific areas:
- Event System Guide - Master webhook handling and state management
Ready to Build?ΒΆ
- Quick Start - Create your first conversational app in 10 minutes
π§ Understanding Achieved!
You now understand how Wappa works. Time to build something amazing!
π Build Your First App