AI AgentsWhatsAppFastifyNode.js

Build a WhatsApp AI Agent with Fastify and Zavu

Learn how to build an AI-powered WhatsApp agent using Fastify and Zavu's managed AI Gateway. No external API keys required - access GPT-4, Claude, and more through Zavu.

Written by: Jennifer VillalobosReviewed by: Victor VillalobosDecember 23, 202510 min read

Build a WhatsApp AI Agent with Fastify and Zavu

In this tutorial, you'll build a production-ready WhatsApp AI agent using Fastify 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 Fastify application that:
  • Receives incoming WhatsApp messages via webhooks
  • Verifies webhook signatures for security
  • Uses Zavu's managed AI agents for intelligent responses
  • Leverages Fastify's built-in schema validation
  • Automatically maintains conversation context

Prerequisites

  • Node.js 18+
  • A Zavu account with API credentials
  • Basic JavaScript/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 project and install dependencies:

Choose your package manager:

Bun (recommended):
bash
bun install @zavudev/sdk fastify @fastify/env dotenv
npm:
bash
npm install @zavudev/sdk fastify @fastify/env dotenv
pnpm:
bash
pnpm add @zavudev/sdk fastify @fastify/env dotenv

Then create the project:

bash
mkdir whatsapp-agent && cd whatsapp-agent npm init -y

Project Structure

text
whatsapp-agent/ ├── src/ │ ├── app.js │ ├── routes/ │ │ └── webhook.js │ └── zavu.js ├── .env └── package.json

Environment Configuration

Create a .env file in your project root:

bash
ZAVUDEV_API_KEY=your_zavu_api_key ZAVU_WEBHOOK_SECRET=your_webhook_secret PORT=3000

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, and optionally add your own API keys if you prefer to use your own credentials for billing purposes.

Initialize the Zavu Client

Create src/zavu.js:

javascript
import Zavudev from '@zavudev/sdk'; export const zavu = new Zavu({ apiKey: process.env.ZAVUDEV_API_KEY, });

Create the Fastify App

Create src/app.js:

javascript
import Fastify from 'fastify'; import dotenv from 'dotenv'; import { webhookRoutes } from './routes/webhook.js'; import { zavu } from './zavu.js'; dotenv.config(); const fastify = Fastify({ logger: true, }); // Register routes fastify.register(webhookRoutes, { zavu }); // Health check fastify.get('/health', async () => { return { status: 'healthy' }; }); // Start server const start = async () => { try { const PORT = process.env.PORT || 3000; await fastify.listen({ port: PORT, host: '0.0.0.0' }); console.log(Server running on port ${PORT}); } catch (err) { fastify.log.error(err); process.exit(1); } }; start();

Create the Webhook Route

Create src/routes/webhook.js:

javascript
import crypto from 'crypto'; export async function webhookRoutes(fastify, options) { const { zavu } = options; // Schema for webhook validation const webhookSchema = { headers: { type: 'object', properties: { 'x-zavu-signature': { type: 'string' } }, required: ['x-zavu-signature'] }, body: { type: 'object', properties: { type: { type: 'string' }, data: { type: 'object' } }, required: ['type'] } }; // Helper function to verify webhook signature function verifyWebhookSignature(payload, signature) { 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) ); } // Webhook endpoint fastify.post('/webhook', { schema: webhookSchema, config: { rawBody: true // Keep raw body for signature verification } }, async (request, reply) => { const signature = request.headers['x-zavu-signature']; const rawBody = request.raw.body; // Verify webhook signature if (!verifyWebhookSignature(rawBody, signature)) { fastify.log.warn('Invalid webhook signature'); return reply.status(401).send({ error: 'Unauthorized' }); } try { const payload = request.body; const eventType = payload.type; fastify.log.info(Received webhook event: ${eventType}); // Handle different event types if (eventType === 'message.inbound') { const message = payload.data; fastify.log.info(Message from ${message.from}: ${message.text}); } return { status: 'ok' }; } catch (error) { fastify.log.error('Webhook error:', error); return reply.status(500).send({ error: 'Internal server error' }); } }); }

Update package.json

Add a start script to package.json:

json
{ "type": "module", "scripts": { "start": "node src/app.js", "dev": "node --watch src/app.js" } }

Deploy and Configure

  • Deploy your Fastify app to a server with HTTPS (required for webhooks)
  • Configure the webhook in your Zavu dashboard:
  • - Go to Senders > Select your sender > Webhook - Set URL to: https://yourdomain.com/webhook - Enable events: message.inbound - Copy the webhook secret to your .env file
  • Create an AI agent for your sender in the Zavu dashboard
  • Run the server:
  • bash
    npm start

    Testing Locally with ngrok

    For local development, use ngrok to expose your server:

    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

  • Go to Senders in your Zavu dashboard
  • Select the sender you want to add AI capabilities to
  • Click on AI Agent tab
  • Configure your agent and save
  • Option 2: Via JavaScript SDK

    javascript
    import { zavu } from './zavu.js'; async function createAIAgent(senderId, name, systemPrompt, model = 'gpt-4o-mini') { const response = await zavu.senders.agent.create({ senderId: senderId, name: name, provider: 'zavu', model: model, systemPrompt: systemPrompt, contextWindowMessages: 10, includeContactMetadata: true, enabled: true }); return response.agent; } // Usage const agent = await createAIAgent( 'sender_abc123', 'Customer Support Bot', 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 ); console.log(Agent created: ${agent.id});

    Knowledge Bases

    Create RAG-powered responses by uploading documents.

    javascript
    import { zavu } from './zavu.js'; // Create knowledge base const kb = await zavu.senders.agent.knowledgeBases.create({ senderId: 'sender_abc123', name: 'Product FAQ', description: 'Frequently asked questions about our products' }); // Add documents await zavu.senders.agent.knowledgeBases.documents.create({ senderId: 'sender_abc123', kbId: 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 }); console.log(Knowledge base created: ${kb.id});

    Custom Tools

    Connect external APIs to extend your agent's capabilities.

    javascript
    import { zavu } from './zavu.js'; // Create a tool const tool = await zavu.senders.agent.tools.create({ senderId: 'sender_abc123', name: 'get_order_status', description: 'Get the current status of a customer order', webhookUrl: 'https://yourdomain.com/api/tools/order-status', webhookSecret: 'your_tool_webhook_secret', parameters: { type: 'object', properties: { order_id: { type: 'string', description: 'The order ID to look up' } }, required: ['order_id'] } }); console.log(Tool created: ${tool.id});

    Then create the tool endpoint with Fastify:

    javascript
    // In your routes file fastify.post('/api/tools/order-status', { schema: { body: { type: 'object', properties: { order_id: { type: 'string' } }, required: ['order_id'] } } }, async (request, reply) => { const { order_id } = request.body; // Call your internal API/service const orderStatus = await getOrderFromDatabase(order_id); return { success: true, data: { order_id: order_id, status: orderStatus.status, estimated_delivery: orderStatus.delivery_date, tracking_url: orderStatus.tracking_url } }; });

    Using Your Own AI Credentials (Optional)

    If you prefer to use your own AI provider credentials:

  • Go to Settings > AI Providers in your Zavu dashboard
  • Add your API keys for OpenAI, Anthropic, Google, or Mistral
  • When creating an agent, use provider: "openai" instead of provider: "zavu"
  • 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
    Check out the Zavu documentation for more examples and advanced features.

    Need help? Contact us or join our Discord community for support.

    Follow us on social media

    See it in action

    Book a personalized demo to see how Zavu AI Agents can transform your customer communication.

    Build a WhatsApp AI Agent with Fastify and Zavu | Zavu Blog | Zavu