Skip to content

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:

  1. 🌐 WhatsApp API receives the user's message and sends it to your webhook URL
  2. πŸ“‘ Webhook Route validates the HTTP request and extracts the tenant ID from the URL
  3. πŸ”§ Middleware Layer sets up security context and request tracking
  4. 🎯 Webhook Controller creates fresh dependencies for this specific request
  5. βš™οΈ Message Processor converts raw WhatsApp JSON into a clean IncomingMessageWebhook
  6. πŸŽͺ Event Dispatcher routes the webhook to your event handler
  7. πŸ‘¨β€πŸ’» Your Event Handler processes the message and sends responses
  8. πŸ“€ 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ΒΆ

  1. πŸ“± Messages come in β†’ Wappa converts them to clean webhook objects
  2. 🎯 Your handler processes them β†’ All dependencies are injected automatically
  3. πŸ“€ You send responses β†’ Using the pre-configured messenger
  4. βœ… 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:

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