--- title: Build a WhatsApp AI Agent with Next.js and Zavu description: Learn how to build an AI-powered WhatsApp agent using Next.js and Zavu's managed AI Gateway. date: 2025-12-23 author: Victor Villalobos locale: en source: https://www.zavu.dev/en/blog/whatsapp-ai-agents-nextjs tags: AI Agents, WhatsApp, Next.js, App Router --- # Build a WhatsApp AI Agent with Next.js and Zavu In this tutorial, you'll build a production-ready WhatsApp AI agent using Next.js App Router 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 Next.js application that: - Receives incoming WhatsApp messages via Route Handlers - Verifies webhook signatures for security - Uses Zavu's managed AI agents for intelligent responses - Leverages Next.js App Router and Server Actions - Automatically maintains conversation context ## Prerequisites - Node.js 18+ - A Zavu account with API credentials - Basic React and TypeScript knowledge **No external AI API keys required!** Zavu's AI Gateway provides access to all major AI models through a single integration. ## Installation Create a new Next.js project or add to an existing one: Choose your package manager: **Bun (recommended)**: ```bash bun install @zavudev/sdk ``` **npm**: ```bash npm install @zavudev/sdk ``` **pnpm**: ```bash pnpm add @zavudev/sdk ``` Then create the project: ```bash npx create-next-app@latest whatsapp-agent cd whatsapp-agent ``` When prompted, select: - TypeScript: Yes - ESLint: Yes - App Router: Yes - Src directory: Yes - Import alias: @/* ## Project Structure ``` whatsapp-agent/ ├── src/ │ ├── app/ │ │ ├── api/ │ │ │ └── webhook/ │ │ │ └── route.ts │ │ └── page.tsx │ └── lib/ │ └── zavu.ts ├── .env.local └── package.json ``` ## Environment Configuration Create a `.env.local` file in your project root: ```bash ZAVUDEV_API_KEY=your_zavu_api_key ZAVU_WEBHOOK_SECRET=your_webhook_secret ``` That's it! No OpenAI, Anthropic, or other AI provider keys needed. ## 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 You can configure which model to use directly in your Zavu dashboard. ## Initialize the Zavu Client Create `src/lib/zavu.ts`: ```typescript import Zavudev from '@zavudev/sdk'; export const zavu = new Zavu({ apiKey: process.env.ZAVUDEV_API_KEY, }); ``` ## Create the Webhook Route Handler Create `src/app/api/webhook/route.ts`: ```typescript import { NextRequest, NextResponse } from 'next/server'; import crypto from 'crypto'; import { zavu } from '@/lib/zavu'; function verifyWebhookSignature(payload: string, signature: string): boolean { const secret = process.env.ZAVU_WEBHOOK_SECRET; if (!signature || !secret) { return false; } const expected = crypto .createHmac('sha256', secret) .update(payload) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(`sha256=${expected}`), Buffer.from(signature) ); } export async function POST(request: NextRequest) { try { const rawBody = await request.text(); const signature = request.headers.get('x-zavu-signature') || ''; if (!verifyWebhookSignature(rawBody, signature)) { console.error('Invalid webhook signature'); return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const payload = JSON.parse(rawBody); const eventType = payload.type; console.log(`Received webhook event: ${eventType}`); if (eventType === 'message.inbound') { const message = payload.data; console.log(`Message from ${message.from}: ${message.text}`); } return NextResponse.json({ status: 'ok' }); } catch (error) { console.error('Webhook error:', error); return NextResponse.json( { error: 'Internal server error' }, { status: 500 } ); } } ``` ## Deploy and Configure 1. Deploy your Next.js app to Vercel or any platform with HTTPS 2. Configure the webhook in your Zavu dashboard: - Go to **Senders** > Select your sender > **Webhook** - Set URL to: `https://yourdomain.com/api/webhook` - Enable events: `message.inbound` - Copy the webhook secret to your `.env.local` file 3. Create an AI agent for your sender in the Zavu dashboard 4. Deploy your app: ```bash npm run build npm start ``` ## Testing Locally For local testing, use ngrok: ```bash npx ngrok http 3000 ``` Copy the HTTPS URL and configure it in your Zavu webhook settings. ## Create a Managed AI Agent ### Option 1: Via Zavu Dashboard 1. Go to **Senders** in your Zavu dashboard 2. Select the sender you want to add AI capabilities to 3. Click on **AI Agent** tab 4. Configure your agent and save ### Option 2: Via Server Actions Create a server action at `src/app/actions/agent.ts`: ```typescript 'use server'; import { zavu } from '@/lib/zavu'; import { revalidatePath } from 'next/cache'; export async function createAgent(formData: FormData) { const senderId = formData.get('senderId') as string; const name = formData.get('name') as string; const systemPrompt = formData.get('systemPrompt') as string; const response = await zavu.senders.agent.create({ senderId, name, provider: 'zavu', model: 'gpt-4o-mini', systemPrompt, contextWindowMessages: 10, includeContactMetadata: true, enabled: true }); revalidatePath('/dashboard'); return response.agent; } export async function getAgentStats(senderId: string) { const response = await zavu.senders.agent.stats(senderId); return response; } ``` ## Knowledge Bases Create a server action for knowledge bases at `src/app/actions/knowledge-base.ts`: ```typescript 'use server'; import { zavu } from '@/lib/zavu'; export async function createKnowledgeBase(formData: FormData) { const senderId = formData.get('senderId') as string; const name = formData.get('name') as string; const description = formData.get('description') as string; const response = await zavu.senders.agent.knowledgeBases.create({ senderId, name, description }); return response.knowledgeBase; } export async function addDocument(formData: FormData) { const senderId = formData.get('senderId') as string; const kbId = formData.get('kbId') as string; const title = formData.get('title') as string; const content = formData.get('content') as string; const response = await zavu.senders.agent.knowledgeBases.documents.create({ senderId, kbId, title, content }); return response.document; } ``` ## Custom Tools Create a tool endpoint at `src/app/api/tools/order-status/route.ts`: ```typescript import { NextRequest, NextResponse } from 'next/server'; export async function POST(request: NextRequest) { try { const body = await request.json(); const { order_id } = body; const orderStatus = await getOrderFromDatabase(order_id); return NextResponse.json({ success: true, data: { order_id: order_id, status: orderStatus.status, estimated_delivery: orderStatus.delivery_date, tracking_url: orderStatus.tracking_url } }); } catch (error) { console.error('Tool error:', error); return NextResponse.json( { success: false, error: 'Internal server error' }, { status: 500 } ); } } async function getOrderFromDatabase(orderId: string) { return { status: 'shipped', delivery_date: '2024-01-20', tracking_url: 'https://tracker.example.com/ORD-12345' }; } ``` Create the tool via server action: ```typescript // src/app/actions/tools.ts 'use server'; import { zavu } from '@/lib/zavu'; export async function createOrderStatusTool(formData: FormData) { const senderId = formData.get('senderId') as string; const webhookUrl = `https://${process.env.VERCEL_URL || 'localhost:3000'}/api/tools/order-status`; const response = await zavu.senders.agent.tools.create({ senderId, name: 'get_order_status', description: 'Get the current status of a customer order', webhookUrl, parameters: { type: 'object', properties: { order_id: { type: 'string', description: 'The order ID to look up' } }, required: ['order_id'] } }); return response.tool; } ``` ## Using Your Own AI Credentials (Optional) If you prefer to use your own AI provider credentials: 1. Go to **Settings** > **AI Providers** in your Zavu dashboard 2. Add your API keys for OpenAI, Anthropic, Google, or Mistral 3. When creating an agent, use `provider: "openai"` instead of `provider: "zavu"` This gives you full control over billing while still benefiting from Zavu's unified API. ## 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 a dashboard UI to manage your agents Check out the [Zavu documentation](https://docs.zavu.dev) for more examples and advanced features.