WhatsApp API for AI agents: connecting Claude, n8n and LangChain
An AI agent that can only talk to you in a chat window is half useful. The other half is reaching the people who already live in WhatsApp: customers, leads, your own team. This guide covers three ways to wire a WhatsApp number into an agent (an MCP server, n8n and Python tools) and the locks you want in place before the agent is allowed to send anything. Disclosure: ZapZap API is an unofficial API. You connect a normal number by QR code, with no Meta business verification and no message templates. That is also its main risk, so a whole section is about it.
Published on · 6 min read
Pick the route by where the agent runs
| Where the agent runs | Route | Needs code? |
|---|---|---|
| --- | --- | --- |
| A desktop assistant (Claude Desktop, Claude Code, Cursor) | MCP server | No, one config entry |
| Triggered automations (a customer writes, the agent answers) | n8n flow | Little |
| Your own product or backend | Python or Node tools (LangChain, CrewAI, your own loop) | Yes |
All three talk to the same REST API: https://api.zapzapapi.com/api/v1/{instanceId}/..., authenticated with two headers, x-api-key and x-api-secret (authentication). If your agent framework reads OpenAPI, the spec is public: ZapZap OpenAPI. The AI agents page collects the three options in one place.
Route 1: an MCP server for Claude and Cursor
MCP (Model Context Protocol) lets an AI client discover tools from a server and call them during a conversation. zapzap-mcp exposes 25 curated tools (send text and media, polls, buttons, check numbers, find messages, groups, webhooks) instead of 150-plus raw endpoints, so the model has fewer wrong choices.
The code is open source at github.com/zapzapapi/zapzap-mcp and is not on npm yet. So you install it from the repository: clone, install and build (Node 18 or newer), then point your client at the compiled file.
Two behaviors worth knowing. Send tools are annotated as non-idempotent and destructive, so MCP clients ask you to confirm each send. And ZAPZAP_READ_ONLY=true removes every write tool, which is the right default for the first week (it is already on in the examples below).
Try prompts like: check that my instance is connected, then tell me which of these three numbers have WhatsApp. Approve each call by hand until you trust it. If you would rather write your own server, the MCP server walkthrough has the TypeScript code.
Instalar a partir do GitHub
git clone https://github.com/zapzapapi/zapzap-mcp
cd zapzap-mcp
npm install
npm run build
# Claude Code:
claude mcp add zapzap -e ZAPZAP_API_KEY=your-api-key -e ZAPZAP_API_SECRET=your-api-secret -e ZAPZAP_READ_ONLY=true -- node "$(pwd)/dist/src/index.js"Claude Desktop ou Cursor (JSON)
{
"mcpServers": {
"zapzap": {
"command": "node",
"args": ["/path/to/zapzap-mcp/dist/src/index.js"],
"env": {
"ZAPZAP_API_KEY": "your-api-key",
"ZAPZAP_API_SECRET": "your-api-secret",
"ZAPZAP_READ_ONLY": "true"
}
}
}
}Route 2: an n8n flow with an AI Agent node
The flow has five nodes. 1) Webhook receives the messages event from your instance (register the production URL with the webhook endpoint). 2) Code extracts number, text and message id, and drops events where fromMe is true; skip this and the agent replies to its own replies in a loop. 3) AI Agent with window memory keyed by the contact's number, so each customer has a separate conversation; put the handoff rule in the system prompt, for example answer with one fixed sentence when the customer asks for a person. 4) IF checks for that fixed sentence and marks the contact as with a human. 5) HTTP Request calls POST /api/v1/{instanceId}/send/text with number and text.
There is also a community node, n8n-nodes-zapzap (version 0.1.3 on npm). Unverified community nodes only run on self-hosted n8n, so on n8n Cloud use the HTTP Request node with the same headers. The full walkthrough is in AI agent on WhatsApp with n8n, and there are ready workflows in the n8n templates.
Route 3: tools for LangChain (Python)
A tool is a function with a name, a description and typed arguments. The model decides when to call it; the function decides what is actually allowed. Keep the locks in the function, never in the prompt. The example below has two tools: check numbers, and send text only to an allowed list, with sending off until you set ZAPZAP_ENABLE_SEND=true.
Wire the tools to an agent with LangChain 1.x (create_agent) or CrewAI's tool decorator, and check your installed version's docs, because both projects change fast. Human approval before real sends comes from your framework's interrupt or human-input features. The full version is in the LangChain and CrewAI guide.
Python: ferramentas
import os
import re
import requests
from langchain_core.tools import tool
BASE = "https://api.zapzapapi.com/api/v1"
INSTANCE = os.environ["ZAPZAP_INSTANCE_ID"]
HEADERS = {
"x-api-key": os.environ["ZAPZAP_API_KEY"],
"x-api-secret": os.environ["ZAPZAP_API_SECRET"],
}
ALLOWED = {n.strip() for n in os.environ.get("ZAPZAP_ALLOWED", "").split(",") if n.strip()}
SEND_ENABLED = os.environ.get("ZAPZAP_ENABLE_SEND") == "true"
def _post(path: str, body: dict) -> dict:
r = requests.post(f"{BASE}/{INSTANCE}{path}", json=body, headers=HEADERS, timeout=20)
r.raise_for_status()
return r.json()
@tool
def check_whatsapp_numbers(numbers: list[str]) -> str:
"""Check which phone numbers are registered on WhatsApp.
Numbers: country code plus digits only, for example 5511999999999."""
clean = [n for n in numbers if re.fullmatch(r"\d{10,15}", n)]
if not clean:
return "No valid numbers. Use country code and digits only."
return str(_post("/chat/check", {"numbers": clean}))
@tool
def send_whatsapp_text(number: str, text: str) -> str:
"""Send a WhatsApp text to ONE allowed recipient. Never invent numbers."""
if not re.fullmatch(r"\d{10,15}", number):
return "Invalid number format."
if number not in ALLOWED:
return "Blocked: this number is not on the allowed list."
if len(text) > 1000:
return "Blocked: text too long."
if not SEND_ENABLED:
return f"Safe mode, not sent. Would send to {number}: {text[:80]}"
return str(_post("/send/text", {"number": number, "text": text}))Python: agente
from langchain.agents import create_agent
agent = create_agent(
model="provider:model-name", # fill in the provider you have a key for
tools=[check_whatsapp_numbers, send_whatsapp_text],
system_prompt="You help the support team. Only message people on the allowed list.",
)
result = agent.invoke({"messages": [{"role": "user", "content": "Is 5511999999999 on WhatsApp?"}]})The locks, whatever the route
| Lock | Why |
|---|---|
| --- | --- |
| Allowed list of recipients, inside the tool | The model can be wrong or be talked into something |
| Human approval per send | Last barrier before a real message |
| Read-only mode first | Lets you test lookups without any send risk |
| Hourly cap and logging | Contains a looping agent and gives you an audit trail |
| A dedicated instance | Keeps risk away from your main number |
| Treat incoming text as untrusted | A customer can write instructions aimed at the model (prompt injection) |
The risk you should not skip
An unofficial API goes against WhatsApp's terms and a number can be limited or banned. An agent does not reduce that risk; it can raise it if it starts cold conversations at volume. Anti-block features such as automatic typing delay and pacing reduce the risk, they do not remove it, and nobody honest can promise otherwise.
Use agents to answer people who wrote first, to support your team and for internal tasks, and only message people who agreed to hear from you. See the anti-ban guide and the acceptable use policy. If you need an officially sanctioned channel, use Meta's Cloud API: the official vs unofficial comparison lays out when each one wins.
Try it
R$15 per active number per month, prepaid, with no per-message fee (pricing). New accounts get a welcome credit when the phone is verified, subject to the current campaign. The quick start takes you from account to first message.
Quick summary
- MCP for desktop assistants, n8n for event-driven automation, Python tools for your backend: all three use the same REST API.
- zapzap-mcp is open source on GitHub and not on npm yet: install it by cloning and building the repository.
- Keep the locks inside the tool: allowed recipients, human approval, read-only mode and an hourly cap.
- An AI agent does not lower the ban risk of the number. Use it to answer people who wrote first and for internal tasks.
Keep reading
Also read
Frequently asked questions
Is the ZapZap MCP server on npm yet?
Not yet. The code is open source at github.com/zapzapapi/zapzap-mcp: clone it, run npm install and npm run build, and point your MCP client at the compiled file. This guide will be updated when it is published to npm.
Can I let the agent send messages on its own?
You can, but start with human approval per send, an allowed list of recipients and read-only mode. Keep the locks inside the tool, not only in the prompt, because the model can be wrong or be led astray by incoming text.
Does n8n Cloud accept the ZapZap node?
Unverified community nodes only run on self-hosted n8n. On n8n Cloud use the HTTP Request node with the x-api-key and x-api-secret headers.
Does using an AI agent raise the ban risk of the number?
It can, if the agent starts cold conversations at volume. An unofficial API goes against WhatsApp's terms and no feature removes the risk. For a sanctioned channel, use Meta's official API.
Give your agent a WhatsApp channel
Connect a test number, start in read-only mode and turn on sending once the locks are in place. R$15 per active number per month.
