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.

Published: 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:

| Feature | Python | Node.js | PHP | |---------|--------|---------|-----| | Learning Curve | Easy | Moderate | Easy | | Async Support | ✅ (asyncio, FastAPI) | ✅ (native) | ⚠️ (limited) | | AI/ML Integration | 🏆 Best | Good | Limited | | Deployment | Easy | Easy | Easy | | Community | Huge | Huge | Large |


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. FastAPI Server: Receives webhook events 2. Message Handler: Processes incoming messages 3. Reply Engine: Generates and sends responses 4. Session Manager: Maintains conversation state 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. Push code to GitHub 2. Go to Railway.app 3. Click "New Project" → "Deploy from GitHub" 4. Select your repository 5. Add environment variables 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. Add NLP - Integrate with DialogFlow or Rasa 2. Add Database - Store conversation history with PostgreSQL 3. Add Analytics - Track user behavior with Mixpanel 4. Add Payments - Integrate Stripe for transactions 5. Add Multi-language - Support multiple languages 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