Build a WhatsApp AI Agent with Django and Zavu
In this tutorial, you'll build a production-ready WhatsApp AI agent using Django and Zavu. The best part? You don't need to manage any external AI API keys - Zavu's AI Gateway gives you access to all top-tier AI models (GPT-4, Claude, Gemini, Mistral, and more) directly from your Zavu dashboard.
What We're Building
A Django application that:- Receives incoming WhatsApp messages via webhooks
- Verifies webhook signatures for security
- Uses Zavu's managed AI agents for intelligent responses
- Automatically maintains conversation context
Prerequisites
- Python 3.9+
- A Zavu account with API credentials
- Basic Django knowledge
Installation
Create a new Django project and install dependencies:
bashmkdir whatsapp-agent && cd whatsapp-agent python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate pip install django zavudev python-dotenv django-admin startproject config . python manage.py startapp agent
Project Structure
textwhatsapp-agent/ ├── config/ │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── agent/ │ ├── views.py │ ├── urls.py │ └── services.py ├── .env └── manage.py
Environment Configuration
Create a .env file in your project root:
bashZAVUDEV_API_KEY=your_zavu_api_key ZAVU_WEBHOOK_SECRET=your_webhook_secret
That's it! No OpenAI, Anthropic, or other AI provider keys needed.
Update config/settings.py:
pythonimport os from dotenv import load_dotenv load_dotenv() INSTALLED_APPS = [ # ... default apps 'agent', ] ZAVUDEV_API_KEY = os.environ.get('ZAVUDEV_API_KEY') ZAVU_WEBHOOK_SECRET = os.environ.get('ZAVU_WEBHOOK_SECRET')
How Zavu AI Gateway Works
Zavu provides a unified AI Gateway that gives you access to all top-tier AI models without managing individual API keys:
- GPT-4o, GPT-4o-mini - OpenAI's latest models
- Claude 3.5 Sonnet, Claude 3 Opus - Anthropic's models
- Gemini Pro - Google's AI models
- Mistral Large - Mistral AI's models
Create a Managed AI Agent
The easiest way to add AI capabilities is through Zavu's managed agents. You have two options:
Option 1: Via Zavu Dashboard
Create an agent for your sender directly in the Zavu Dashboard:
With the zavu provider, all AI processing is handled by Zavu's managed gateway. Your agent will automatically respond to incoming WhatsApp messages without any additional code!
Option 2: Via Python SDK
You can also create and configure AI agents programmatically using the zavudev SDK. Add these helper functions to agent/services.py:
pythondef create_ai_agent(sender_id: str, name: str, system_prompt: str, model: str = "gpt-4o-mini") -> dict: """Create an AI agent for a sender using Zavu's AI Gateway.""" response = zavu_client.senders.agent.create( sender_id=sender_id, name=name, provider="zavu", # Use Zavu's AI Gateway (no external API keys needed) model=model, system_prompt=system_prompt, context_window_messages=10, # Include last 10 messages for context include_contact_metadata=True, # Include contact info in context enabled=True ) return response.agent def get_agent_stats(sender_id: str) -> dict: """Get statistics for an AI agent.""" response = zavu_client.senders.agent.stats(sender_id) return response def list_agent_executions(sender_id: str, limit: int = 50) -> list: """List recent agent executions.""" response = zavu_client.senders.agent.executions.list( sender_id=sender_id, limit=limit ) return response.items
Now you can create an agent from Django code:
Note: When usingpython# Example: Create an agent from a Django management command or view from .services import create_ai_agent agent = create_ai_agent( sender_id="sender_abc123", name="Customer Support Bot", model="gpt-4o-mini", system_prompt="""You are a helpful customer support assistant for Zavu. Rules: - Be friendly and concise - Help with WhatsApp, SMS, and email messaging questions - If unsure, offer to connect with a human agent - Respond in the same language as the customer""" ) print(f"Agent created: {agent['id']}")
provider="zavu", Zavu's AI Gateway handles all AI model access. No external API keys needed!Available AI Models
When creating an agent, you can choose from these models:
| Provider | Models |
|---|
| OpenAI | gpt-4o, gpt-4o-mini, gpt-4-turbo |
|---|---|
| Anthropic | claude-3-5-sonnet, claude-3-opus, claude-3-haiku |
| gemini-pro, gemini-1.5-pro | |
| Mistral | mistral-large, mistral-medium |
Initialize the Zavu Client
Create agent/services.py:
pythonimport os import hmac import hashlib from zavudev import Zavudev zavu_client = Zavudev(api_key=os.environ.get('ZAVUDEV_API_KEY')) def verify_webhook_signature(payload: bytes, signature: str) -> bool: """Verify the webhook signature from Zavu.""" secret = os.environ.get('ZAVU_WEBHOOK_SECRET', '') if not signature or not secret: return False expected = hmac.new( secret.encode('utf-8'), payload, hashlib.sha256 ).hexdigest() return hmac.compare_digest(f"sha256={expected}", signature) def send_whatsapp_message(to: str, text: str) -> dict: """Send a WhatsApp message using Zavu.""" response = zavu_client.messages.send( to=to, text=text, channel="whatsapp" ) return response.message
Create the Webhook View
Create agent/views.py:
pythonimport json import logging from django.http import JsonResponse, HttpResponse from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_POST from .services import verify_webhook_signature, send_whatsapp_message logger = logging.getLogger(__name__) @csrf_exempt @require_POST def webhook(request): """Handle incoming WhatsApp messages from Zavu.""" signature = request.headers.get('X-Zavu-Signature', '') if not verify_webhook_signature(request.body, signature): logger.warning("Invalid webhook signature") return HttpResponse(status=401) try: payload = json.loads(request.body) except json.JSONDecodeError: return JsonResponse({"error": "Invalid JSON"}, status=400) event_type = payload.get('type') logger.info(f"Received webhook event: {event_type}") return JsonResponse({"status": "ok"})
With a managed AI agent configured, Zavu automatically handles the AI response. The webhook is primarily for logging or custom business logic.
Configure URLs
Create agent/urls.py:
pythonfrom django.urls import path from . import views urlpatterns = [ path('webhook/', views.webhook, name='webhook'), ]
Update config/urls.py:
pythonfrom django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('api/', include('agent.urls')), ]
Deploy and Configure
https://yourdomain.com/api/webhook/ - Enable events: message.inbound - Copy the webhook secret to your .env filebashpython manage.py runserver 0.0.0.0:8000
Testing Locally with ngrok
For local development, use ngrok to expose your server:
bashngrok http 8000
Copy the HTTPS URL and configure it in your Zavu webhook settings.
Managed Agent Features
Zavu's AI agents come with powerful built-in features, all configurable through the dashboard:
Knowledge Bases
Create RAG-powered responses by uploading documents to give your agent domain-specific knowledge.
#### Via Dashboard
#### Via Python SDK
You can also manage knowledge bases programmatically. Add these functions to agent/services.py:
pythondef create_knowledge_base(sender_id: str, name: str, description: str = None) -> dict: """Create a new knowledge base for an agent.""" response = zavu_client.senders.agent.knowledge_bases.create( sender_id=sender_id, name=name, description=description ) return response.knowledge_base def add_document_to_kb(sender_id: str, kb_id: str, title: str, content: str) -> dict: """Add a document to a knowledge base.""" response = zavu_client.senders.agent.knowledge_bases.documents.create( sender_id=sender_id, kb_id=kb_id, title=title, content=content ) return response.document def list_kb_documents(sender_id: str, kb_id: str, limit: int = 50) -> list: """List documents in a knowledge base.""" response = zavu_client.senders.agent.knowledge_bases.documents.list( sender_id=sender_id, kb_id=kb_id, limit=limit ) return response.items def delete_kb_document(sender_id: str, kb_id: str, doc_id: str) -> None: """Delete a document from a knowledge base.""" zavu_client.senders.agent.knowledge_bases.documents.delete( sender_id=sender_id, kb_id=kb_id, doc_id=doc_id )
Example usage:
pythonfrom .services import create_knowledge_base, add_document_to_kb # Create a knowledge base kb = create_knowledge_base( sender_id="sender_abc123", name="Product FAQ", description="Frequently asked questions about our products" ) # Add documents to the knowledge base add_document_to_kb( sender_id="sender_abc123", kb_id=kb['id'], title="Return Policy", content="""Our return policy allows returns within 30 days of purchase. Items must be: - In original condition - With receipt or proof of purchase - Not used or damaged To process a return, contact support@example.com""" ) add_document_to_kb( sender_id="sender_abc123", kb_id=kb['id'], title="Shipping Information", content="""We offer free shipping on orders over $50. Standard shipping: 5-7 business days Express shipping: 2-3 business days Overnight shipping: Next business day""" ) print(f"Knowledge base created: {kb['id']}")
The agent will automatically use this knowledge to answer customer questions about returns and shipping.
Custom Tools
Connect external APIs to extend your agent's capabilities by creating tools that the AI can call.
#### Via Dashboard
#### Via Python SDK
You can also create tools programmatically. Add these functions to agent/services.py:
pythondef create_tool( sender_id: str, name: str, description: str, webhook_url: str, parameters: dict, webhook_secret: str = None ) -> dict: """Create a tool for an agent.""" response = zavu_client.senders.agent.tools.create( sender_id=sender_id, name=name, description=description, webhook_url=webhook_url, webhook_secret=webhook_secret, # Optional signature verification parameters=parameters ) return response.tool def list_tools(sender_id: str, enabled: bool = None) -> list: """List tools for an agent.""" response = zavu_client.senders.agent.tools.list( sender_id=sender_id, enabled=enabled ) return response.items def test_tool(sender_id: str, tool_id: str, test_params: dict) -> bool: """Test a tool with sample parameters.""" response = zavu_client.senders.agent.tools.test( sender_id=sender_id, tool_id=tool_id, test_params=test_params ) return response.scheduled
Example usage:
pythonfrom .services import create_tool # Create a tool to check order status tool = create_tool( sender_id="sender_abc123", name="get_order_status", description="Get the current status of a customer order", webhook_url="https://yourdomain.com/api/tools/order-status", webhook_secret="your_tool_webhook_secret", parameters={ "type": "object", "properties": { "order_id": { "type": "string", "description": "The order ID to look up" } }, "required": ["order_id"] } ) print(f"Tool created: {tool['id']}")
Then create an endpoint to handle tool invocations:
python# agent/views.py @csrf_exempt @require_POST def tool_webhook(request, tool_id): """Handle tool calls from the AI agent.""" import json import hmac import hashlib # Verify tool webhook signature signature = request.headers.get('X-Zavu-Tool-Signature', '') secret = os.environ.get('ZAVU_TOOL_WEBHOOK_SECRET', '') if signature and secret: expected = hmac.new( secret.encode('utf-8'), request.body, hashlib.sha256 ).hexdigest() if not hmac.compare_digest(f"sha256={expected}", signature): return HttpResponse(status=401) try: payload = json.loads(request.body) order_id = payload.get('order_id') # Call your internal API/service order_status = get_order_from_database(order_id) return JsonResponse({ "success": True, "data": { "order_id": order_id, "status": order_status.status, "estimated_delivery": order_status.delivery_date, "tracking_url": order_status.tracking_url } }) except Exception as e: logger.error(f"Tool error: {e}") return JsonResponse({ "success": False, "error": str(e) }, status=500)
Now when a customer asks "Where's my order ORD-12345?", the AI will automatically call your tool with the order ID and provide the response.
Conversation Flows
Build guided conversation paths for specific workflows through the dashboard flow builder.
Analytics
Track token usage, costs, and performance metrics directly in your Zavu dashboard under the Analytics section.
Using Your Own AI Credentials (Optional)
If you prefer to use your own AI provider credentials for billing purposes, you can configure them in your Zavu dashboard:
provider: "openai" (or your preferred provider) instead of provider: "zavu"This gives you full control over billing while still benefiting from Zavu's unified API and conversation management.
Custom Webhook Logic (Advanced)
If you need custom processing alongside the AI agent, you can add logic in your webhook:
python@csrf_exempt @require_POST def webhook(request): """Handle incoming WhatsApp messages from Zavu.""" signature = request.headers.get('X-Zavu-Signature', '') if not verify_webhook_signature(request.body, signature): return HttpResponse(status=401) try: payload = json.loads(request.body) except json.JSONDecodeError: return JsonResponse({"error": "Invalid JSON"}, status=400) if payload.get('type') == 'message.inbound': message = payload.get('data', {}) sender = message.get('from') text = message.get('text', '') logger.info(f"Message from {sender}: {text}") if text.lower() == 'human': send_whatsapp_message( to=sender, text="Connecting you with a human agent..." ) return JsonResponse({"status": "ok"})
Next Steps
- Explore the AI Agents dashboard to monitor conversations
- Add knowledge bases for domain-specific responses
- Create custom tools to integrate with your backend systems
- Build conversation flows for specific use cases
- Add support for media messages (images, documents)