Dev.to AI πŸ€– Ai πŸ‘ 0 πŸ“– 6 min read

Building a WhatsApp AI Agent with Gemini Using Gemini as Your Copilot

What you'll build: A WhatsApp number that replies with an AI agent powered by Google Gemini. You'll use Gemini (via the Gemini CLI or Gemini Code Assist in your IDE) as your pair-programming copilot to scaffold, debug, a

What you'll build: A WhatsApp number that replies with an AI agent powered by Google Gemini. You'll use Gemini (via the Gemini CLI or Gemini Code Assist in your IDE) as your pair-programming copilot to scaffold, debug, and extend the code, so Gemini is both the agent's runtime brain and the assistant building it.

How the pieces fit together

WhatsApp user
     β”‚  message
     β–Ό
Meta WhatsApp Cloud API  ──webhook POST──►  Your server (Flask)
     β–²                                            β”‚
     β”‚  send reply (Graph API)                    β–Ό
     └──────────────────────────────────  Gemini API (the "brain")

Two moving parts:

  • WhatsApp Cloud API (Meta) β€” receives inbound messages via a webhook and sends replies via the Graph API. Free tier available.
  • Gemini API (Google) β€” generates the agent's responses.

Two hats for Gemini: at runtime, the Gemini API generates replies to WhatsApp users. While building, you use Gemini as your coding copilot β€” the Gemini CLI (npm install -g @google/gemini-cli, then run gemini) in your terminal, or Gemini Code Assist inside VS Code / JetBrains. You describe what you want in plain English, and it writes, explains, and fixes the code below.

Prerequisites

  • Python 3.10+
  • A Meta for Developers account (free)
  • A Google AI Studio API key for Gemini (free tier available)
  • ngrok or similar, to expose your local server to Meta's webhook
  • The Gemini CLI installed (npm install -g @google/gemini-cli) or Gemini Code Assist enabled in your IDE, open alongside your editor

Step 1 β€” Get your Gemini API key

  1. Go to aistudio.google.com β†’ Get API key.
  2. Copy the key somewhere safe.

Ask Gemini: "Explain what a Gemini API key can access and how to store it safely as an environment variable."

Step 2 β€” Set up WhatsApp Cloud API

  1. In Meta for Developers, create an app β†’ type Business.
  2. Add the WhatsApp product. Meta gives you a test phone number and a temporary access token.
  3. Note these three values from the WhatsApp β†’ API Setup page:
    • Phone number ID
    • Temporary access token (valid 24h; swap for a permanent System User token later)
    • App secret (App Settings β†’ Basic)
  4. Add your own number as a recipient so you can test.

Ask Gemini: "Walk me through creating a permanent WhatsApp access token with a System User in Meta Business Suite."

Step 3 β€” Project setup

mkdir whatsapp-gemini-agent && cd whatsapp-gemini-agent
python -m venv .venv && source .venv/bin/activate
pip install flask google-genai requests python-dotenv

Create a .env file:

GEMINI_API_KEY=your_gemini_key
WHATSAPP_TOKEN=your_whatsapp_access_token
WHATSAPP_PHONE_NUMBER_ID=your_phone_number_id
VERIFY_TOKEN=pick_any_random_string

Ask Gemini: "Generate a .gitignore for a Python project and make sure .env is excluded."

Step 4 β€” The webhook server

Meta requires two things from your endpoint:

  1. GET /webhook β€” a one-time verification handshake.
  2. POST /webhook β€” where inbound messages arrive.

Create app.py:

import os
import requests
from flask import Flask, request
from google import genai
from dotenv import load_dotenv

load_dotenv()

GEMINI_API_KEY = os.environ["GEMINI_API_KEY"]
WHATSAPP_TOKEN = os.environ["WHATSAPP_TOKEN"]
PHONE_NUMBER_ID = os.environ["WHATSAPP_PHONE_NUMBER_ID"]
VERIFY_TOKEN = os.environ["VERIFY_TOKEN"]

app = Flask(__name__)
client = genai.Client(api_key=GEMINI_API_KEY)

SYSTEM_PROMPT = (
    "You are a friendly, concise WhatsApp assistant. "
    "Keep replies short and clear β€” this is a chat app, not email."
)


def ask_gemini(user_text: str) -> str:
    response = client.models.generate_content(
        model="gemini-2.5-flash",
        contents=user_text,
        config=genai.types.GenerateContentConfig(system_instruction=SYSTEM_PROMPT),
    )
    return response.text


def send_whatsapp_message(to: str, body: str) -> None:
    url = f"https://graph.facebook.com/v22.0/{PHONE_NUMBER_ID}/messages"
    headers = {"Authorization": f"Bearer {WHATSAPP_TOKEN}"}
    payload = {
        "messaging_product": "whatsapp",
        "to": to,
        "type": "text",
        "text": {"body": body},
    }
    requests.post(url, headers=headers, json=payload, timeout=20)


@app.get("/webhook")
def verify():
    # Meta's verification handshake
    if (request.args.get("hub.mode") == "subscribe"
            and request.args.get("hub.verify_token") == VERIFY_TOKEN):
        return request.args.get("hub.challenge"), 200
    return "Forbidden", 403


@app.post("/webhook")
def incoming():
    data = request.get_json()
    try:
        change = data["entry"][0]["changes"][0]["value"]
        message = change["messages"][0]          # inbound message
        sender = message["from"]                  # user's phone number
        text = message["text"]["body"]            # message text

        reply = ask_gemini(text)
        send_whatsapp_message(sender, reply)
    except (KeyError, IndexError):
        # Status updates and non-text messages land here β€” ignore them
        pass
    return "OK", 200


if __name__ == "__main__":
    app.run(port=5000)

Ask Gemini: "Paste this file and explain each function line by line, then suggest error handling I'm missing."

Step 5 β€” Expose your server and connect the webhook

Run the server, then tunnel it:

python app.py            # terminal 1
ngrok http 5000          # terminal 2  β†’ copy the https URL

In Meta's WhatsApp β†’ Configuration:

  • Callback URL: https://<your-ngrok-id>.ngrok.io/webhook
  • Verify token: the same VERIFY_TOKEN from your .env
  • Click Verify and save (this triggers the GET handshake).
  • Under Webhook fields, subscribe to messages.

Ask Gemini: "My webhook verification is returning 403. Here's my code and the ngrok logs β€” what's wrong?"

Step 6 β€” Test it

Send a WhatsApp message from your registered number to the test number. Within a second or two you should get a Gemini-generated reply.

If nothing comes back, ask Claude to help you read the logs:

Ask Gemini: "The webhook receives a POST but no reply is sent. Here's the JSON payload and my server log β€” trace where it breaks."

Step 7 β€” Turn the chatbot into an agent

A chatbot answers. An agent takes actions. Gemini supports function calling β€” you declare tools, and the model decides when to call them.

Example: give the agent a check_reservation tool.

def check_reservation(confirmation_code: str) -> dict:
    # Replace with a real lookup (DB, internal API, etc.)
    return {"code": confirmation_code, "status": "confirmed", "checkin": "2026-08-14"}


def ask_gemini_agent(user_text: str) -> str:
    response = client.models.generate_content(
        model="gemini-2.5-flash",
        contents=user_text,
        config=genai.types.GenerateContentConfig(
            system_instruction=SYSTEM_PROMPT,
            tools=[check_reservation],   # SDK auto-generates the schema from the function
        ),
    )
    return response.text

The Gemini SDK reads the function's signature and docstring to build the tool schema, calls it when the user asks about a reservation, and folds the result into its reply.

Ask Gemini: "Add a second tool that cancels a reservation, and add conversation memory so the agent remembers earlier messages in the same chat."

Good next tools to build with Claude's help:

  • Conversation memory β€” store recent turns per phone number (a dict, Redis, or a DB) and pass them as contents.
  • Handoff to a human β€” detect frustration or keywords and notify a live agent.
  • Domain tools β€” bookings, order status, FAQs backed by your own data.

Step 8 β€” Before you go to production

  • Swap the temporary WhatsApp token for a permanent System User token.
  • Verify the X-Hub-Signature-256 header on every POST using your App Secret β€” reject anything unsigned.
  • Return 200 fast and process Gemini calls in a background task/queue (Meta retries if you're slow).
  • Add rate limiting and logging.
  • Move off ngrok to real hosting (Cloud Run, Render, Fly.io, a VM).

Ask Gemini: "Write the X-Hub-Signature-256 verification middleware for my Flask app, and refactor the Gemini call to run in a background thread so the webhook returns 200 immediately."

How to work with Gemini effectively

  • Give context, not just the error. Paste the code and the log/payload.
  • Ask for explanations, not only fixes β€” you own this code afterward.
  • Iterate in small steps. One tool, one feature, one bug at a time.
  • Ask Gemini to review for security and edge cases before you ship. In the Gemini CLI you can point it right at a file (gemini "review app.py for security issues").

Quick reference

Piece Service Docs
Inbound + outbound messages WhatsApp Cloud API developers.facebook.com/docs/whatsapp/cloud-api
Agent reasoning + tools Gemini API ai.google.dev/gemini-api/docs
Your coding copilot Gemini CLI / Code Assist github.com/google-gemini/gemini-cli Β· codeassist.google

Model note: gemini-2.5-flash is fast and cheap for chat; switch to gemini-2.5-pro for harder reasoning. Check Google's model list for the latest IDs.

πŸ“° Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.