Tutorial

Build a WhatsApp Chatbot with Python in Under 30 Minutes

Create a fully functional WhatsApp chatbot using Python, FastAPI, and the WhatsApp Messaging API. Includes webhook setup and auto-reply logic.

February 20, 2026By Retention Stack

Build a WhatsApp Chatbot with Python in 30 Minutes (2026 Guide)

Meta Description: Build a production-ready WhatsApp chatbot with Python, FastAPI, and webhooks. Complete tutorial with code examples, auto-reply logic, and deployment guide.


Introduction

Building a WhatsApp chatbot used to mean enterprise SDKs, Meta Business approval forms, and weeks of waiting. Not anymore.

This tutorial shows you how to build a fully functional WhatsApp chatbot in Python that can:

  • ✅ Receive and process incoming messages in real-time
  • ✅ Send automatic replies based on keywords
  • ✅ Handle multiple conversations simultaneously
  • ✅ Deploy to production with FastAPI
  • ✅ Scale to thousands of users

By the end, you'll have a working chatbot handling real WhatsApp messages—no approval process, no waiting, no Meta Business account required.

What you'll need:

  • Python 3.8+
  • A RapidAPI account (free)
  • 30 minutes
  • Basic Python knowledge

Let's build it.


Why Python for WhatsApp Chatbots?

The Python Advantage

python
# This is all it takes to send a WhatsApp message in Python
import requests

response = requests.post(
    'https://whatsapp-messaging-bot.p.rapidapi.com/v1/sendText',
    headers={
        'X-RapidAPI-Key': 'your-key',
        'X-RapidAPI-Host': 'whatsapp-messaging-bot.p.rapidapi.com',
        'Content-Type': 'application/json'
    },
    json={'chatId': '1234567890', 'text': 'Hello from Python!', 'session': 'default'}
)

Why developers choose Python:

  • 🐍 Simple, readable syntax
  • 🔧 FastAPI for async operations
  • 📦 Rich ecosystem (requests, pydantic, SQLAlchemy)
  • ⚡ Perfect for AI/ML integrations (OpenAI, LangChain)
  • 🚀 Fast development time

Comparison:

FeaturePythonNode.jsPHP
Learning CurveEasyModerateEasy
Async Support✅ (asyncio, FastAPI)✅ (native)⚠️ (limited)
AI/ML Integration🏆 BestGoodLimited
DeploymentEasyEasyEasy
CommunityHugeHugeLarge

Architecture Overview

How the Chatbot Works

User sends WhatsApp message
        ↓
WhatsApp API receives message
        ↓
Webhook triggers your FastAPI endpoint
        ↓
Your bot processes message (keyword matching, AI, etc.)
        ↓
Bot sends reply via API
        ↓
User receives response in WhatsApp

Key Components:

  1. 1.FastAPI Server: Receives webhook events
  2. 2.Message Handler: Processes incoming messages
  3. 3.Reply Engine: Generates and sends responses
  4. 4.Session Manager: Maintains conversation state
  5. 5.Database (optional): Stores conversation history

Step 1: Project Setup (5 minutes)

Create Project Structure

bash
mkdir whatsapp-chatbot-python
cd whatsapp-chatbot-python

# Create virtual environment
python3 -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install dependencies
pip install fastapi uvicorn requests python-dotenv pydantic

Project Structure

whatsapp-chatbot-python/
├── main.py                 # FastAPI app
├── bot/
│   ├── __init__.py
│   ├── message_handler.py  # Process incoming messages
│   ├── reply_engine.py     # Generate replies
│   └── whatsapp_client.py  # API wrapper
├── config.py               # Configuration
├── .env                    # API keys
└── requirements.txt

Create requirements.txt

txt
fastapi==0.104.1
uvicorn[standard]==0.24.0
requests==2.31.0
python-dotenv==1.0.0
pydantic==2.5.0
pydantic-settings==2.1.0

Step 2: Configuration Setup

Create .env file

bash
# RapidAPI Credentials
RAPIDAPI_KEY=your_rapidapi_key_here
RAPIDAPI_HOST=whatsapp-messaging-bot.p.rapidapi.com

# WhatsApp Session
WHATSAPP_SESSION=my-chatbot

# Server Config
HOST=0.0.0.0
PORT=8000
DEBUG=True

# Webhook Config (for production)
WEBHOOK_URL=https://your-domain.com/webhook
WEBHOOK_SECRET=your-secret-key-here

Create config.py

python
from pydantic_settings import BaseSettings
from functools import lru_cache

class Settings(BaseSettings):
    # RapidAPI
    rapidapi_key: str
    rapidapi_host: str
    
    # WhatsApp
    whatsapp_session: str
    
    # Server
    host: str = "0.0.0.0"
    port: int = 8000
    debug: bool = True
    
    # Webhook
    webhook_url: str = ""
    webhook_secret: str = ""
    
    # API Base URL
    @property
    def api_base_url(self) -> str:
        return f"https://{self.rapidapi_host}"
    
    class Config:
        env_file = ".env"

@lru_cache()
def get_settings() -> Settings:
    return Settings()

Step 3: WhatsApp API Client

Create bot/whatsapp_client.py

python
import requests
from typing import Dict, Any, Optional
from config import get_settings

class WhatsAppClient:
    def __init__(self):
        self.settings = get_settings()
        self.base_url = self.settings.api_base_url
        self.session = self.settings.whatsapp_session
        self.headers = {
            'X-RapidAPI-Key': self.settings.rapidapi_key,
            'X-RapidAPI-Host': self.settings.rapidapi_host,
            'Content-Type': 'application/json'
        }
    
    def send_text_message(self, chat_id: str, text: str) -> Dict[str, Any]:
        """Send a text message to a WhatsApp contact."""
        url = f"{self.base_url}/v1/sendText"
        
        payload = {
            "chatId": chat_id,
            "text": text,
            "session": self.session
        }
        
        try:
            response = requests.post(url, json=payload, headers=self.headers)
            response.raise_for_status()
            return response.json()
        except requests.exceptions.RequestException as e:
            print(f"Error sending message: {e}")
            return {"error": str(e)}
    
    def send_image(self, chat_id: str, image_url: str, caption: str = "") -> Dict[str, Any]:
        """Send an image message."""
        url = f"{self.base_url}/v1/sendImage"
        
        payload = {
            "chatId": chat_id,
            "file": {"url": image_url, "mimetype": "image/jpeg"},
            "caption": caption,
            "session": self.session
        }
        
        try:
            response = requests.post(url, json=payload, headers=self.headers)
            response.raise_for_status()
            return response.json()
        except requests.exceptions.RequestException as e:
            print(f"Error sending image: {e}")
            return {"error": str(e)}
    
    def get_contacts(self) -> Dict[str, Any]:
        """Get all contacts."""
        url = f"{self.base_url}/v1/sessions/{self.session}/contacts"
        
        try:
            response = requests.get(url, headers=self.headers)
            response.raise_for_status()
            return response.json()
        except requests.exceptions.RequestException as e:
            print(f"Error getting contacts: {e}")
            return {"error": str(e)}
    
    def create_session(self) -> Dict[str, Any]:
        """Create a new WhatsApp session."""
        url = f"{self.base_url}/v1/sessions"
        
        payload = {"name": self.session}
        
        try:
            response = requests.post(url, json=payload, headers=self.headers)
            response.raise_for_status()
            return response.json()
        except requests.exceptions.RequestException as e:
            print(f"Error creating session: {e}")
            return {"error": str(e)}
    
    def get_qr_code(self) -> Optional[str]:
        """Get QR code for session authentication."""
        url = f"{self.base_url}/v1/sessions/{self.session}/qr"
        
        try:
            response = requests.get(url, headers=self.headers)
            response.raise_for_status()
            data = response.json()
            return data.get('qr')
        except requests.exceptions.RequestException as e:
            print(f"Error getting QR code: {e}")
            return None

Step 4: Reply Engine (The Brain)

Create bot/reply_engine.py

python
from typing import Dict, Optional
import re

class ReplyEngine:
    """
    Generates replies based on incoming messages.
    Supports keyword matching, command handling, and default responses.
    """
    
    def __init__(self):
        # Define your bot's responses
        self.keywords = {
            'hi': 'Hello! 👋 How can I help you today?',
            'hello': 'Hi there! 👋 Welcome to our WhatsApp bot.',
            'help': self._help_message(),
            'pricing': self._pricing_message(),
            'features': self._features_message(),
            'contact': '📞 You can reach us at support@example.com or call +1-555-0123',
            'thanks': "You're welcome! Feel free to ask anything else. 😊",
            'bye': 'Goodbye! Have a great day! 👋',
        }
        
        # Command handlers (messages starting with /)
        self.commands = {
            '/start': 'Welcome! Type "help" to see what I can do.',
            '/help': self._help_message(),
            '/subscribe': 'Great! You\'re now subscribed to updates. 🎉',
            '/unsubscribe': 'You\'ve been unsubscribed. We\'ll miss you! 😢',
            '/status': 'Bot is running smoothly! ✅',
        }
    
    def generate_reply(self, message_text: str, sender: str) -> str:
        """
        Generate a reply based on the incoming message.
        
        Args:
            message_text: The text of the incoming message
            sender: The sender's phone number or ID
            
        Returns:
            The reply text
        """
        message_text = message_text.strip().lower()
        
        # Check for commands first
        if message_text.startswith('/'):
            return self.commands.get(message_text, "Unknown command. Type /help for available commands.")
        
        # Check for keyword matches
        for keyword, reply in self.keywords.items():
            if keyword in message_text:
                return reply
        
        # Check for questions (contains ?)
        if '?' in message_text:
            return self._handle_question(message_text)
        
        # Default response
        return self._default_response()
    
    def _help_message(self) -> str:
        return """
🤖 *Available Commands:*

• Type "pricing" for pricing info
• Type "features" to see what we offer
• Type "contact" to reach our team
• Type "help" to see this message

Or just ask me anything! 💬
""".strip()
    
    def _pricing_message(self) -> str:
        return """
💰 *Our Pricing:*

• Starter: $9/month - 1,000 messages
• Pro: $29/month - 10,000 messages
• Enterprise: Custom pricing

All plans include:
✅ Unlimited contacts
✅ 24/7 support
✅ No setup fees

Reply "contact" to talk to sales!
""".strip()
    
    def _features_message(self) -> str:
        return """
✨ *Key Features:*

📱 Send messages, images, files
👥 Group management
📊 Analytics dashboard
🔒 Secure & encrypted
⚡ Lightning fast delivery
🌍 Global coverage

Want to learn more? Type "contact"
""".strip()
    
    def _handle_question(self, question: str) -> str:
        """Handle questions intelligently."""
        question_lower = question.lower()
        
        if any(word in question_lower for word in ['price', 'cost', 'pay', 'much']):
            return self._pricing_message()
        elif any(word in question_lower for word in ['do', 'can', 'feature', 'what']):
            return self._features_message()
        elif any(word in question_lower for word in ['contact', 'talk', 'speak', 'reach']):
            return self.keywords['contact']
        else:
            return "That's a great question! Type 'contact' to speak with our team who can help you better. 😊"
    
    def _default_response(self) -> str:
        return "Thanks for your message! Type 'help' to see what I can do, or 'contact' to reach our team. 💬"

Step 5: Message Handler

Create bot/message_handler.py

python
from typing import Dict, Any
from .whatsapp_client import WhatsAppClient
from .reply_engine import ReplyEngine

class MessageHandler:
    """
    Handles incoming WhatsApp messages and coordinates responses.
    """
    
    def __init__(self):
        self.client = WhatsAppClient()
        self.reply_engine = ReplyEngine()
    
    def process_incoming_message(self, webhook_data: Dict[str, Any]) -> None:
        """
        Process a webhook event from WhatsApp.
        
        Args:
            webhook_data: The webhook payload from WhatsApp API
        """
        try:
            # Extract message details
            event_type = webhook_data.get('event')
            
            if event_type != 'message':
                print(f"Ignoring non-message event: {event_type}")
                return
            
            payload = webhook_data.get('payload', {})
            message = payload.get('body', '')
            sender = payload.get('from', '')
            chat_id = payload.get('chat_id', sender)
            
            # Ignore messages from yourself (bot)
            if payload.get('fromMe', False):
                print("Ignoring message from bot itself")
                return
            
            print(f"📩 Received message from {sender}: {message}")
            
            # Generate reply
            reply_text = self.reply_engine.generate_reply(message, sender)
            
            # Send reply
            result = self.client.send_text_message(chat_id, reply_text)
            
            if 'error' in result:
                print(f"❌ Failed to send reply: {result['error']}")
            else:
                print(f"✅ Sent reply to {sender}: {reply_text[:50]}...")
                
        except Exception as e:
            print(f"❌ Error processing message: {e}")

Step 6: FastAPI Server

Create main.py

python
from fastapi import FastAPI, Request, HTTPException, Header
from fastapi.responses import JSONResponse
from typing import Optional
import uvicorn

from bot.message_handler import MessageHandler
from bot.whatsapp_client import WhatsAppClient
from config import get_settings

app = FastAPI(
    title="WhatsApp Chatbot API",
    description="A production-ready WhatsApp chatbot built with Python and FastAPI",
    version="1.0.0"
)

settings = get_settings()
message_handler = MessageHandler()
whatsapp_client = WhatsAppClient()

@app.get("/")
async def root():
    """Health check endpoint."""
    return {
        "status": "running",
        "message": "WhatsApp Chatbot API is live!",
        "version": "1.0.0"
    }

@app.post("/webhook")
async def webhook(request: Request, x_webhook_secret: Optional[str] = Header(None)):
    """
    Webhook endpoint to receive incoming WhatsApp messages.
    
    In production, validate the webhook secret for security.
    """
    # Validate webhook secret (production)
    if settings.webhook_secret and x_webhook_secret != settings.webhook_secret:
        raise HTTPException(status_code=401, detail="Invalid webhook secret")
    
    try:
        # Get webhook payload
        data = await request.json()
        
        # Process the message
        message_handler.process_incoming_message(data)
        
        return JSONResponse(
            status_code=200,
            content={"status": "success", "message": "Webhook processed"}
        )
    except Exception as e:
        print(f"Webhook error: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@app.post("/send-message")
async def send_message(chat_id: str, text: str):
    """
    Manually send a message to a WhatsApp contact.
    Useful for testing and admin operations.
    """
    result = whatsapp_client.send_text_message(chat_id, text)
    
    if 'error' in result:
        raise HTTPException(status_code=500, detail=result['error'])
    
    return {"status": "success", "data": result}

@app.get("/contacts")
async def get_contacts():
    """Get all WhatsApp contacts."""
    result = whatsapp_client.get_contacts()
    
    if 'error' in result:
        raise HTTPException(status_code=500, detail=result['error'])
    
    return {"status": "success", "data": result}

@app.post("/setup")
async def setup_session():
    """
    Create a WhatsApp session and get QR code for authentication.
    Scan the QR code with your WhatsApp to link the bot.
    """
    # Create session
    session_result = whatsapp_client.create_session()
    
    if 'error' in session_result:
        raise HTTPException(status_code=500, detail=session_result['error'])
    
    # Get QR code
    qr_code = whatsapp_client.get_qr_code()
    
    if not qr_code:
        raise HTTPException(status_code=500, detail="Failed to get QR code")
    
    return {
        "status": "success",
        "message": "Session created! Scan the QR code with WhatsApp.",
        "qr_code": qr_code,
        "instructions": "1. Open WhatsApp on your phone\n2. Go to Settings > Linked Devices\n3. Tap 'Link a Device'\n4. Scan the QR code"
    }

if __name__ == "__main__":
    uvicorn.run(
        "main:app",
        host=settings.host,
        port=settings.port,
        reload=settings.debug
    )

Step 7: Run Your Chatbot Locally

Initialize the Bot

Step 1: Start the server

bash
python main.py

You'll see:

INFO:     Uvicorn running on http://0.0.0.0:8000
INFO:     Application startup complete.

Step 2: Create your WhatsApp session

Open a new terminal and run:

bash
curl -X POST http://localhost:8000/setup

You'll get a QR code in the response. Scan it with WhatsApp (Settings → Linked Devices).

Step 3: Test the bot

Send a WhatsApp message to the phone number you linked. Try:

  • "hi"
  • "help"
  • "pricing"
  • "what features do you have?"

The bot will reply automatically! 🎉


Step 8: Advanced Features

Add AI-Powered Responses (OpenAI Integration)

bash
pip install openai

Update bot/reply_engine.py:

python
import openai
from config import get_settings

class ReplyEngine:
    def __init__(self):
        self.settings = get_settings()
        openai.api_key = self.settings.openai_api_key  # Add to .env
        # ... existing code ...
    
    def generate_ai_reply(self, message: str, sender: str) -> str:
        """Generate AI-powered reply using OpenAI."""
        try:
            response = openai.ChatCompletion.create(
                model="gpt-3.5-turbo",
                messages=[
                    {"role": "system", "content": "You are a helpful customer support chatbot."},
                    {"role": "user", "content": message}
                ],
                max_tokens=150,
                temperature=0.7
            )
            return response.choices[0].message.content
        except Exception as e:
            print(f"OpenAI error: {e}")
            return self._default_response()

Add Conversation History (SQLite)

bash
pip install sqlalchemy
python
# database.py
from sqlalchemy import create_engine, Column, Integer, String, Text, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from datetime import datetime

Base = declarative_base()

class Conversation(Base):
    __tablename__ = 'conversations'
    
    id = Column(Integer, primary_key=True)
    chat_id = Column(String(50), index=True)
    sender = Column(String(50))
    message = Column(Text)
    reply = Column(Text)
    created_at = Column(DateTime, default=datetime.utcnow)

engine = create_engine('sqlite:///chatbot.db')
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)

Step 9: Deploy to Production

Option 1: Deploy to Heroku

bash
# Create Procfile
echo "web: uvicorn main:app --host 0.0.0.0 --port \$PORT" > Procfile

# Create runtime.txt
echo "python-3.11.0" > runtime.txt

# Deploy
heroku create my-whatsapp-bot
git push heroku main

Option 2: Deploy to Railway

  1. 1.Push code to GitHub
  2. 2.Go to Railway.app
  3. 3.Click "New Project" → "Deploy from GitHub"
  4. 4.Select your repository
  5. 5.Add environment variables
  6. 6.Deploy!

Option 3: Deploy to DigitalOcean

bash
# Install Docker
docker build -t whatsapp-chatbot .
docker run -p 8000:8000 whatsapp-chatbot

Dockerfile:

dockerfile
FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 8000

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Common Use Cases & Examples

1. Customer Support Bot

python
class CustomerSupportEngine(ReplyEngine):
    def generate_reply(self, message_text: str, sender: str) -> str:
        message_lower = message_text.lower()
        
        if 'order' in message_lower and 'status' in message_lower:
            return "Please provide your order number (e.g., #12345)"
        elif 'refund' in message_lower:
            return "I can help with refunds. Reply with your order number."
        elif 'track' in message_lower:
            return "To track your order, visit: https://example.com/track"
        
        return super().generate_reply(message_text, sender)

2. Lead Capture Bot

python
class LeadCaptureEngine(ReplyEngine):
    def generate_reply(self, message_text: str, sender: str) -> str:
        if message_text.startswith('/'):
            command = message_text
            
            if command == '/start':
                return "Welcome! What's your name?"
            elif command == '/email':
                return "What's your email address?"
            elif command == '/demo':
                return "Great! Our team will contact you within 24 hours."
        
        # Store lead data in database
        # ...
        
        return "Thanks! Type /demo to request a demo."

3. E-commerce Order Bot

python
def handle_ecommerce(message: str) -> str:
    if 'price' in message.lower():
        return "Our products range from $10-$100. Browse at: https://shop.example.com"
    elif 'buy' in message.lower() or 'purchase' in message.lower():
        return "📦 To order:\n1. Visit https://shop.example.com\n2. Add to cart\n3. We'll confirm via WhatsApp!"
    else:
        return "We sell amazing products! Type 'price' to see pricing or 'buy' to order."

Performance & Scaling

Handle High Message Volume

python
# Use async for better performance
from fastapi import BackgroundTasks

@app.post("/webhook")
async def webhook(request: Request, background_tasks: BackgroundTasks):
    data = await request.json()
    
    # Process in background
    background_tasks.add_task(message_handler.process_incoming_message, data)
    
    return {"status": "accepted"}

Add Rate Limiting

bash
pip install slowapi
python
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address

limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter

@app.post("/webhook")
@limiter.limit("100/minute")
async def webhook(request: Request):
    # ... existing code ...

Monitoring & Analytics

Track Bot Performance

python
# Add to message_handler.py
import time

class MessageHandler:
    def __init__(self):
        self.client = WhatsAppClient()
        self.reply_engine = ReplyEngine()
        self.stats = {
            'total_messages': 0,
            'responses_sent': 0,
            'avg_response_time': 0
        }
    
    def process_incoming_message(self, webhook_data: Dict[str, Any]) -> None:
        start_time = time.time()
        
        # ... process message ...
        
        self.stats['total_messages'] += 1
        self.stats['responses_sent'] += 1
        
        response_time = time.time() - start_time
        self.stats['avg_response_time'] = (
            (self.stats['avg_response_time'] * (self.stats['total_messages'] - 1) + response_time)
            / self.stats['total_messages']
        )

Troubleshooting

Common Issues

1. Bot not responding to messages

  • Check if webhook URL is correctly configured
  • Verify your API key is correct
  • Ensure the session is active (QR code scanned)

2. "Session not found" error

  • Run the /setup endpoint again
  • Scan the QR code with WhatsApp

3. Messages delayed

  • Check your server's internet connection
  • Verify RapidAPI rate limits
  • Consider upgrading your plan

4. Webhook not receiving events

  • Ensure your server is publicly accessible (use ngrok for local testing)
  • Check firewall settings
  • Verify webhook secret matches

Next Steps

Enhance your chatbot:

  1. 1.Add NLP - Integrate with DialogFlow or Rasa
  2. 2.Add Database - Store conversation history with PostgreSQL
  3. 3.Add Analytics - Track user behavior with Mixpanel
  4. 4.Add Payments - Integrate Stripe for transactions
  5. 5.Add Multi-language - Support multiple languages
  6. 6.Add Media Handling - Process images, PDFs, etc.

Production Checklist:

  • [ ] Add authentication for admin endpoints
  • [ ] Set up logging (Sentry, LogDNA)
  • [ ] Configure webhook secret validation
  • [ ] Add rate limiting
  • [ ] Set up monitoring (Uptime Robot, Pingdom)
  • [ ] Configure backups for database
  • [ ] Add SSL certificate
  • [ ] Test with high message volume

Conclusion

You've just built a production-ready WhatsApp chatbot in Python! 🎉

What you accomplished:

  • ✅ FastAPI server with webhook handling
  • ✅ Intelligent reply engine with keyword matching
  • ✅ WhatsApp API integration
  • ✅ Production deployment guide
  • ✅ Scalable architecture

Total setup time: ~30 minutes Total cost: ~$0.001 per message (vs $0.01 for SMS) Approval time: 0 seconds (vs weeks with Meta)


Start Building Today

Ready to launch your WhatsApp chatbot?

👉 Get your free RapidAPI key and send your first message in 5 minutes.

What's included:

  • 100 free messages to test
  • No credit card required
  • Full API access
  • 24/7 support

Related tutorials:


Questions? Drop a comment below or reach out on Twitter / X.

Happy coding! 🐍⚡

Ready to Get Started?

Try the WhatsApp API free on RapidAPI with no credit card required.

Try Free on RapidAPI