Skip to content
Back to blog

WhatsApp Business API Automation: A Complete Guide

A complete guide to WhatsApp Business API automation covering setup, message templates, webhook handling, and building a customer support bot.

MH
Mahmoud Hashem
· September 25, 2024 · 8 min read
WhatsApp messaging interface on a mobile device

Introduction

WhatsApp has over 2 billion active users worldwide, making it one of the most important communication channels for businesses. The WhatsApp Business API enables companies to send and receive messages programmatically, automate customer interactions, and integrate WhatsApp into their existing systems.

This guide covers everything you need to know to build WhatsApp automation: from initial setup through message templates, webhook handling, and building a functional customer support bot.

Understanding WhatsApp Business API

The WhatsApp Business API is different from the WhatsApp Business app. The app is for small businesses to manage conversations manually. The API is for businesses that need to automate and scale WhatsApp communication.

Key Concepts

  • Business Solution Provider (BSP): Meta doesn’t provide direct API access. You use a BSP like Twilio, 360dialog, or MessageBird as an intermediary
  • Phone Number: You need a dedicated phone number registered with WhatsApp Business
  • Message Templates: Pre-approved message formats for initiating conversations
  • Session Messages: Messages sent within a 24-hour window after a customer messages you
  • Webhooks: HTTP endpoints that receive incoming messages and status updates

Pricing Model

WhatsApp charges per conversation, not per message:

  • Business-initiated conversations: You send a template message to start the conversation
  • User-initiated conversations: The customer messages you first
  • Pricing varies by country: Different rates for different regions

Setting Up WhatsApp Business API

Step 1: Choose a Business Solution Provider

Popular BSPs include:

  • Twilio: Well-documented API, good developer experience
  • 360dialog: Direct Meta partner, competitive pricing
  • MessageBird: Multi-channel platform with WhatsApp support
  • Meta Cloud API: Meta’s own cloud-hosted API (simplest setup)

Step 2: Register Your Phone Number

# Example using Meta Cloud API
import requests

GRAPH_API_URL = "https://graph.facebook.com/v18.0"
ACCESS_TOKEN = "your-access-token"
PHONE_NUMBER_ID = "your-phone-number-id"

# Register phone number
response = requests.post(
    f"{GRAPH_API_URL}/{PHONE_NUMBER_ID}/register",
    headers={"Authorization": f"Bearer {ACCESS_TOKEN}"},
    json={
        "messaging_product": "whatsapp",
        "pin": "123456"  # 6-digit PIN you chose
    }
)

Step 3: Configure Webhooks

Set up a webhook endpoint to receive incoming messages:

from fastapi import FastAPI, Request, Response
import json

app = FastAPI()

VERIFY_TOKEN = "your_verify_token"

@app.get("/webhook")
async def verify_webhook(hub_mode: str, hub_challenge: str, hub_verify_token: str):
    """Verify webhook with Meta."""
    if hub_mode == "subscribe" and hub_verify_token == VERIFY_TOKEN:
        return Response(content=hub_challenge, status_code=200)
    return Response(status_code=403)

@app.post("/webhook")
async def receive_webhook(request: Request):
    """Handle incoming WhatsApp messages."""
    body = await request.json()
    
    # Process the webhook
    if body.get("object") == "whatsapp_business_account":
        for entry in body.get("entry", []):
            for change in entry.get("changes", []):
                if change.get("field") == "messages":
                    handle_message(change.get("value"))
    
    return Response(status_code=200)

Message Templates

You cannot send arbitrary messages to customers outside the 24-hour session window. You must use pre-approved message templates.

Creating a Template

def create_message_template():
    """Create a message template for approval."""
    template = {
        "name": "order_confirmation",
        "language": "en_US",
        "category": "UTILITY",
        "components": [
            {
                "type": "BODY",
                "text": "Hi {{1}}, your order {{2}} has been confirmed. "
                        "Expected delivery: {{3}}. Track your order at {{4}}."
            },
            {
                "type": "BUTTONS",
                "buttons": [
                    {
                        "type": "QUICK_REPLY",
                        "text": "Track Order"
                    },
                    {
                        "type": "QUICK_REPLY",
                        "text": "Contact Support"
                    }
                ]
            }
        ]
    }
    
    response = requests.post(
        f"{GRAPH_API_URL}/{PHONE_NUMBER_ID}/message_templates",
        headers={"Authorization": f"Bearer {ACCESS_TOKEN}"},
        json=template
    )
    return response.json()

Sending a Template Message

def send_template_message(phone_number: str, order_data: dict):
    """Send an order confirmation template message."""
    message = {
        "messaging_product": "whatsapp",
        "recipient_type": "individual",
        "to": phone_number,
        "type": "template",
        "template": {
            "name": "order_confirmation",
            "language": {"code": "en_US"},
            "components": [
                {
                    "type": "body",
                    "parameters": [
                        {"type": "text", "text": order_data["customer_name"]},
                        {"type": "text", "text": order_data["order_id"]},
                        {"type": "text", "text": order_data["delivery_date"]},
                        {"type": "text", "text": order_data["tracking_url"]}
                    ]
                }
            ]
        }
    }
    
    response = requests.post(
        f"{GRAPH_API_URL}/{PHONE_NUMBER_ID}/messages",
        headers={
            "Authorization": f"Bearer {ACCESS_TOKEN}",
            "Content-Type": "application/json"
        },
        json=message
    )
    return response.json()

Handling Incoming Messages

Parsing Message Types

WhatsApp supports text, image, audio, document, and location messages:

def handle_message(value: dict):
    """Process incoming WhatsApp message."""
    messages = value.get("messages", [])
    
    if not messages:
        # Could be a status update (sent, delivered, read)
        handle_status(value.get("statuses", []))
        return
    
    message = messages[0]
    sender_phone = message["from"]
    message_type = message["type"]
    
    if message_type == "text":
        text = message["text"]["body"]
        handle_text_message(sender_phone, text)
    
    elif message_type == "interactive":
        # Handle button clicks and list selections
        interactive = message["interactive"]
        if interactive["type"] == "button_reply":
            button_id = interactive["button_reply"]["id"]
            handle_button_response(sender_phone, button_id)
    
    elif message_type == "image":
        image_id = message["image"]["id"]
        caption = message["image"].get("caption", "")
        handle_image_message(sender_phone, image_id, caption)
    
    elif message_type == "location":
        latitude = message["location"]["latitude"]
        longitude = message["location"]["longitude"]
        handle_location_message(sender_phone, latitude, longitude)

Sending Reply Messages

Within the 24-hour session window, you can send free-form messages:

def send_text_message(phone_number: str, text: str):
    """Send a text message to a customer."""
    message = {
        "messaging_product": "whatsapp",
        "recipient_type": "individual",
        "to": phone_number,
        "type": "text",
        "text": {"body": text}
    }
    
    response = requests.post(
        f"{GRAPH_API_URL}/{PHONE_NUMBER_ID}/messages",
        headers={
            "Authorization": f"Bearer {ACCESS_TOKEN}",
            "Content-Type": "application/json"
        },
        json=message
    )
    return response.json()

Building a Customer Support Bot

Let’s build a bot that handles common customer queries using AI and routes complex issues to human agents.

Bot Architecture

from dataclasses import dataclass
from enum import Enum

class MessageType(Enum):
    TEXT = "text"
    INTERACTIVE = "interactive"

@dataclass
class CustomerContext:
    phone_number: str
    name: str = ""
    conversation_state: str = "initial"
    order_id: str = ""
    issue_type: str = ""

class WhatsAppBot:
    def __init__(self, llm_client, database):
        self.llm = llm_client
        self.db = database
        self.contexts = {}  # In production, use Redis
    
    def get_context(self, phone_number: str) -> CustomerContext:
        if phone_number not in self.contexts:
            self.contexts[phone_number] = CustomerContext(phone_number=phone_number)
        return self.contexts[phone_number]
    
    def process_message(self, phone_number: str, text: str):
        context = self.get_context(phone_number)
        
        # Route based on conversation state
        if context.conversation_state == "initial":
            return self.handle_initial(context, text)
        elif context.conversation_state == "awaiting_order_id":
            return self.handle_order_lookup(context, text)
        elif context.conversation_state == "in_support":
            return self.handle_support(context, text)

Intent Detection with AI

    def detect_intent(self, text: str) -> str:
        """Use LLM to detect user intent."""
        prompt = f"""Classify this customer message into one of these categories:
        - order_status: Asking about order status
        - product_inquiry: Asking about products
        - complaint: Filing a complaint
        - general: General question
        - human: Requesting human agent
        
        Message: "{text}"
        
        Respond with only the category name."""
        
        intent = self.llm.invoke(prompt).strip().lower()
        return intent
    
    def handle_initial(self, context: CustomerContext, text: str):
        intent = self.detect_intent(text)
        
        if intent == "order_status":
            context.conversation_state = "awaiting_order_id"
            return "Please enter your order ID (e.g., ORD-12345)"
        
        elif intent == "product_inquiry":
            return self.handle_product_inquiry(text)
        
        elif intent == "complaint":
            context.conversation_state = "in_support"
            context.issue_type = "complaint"
            return "I'm sorry to hear you're having an issue. " \
                   "Please describe the problem in detail."
        
        elif intent == "human":
            return self.escalate_to_human(context)
        
        else:
            return self.handle_general_query(text)

AI-Powered Responses

    def handle_general_query(self, text: str) -> str:
        """Generate AI response using knowledge base."""
        # Retrieve relevant context from knowledge base
        relevant_docs = self.db.search_knowledge_base(text, top_k=3)
        context = "\n".join([doc.content for doc in relevant_docs])
        
        prompt = f"""You are a helpful customer support assistant.
        Use the following knowledge base to answer the customer's question.
        If you don't know the answer, say you'll connect them with a human agent.
        
        Knowledge Base:
        {context}
        
        Customer Question: {text}
        
        Answer:"""
        
        response = self.llm.invoke(prompt)
        return response

Interactive Messages with Buttons

def send_interactive_message(phone_number: str, body_text: str, buttons: list):
    """Send a message with quick reply buttons."""
    message = {
        "messaging_product": "whatsapp",
        "recipient_type": "individual",
        "to": phone_number,
        "type": "interactive",
        "interactive": {
            "type": "button",
            "body": {"text": body_text},
            "action": {
                "buttons": [
                    {
                        "type": "reply",
                        "reply": {"id": btn["id"], "title": btn["title"]}
                    }
                    for btn in buttons
                ]
            }
        }
    }
    
    response = requests.post(
        f"{GRAPH_API_URL}/{PHONE_NUMBER_ID}/messages",
        headers={
            "Authorization": f"Bearer {ACCESS_TOKEN}",
            "Content-Type": "application/json"
        },
        json=message
    )
    return response.json()

# Usage
send_interactive_message(
    phone_number="+1234567890",
    body_text="How can I help you today?",
    buttons=[
        {"id": "track_order", "title": "Track Order"},
        {"id": "product_info", "title": "Product Info"},
        {"id": "support", "title": "Support"}
    ]
)

Best Practices

  1. Respect the 24-hour rule: You can only send free-form messages within 24 hours of the customer’s last message. Use templates for business-initiated conversations.

  2. Get user opt-in: Always get explicit consent before sending marketing messages. WhatsApp can suspend accounts that send unsolicited messages.

  3. Implement rate limiting: WhatsApp has throughput limits. Space out messages to avoid being rate-limited.

  4. Handle media downloads: When receiving images or documents, download and store them promptly. Media URLs expire.

  5. Log all conversations: Keep records for customer service, compliance, and analytics.

  6. Provide human escalation: Always give customers a path to reach a human agent. AI bots should recognize when they can’t help and escalate.

Conclusion

WhatsApp Business API automation opens up a powerful channel for customer engagement. The combination of message templates for proactive outreach, session messages for real-time conversation, and AI for intelligent responses creates a robust customer communication system.

Start with a simple bot that handles the most common queries, then gradually add AI capabilities and more sophisticated routing. The key is to always provide value to the customer while respecting WhatsApp’s rules and limitations. With proper implementation, WhatsApp automation can significantly reduce support costs while improving customer satisfaction.

#WhatsApp #Automation #API

Related articles

Let's build something great together

Ready to automate your business processes and save hundreds of hours every month? Let's talk about your project.