The WhatsApp agent framework.
wappa is a TypeScript framework for building WhatsApp agents: bots whose "brain" is an
LLM with tool-calling and whose "body" is a pluggable WhatsApp transport. You define an
agent (instructions + tools + provider), pick a transport (Baileys for personal-number/QR
login, the official WhatsApp Cloud API, or Twilio's WhatsApp API), and run.
npm create wappa-agent my-bot
Features
- Transport-agnostic core.
@wappajs/corenever imports a WhatsApp library; it speaks a normalized message model. Adapters translate. - Provider-agnostic agent loop. The core owns the tool-call loop and conversation
memory. Providers (
@wappajs/anthropic,@wappajs/openai) map onegenerate()call to their SDK, and@wappajs/openaiworks against any OpenAI-compatible server viabaseURL. - Middleware-first extensibility. grammY/Telegraf-style
use(ctx, next), pluscommand()andhears()routing. Auth, rate limiting, logging, transcription and handoff are all just middleware. - Typed tools with zod.
defineToolinfers argument types from a zod schema, validates model-supplied arguments, and turns failures into retryable tool results instead of crashes. - Sessions built in. Per-chat conversation history and durable data with in-memory and file-backed stores, and a lost-update-safe pause/resume flag for human handoff.
- Testability is a feature.
@wappajs/core/testingshipsMockTransportandScriptedProvider, so you can unit-test a whole bot offline, with no WhatsApp and no LLM key. - Per-chat concurrency model. Messages within one chat are processed strictly in order; different chats run concurrently. Graceful shutdown drains in-flight turns.
Architecture
WhatsApp
│
┌──────────────┴───────────────┐
│ Transport │ @wappajs/baileys (personal number, QR login)
│ QR / webhooks / Graph API │ @wappajs/cloud-api (official Meta Cloud API)
│ │ @wappajs/twilio (Twilio WhatsApp BSP)
└──────────────┬───────────────┘
│ InboundMessage / OutboundPayload (normalized)
┌──────────────┴───────────────┐
│ Bot │ per-chat queues · middleware chain
│ use() · command() · hears()│ built-in router · session persistence
└──────────────┬───────────────┘
│ Context (message, session, reply, state)
┌──────────────┴───────────────┐
│ Agent │ tool-call loop · history window
│ defineTool + zod │ error rollback · maxTurns cap
└──────────────┬───────────────┘
│ GenerateRequest / GenerateResult
┌──────────────┴───────────────┐
│ Provider │ @wappajs/anthropic (Claude)
│ one generate() │ @wappajs/openai (GPT + compatible servers)
└──────────────────────────────┘
Quickstart: Baileys + Claude
The fastest path to a running agent: a personal WhatsApp number, logged in via QR code.
npm create wappa-agent my-bot -- --transport baileys --provider anthropic
Or wire it up by hand in an existing ESM project (Node >= 20):
npm install @wappajs/core @wappajs/baileys @wappajs/anthropic zod
// src/index.ts (ESM, Node >= 20)
import { Agent, Bot, defineTool } from '@wappajs/core';
import { BaileysTransport } from '@wappajs/baileys';
import { AnthropicProvider } from '@wappajs/anthropic';
import { z } from 'zod';
const agent = new Agent({
instructions: 'You are a helpful assistant reachable over WhatsApp. Keep replies short.',
provider: new AnthropicProvider(), // reads ANTHROPIC_API_KEY from the environment
tools: [
defineTool({
name: 'get_time',
description: 'Get the current date and time.',
parameters: z.object({}),
execute: () => new Date().toString(),
}),
],
});
const bot = new Bot({ transport: new BaileysTransport(), agent });
await bot.start(); // prints a QR code, scan it with WhatsApp on your phone
export ANTHROPIC_API_KEY=sk-ant-...
npx tsc && node dist/index.js
Auth state persists in ./wappa-auth, so the QR scan is only needed once.
Quickstart: Cloud API
The official transport runs a webhook server and sends through the Graph API:
import { Agent, Bot } from '@wappajs/core';
import { CloudApiTransport } from '@wappajs/cloud-api';
import { OpenAIProvider } from '@wappajs/openai';
const transport = new CloudApiTransport({
accessToken: process.env.WHATSAPP_ACCESS_TOKEN!,
phoneNumberId: process.env.WHATSAPP_PHONE_NUMBER_ID!,
verifyToken: process.env.WHATSAPP_VERIFY_TOKEN!,
appSecret: process.env.WHATSAPP_APP_SECRET, // strongly recommended
port: 3000, // starts a node:http webhook server
});
const bot = new Bot({
transport,
agent: new Agent({
instructions: 'You are a helpful WhatsApp assistant.',
provider: new OpenAIProvider(), // reads OPENAI_API_KEY
}),
});
await bot.start();
The Meta dashboard setup (app, phone number, webhook verification, app secret) is walked through step by step in docs/transports/cloud-api.md.
Packages
| Package | What it is |
|---|---|
@wappajs/core |
Transport-agnostic core: Bot, Agent, defineTool, sessions, middleware, logger |
@wappajs/core/testing |
MockTransport + ScriptedProvider for offline tests |
@wappajs/baileys |
Baileys transport, personal number via QR login (unofficial client, see below) |
@wappajs/cloud-api |
Official WhatsApp Cloud API transport (Meta webhook + Graph API, no Meta SDK) |
@wappajs/twilio |
Twilio WhatsApp transport (form-encoded webhook + Messages REST API, no Twilio SDK) |
@wappajs/anthropic |
Claude provider (Anthropic Messages API), default model claude-sonnet-5 |
@wappajs/openai |
OpenAI provider (Chat Completions), default model gpt-5; baseURL for Ollama etc. |
create-wappa-agent |
Project scaffolder: npm create wappa-agent my-bot |
Documentation
- Getting started: install options and first run
- Concepts: Bot pipeline, Agent loop, tools, sessions, middleware, handoff
- Baileys transport
- Cloud API transport
- Twilio transport
- Providers: Anthropic, OpenAI, OpenAI-compatible servers, custom providers
- Testing: unit-testing bots with
MockTransport+ScriptedProvider - Recipes: handoff, media, groups, proactive messages, transcription, rate limits
Release history is in CHANGELOG.md, and the release process in RELEASING.md.
Runnable examples live in examples/: echo-bot (router-only, no LLM),
support-agent (Claude + tools + Baileys, the flagship), and cloud-api-agent
(OpenAI + Cloud API webhook deployment).
Roadmap
Deliberately not in v0.1 (several have recipes showing how to do them yourself in docs/recipes.md):
- Streaming replies
- WhatsApp flows/forms
- Built-in voice transcription (recipe: transcription middleware)
- Scheduled/cron messages (recipe: plain
setInterval+bot.send) - Built-in group mention filtering (recipe: middleware using
bot.selfId) - Analytics / admin UI
- Redis session store
A note on Baileys and WhatsApp's Terms of Service
@wappajs/baileys builds on Baileys, an
unofficial WhatsApp Web client. Using it may violate WhatsApp's Terms of Service and
can get phone numbers banned. Use a number you can afford to lose, and prefer an
official transport (@wappajs/cloud-api or @wappajs/twilio) for anything production-grade.
Comments