关于 openwa
OpenWA 是面向 WhatsApp 自动化开发的开源、可自托管 API 网关。它提供 REST API、仪表板、多会话支持、Webhook、实时事件,以及 JavaScript/TypeScript 和 Python SDK。
主要功能
- 01REST API 和 React 仪表板
- 02管理多个 WhatsApp 账号会话
- 03消息、联系人、群组和频道接口
- 04带签名和重试的 Webhook
- 05Socket.IO 实时事件
- 06JavaScript/TypeScript 与 Python SDK
适用场景
- 01自动化多个 WhatsApp 账号的消息处理
- 02通过 Webhook 处理收到的消息事件
- 03实时监控会话和消息事件
- 04使用 SDK 集成 WhatsApp 操作
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ thatjuan/ agent-skills --skill openwa安装后在 Claude Code 中输入/openwa确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
README.mdreferences/architecture.mdconfiguration.mddeployment.mdgotchas.mdoperation.mdrest-api.mdsdk.mdwebhooks-and-events.md详细介绍
OpenWA
OpenWA 是一个可自托管、开源的 WhatsApp API 网关(MIT、NestJS 11 / TypeScript / Node 22)。它在端口 2785 上通过 REST API 封装 whatsapp-web.js(Puppeteer + Chromium),提供运行于端口 2886 的 React 仪表板,并支持多会话 WhatsApp 自动化、webhook、Socket.IO 实时事件、可插拔存储/缓存/数据库,以及插件钩子系统。
产品组成
| 组件 | 端口 | 作用 |
|---|---|---|
openwa-api (NestJS) | 2785 | REST + WebSocket + webhook 分发器 |
dashboard (React 19 + Vite) | 2886 | 会话/API 密钥/webhook 界面 |
| Swagger UI | 2785 | /api/docs |
| Traefik(可选) | 80、8080 | 反向代理 + 仪表板(配置组 with-proxy) |
| PostgreSQL(可选) | 5432 | 配置组 postgres |
| Redis(可选) | 6379 | 配置组 redis,用于启用 BullMQ 队列 |
| MinIO(可选) | 9000、9001 | 配置组 minio(兼容 S3 的存储) |
全局 API 前缀为 /api(src/main.ts:128 中的 app.setGlobalPrefix('api'))。以下所有路径均相对于 <baseUrl>/api。
技术栈 — 已验证
| 层 | 技术 | 依据 |
|---|---|---|
| 框架 | NestJS 11.x | package.json |
| WA 引擎 | whatsapp-web.js 1.26.1(Puppeteer + Chromium) | package.json、src/engine/engine.factory.ts |
| 主数据库 | SQLite(始终启用 — 存储 API 密钥、审计日志) | src/app.module.ts |
| 数据库 | SQLite 或 PostgreSQL(会话、消息、webhook) | src/app.module.ts |
| ORM | TypeORM 0.3.x | package.json |
| 队列 | BullMQ 5.x(由 QUEUE_ENABLED 控制) | src/app.module.ts:31 |
| 缓存 | Redis(可选,由 REDIS_ENABLED 控制) | src/common/cache/ |
| 存储 | 本地或 S3/MinIO | src/common/storage/ |
| 实时通信 | /events 命名空间上的 Socket.IO 4.8 | src/modules/events/events.gateway.ts |
| 验证 | class-validator、class-transformer | package.json |
| SDK | @openwa/sdk (JS/TS) + openwa (Python) | sdk/javascript/、sdk/python/ |
仓库目录结构
src/
main.ts # Boot + .env precedence + first-run API key
app.module.ts # Composition; conditional QueueModule
config/configuration.ts # Env → config object
core/{hooks,plugins}/ # Plugin hook system
engine/ # IWhatsAppEngine interface + adapters
modules/
session/ # Session CRUD + in-memory engine map
message/ # Send & history endpoints
webhook/ # Per-session webhook subscriptions
events/ # Socket.IO gateway (/events namespace)
auth/ # API-key auth + roles
contact/ group/ label/ channel/ status/ catalog/
queue/ # BullMQ jobs (only if QUEUE_ENABLED)
health/ # /health, /health/live, /health/ready
infra/ settings/ stats/ audit/ docker/ plugins/
dashboard/ # React 19 + Vite SPA
sdk/{javascript,python}/ # Client libraries
traefik/{traefik.yml,dynamic.yml}
docker-compose.yml # Profiled production stack
docker-compose.dev.yml # SQLite + local dev quick-start
Dockerfile # Multi-stage Node 22-slim + Chromium
docs/ # 22 markdown design docs
身份验证 — X-API-Key
身份验证使用哈希后的 API 密钥,并通过 X-API-Key 标头发送(根据 main.ts:122 中的 CORS 允许列表,也接受 Authorization: Bearer)。密钥以哈希形式存储在主 SQLite 数据库中,并具有以下角色之一:ADMIN、OPERATOR 或 VIEWER(src/modules/auth/entities/api-key.entity.ts)。
curl -H "X-API-Key: owa_k1_xxxxxxxx..." http://localhost:2785/api/sessions
- 密钥格式:
owa_k1_<32 bytes hex>(src/modules/auth/auth.service.ts:95) - 首次运行引导:如果不存在 API 密钥,OpenWA 会创建一个并将其写入
data/.api-key,随后在启动横幅中打印该密钥。在开发环境(NODE_ENV=development)中,引导密钥是字面字符串dev-admin-key。 - 角色控制:写入端点使用
@RequireRole(ApiKeyRole.OPERATOR);读取操作大多只需 API 密钥即可访问。API 密钥的增删改查需要 ADMIN 角色。 - 可选的单密钥范围限制:IP 允许列表(
allowedIps)和会话允许列表(allowedSessions)。
密钥创建/撤销流程请参阅身份验证与 API 密钥生命周期。
会话 — 多账号 WhatsApp
每个 WhatsApp 账号对应一条持久化的 Session 记录,以及一个以内存中的会话 ID 为键的 IWhatsAppEngine 引擎(src/modules/session/session.service.ts)。会话会经历以下状态:
CREATED → INITIALIZING → QR_READY → AUTHENTICATING → READY
↘ FAILED
any → DISCONNECTED (also forced on every API restart)
使会话上线的最简工作流:
# 1. Create
curl -X POST http://localhost:2785/api/sessions \
-H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"name":"bot-1"}'
# 2. Start (initialises Chromium + WA engine)
curl -X POST http://localhost:2785/api/sessions/$ID/start -H "X-API-Key: $KEY"
# 3. Fetch QR — returns SVG data while status = QR_READY
curl http://localhost:2785/api/sessions/$ID/qr -H "X-API-Key: $KEY"
# … scan with WhatsApp mobile …
# 4. Poll status (or subscribe via /events) until status = READY
curl http://localhost:2785/api/sessions/$ID -H "X-API-Key: $KEY"
聊天 ID 遵循 WhatsApp Web 约定:私聊使用 <phone>@c.us,群组使用 <id>@g.us,频道使用 <id>@newsletter。格式无效会导致发送静默失败。
完整生命周期、内存中的引擎映射、代理选项以及重启时的重置行为,请参阅:operation.md。
REST API — 控制器目录
所有路由均挂载在 /api 下。括号中的角色表示要求高于默认的 VIEWER 或更高权限时所需的角色。
| 领域 | 路由 | 文件 |
|---|---|---|
| 会话 | POST /sessions (OPERATOR)、GET /sessions、GET /sessions/:id、DELETE /sessions/:id (OPERATOR)、POST /sessions/:id/start (OPERATOR)、POST /sessions/:id/stop (OPERATOR)、GET /sessions/:id/qr、GET /sessions/:id/groups、GET /sessions/stats/overview | session.controller.ts |
| 消息 | GET /sessions/:sessionId/messages、POST /sessions/:sessionId/messages/send-text、…/send-image、…/send-video、…/send-audio、…/send-document、…/send-location、…/send-contact、…/send-sticker、…/reply、…/forward、…/react、GET …/:chatId/:messageId/reactions、POST …/delete、POST …/send-bulk、GET …/batch/:batchId、POST …/batch/:batchId/cancel | message.controller.ts |
| Webhook | /sessions/:sessionId/webhooks 下的 POST/GET/GET :id/PUT :id/DELETE :id,以及 POST :id/test | webhook.controller.ts |
| API 密钥 | POST /auth/api-keys (ADMIN)、GET、GET :id、PUT :id、DELETE :id、POST :id/revoke | auth.controller.ts |
| 身份验证探测 | GET /auth/validate(请求头 X-API-Key) | auth-validate.controller.ts |
| 健康检查 | GET /health、GET /health/live、GET /health/ready(公开;K8s 形式) | health.controller.ts |
| 联系人/群组/标签/频道/状态/目录 | 各模块控制器位于 /sessions/:sessionId/... 下 | modules/<name>/ |
| 基础设施 | 用于迁移的设置、统计、导出/导入 | modules/infra/ |
权威定义以控制器文件和自动发布的 OpenAPI 为准,地址为 http://localhost:2785/api/docs。包含角色/身份验证说明的完整路由表:rest-api.md。
Webhook — 按会话配置、带签名、可重试
Webhook 按会话创建(POST /api/sessions/:sessionId/webhooks),需要提供 URL、events 数组,以及可选的 secret/自定义 headers。当 QUEUE_ENABLED=true 时,通过 BullMQ 投递(并进行重试);否则采用同步投递。
每次投递都会发送以下请求头:
| 请求头 | 含义 |
|---|---|
X-OpenWA-Event | 事件名称(例如 message.received) |
X-OpenWA-Delivery-Id | 每次投递尝试的父级分发任务的唯一 ID |
X-OpenWA-Idempotency-Key | 对每个(事件 × 主体)保持稳定的键 — 用于消费者去重 |
X-OpenWA-Retry-Count | 首次尝试为 0,之后为 attemptsMade |
X-OpenWA-Signature | 使用 webhook.secret 对 JSON 请求体计算的 sha256=<hex hmac>(未设置密钥时省略) |
默认值:WEBHOOK_TIMEOUT=10000 毫秒、WEBHOOK_MAX_RETRIES=3、WEBHOOK_RETRY_DELAY=5000 毫秒。
可订阅的事件类型(WebSocket 也支持 — src/modules/events/dto/ws-messages.dto.ts):
message.received、message.sent、message.ack、message.revoked、session.status、session.qr、session.authenticated、session.disconnected、group.join、group.leave、group.update — 以及用于订阅全部事件的 *。
签名验证、投递流程、队列与同步模式、幂等语义、重试时序:webhooks-and-events.md。
实时通信 — Socket.IO /events
事件分类与 Webhook 相同,通过 Socket.IO 在 /events 命名空间中投递。协议使用自定义 JSON(而非 Socket.IO 事件发射器):客户端发送 {type:'subscribe', sessionId, events, requestId?},并在服务端接收 {type:'event', ...} / {type:'subscribed', ...} / {type:'error', ...} / {type:'pong'}。
import { io } from 'socket.io-client';
const sock = io('http://localhost:2785/events', { auth: { apiKey: KEY } });
sock.emit('message', { type: 'subscribe', sessionId: '*', events: ['message.received'] });
sock.on('message', (msg) => { /* handle msg.type === 'event' */ });
传输格式、身份验证模式、房间布局(session:<id>:<event>)以及 ping/pong:webhooks-and-events.md#websocket。
部署
提供三种文档化的部署路径:
| 路径 | 命令 |
|---|---|
| 本地开发(SQLite、无 Redis/队列、全部集成) | docker compose -f docker-compose.dev.yml up -d |
| 基础生产环境 | docker compose up -d |
| 完整生产环境(Postgres + Redis + MinIO + Traefik + Dashboard) | docker compose --profile full up -d |
镜像基于多阶段构建的 node:22-slim,内置 Chromium,并设置了 PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium。容器每隔 30 s 执行一次健康检查:node -e "require('http').get('http://localhost:2785/api/health', ...)"。
Compose 配置文件的配置档(postgres、redis、minio、with-dashboard、with-proxy、full)、卷布局(openwa-data:/app/data)、Docker socket 挂载(/var/run/docker.sock:ro —— 由 modules/docker 用于编排)、Traefik 静态/动态配置以及 K8s 健康探针:deployment.md。
配置——由环境变量驱动,分三层优先级
引导启动(src/main.ts:11-65)会通过 override: false 加载 dotenv,因此优先级最高的是进程环境变量:
process.env > ./.env > ./data/.env.generated
.env.generated 是 Dashboard 写入的文件,其优先级最低,而非最高。常见误区是以为 Dashboard 保存的设置会覆盖 Docker environment: 块——实际上不会。
首次启动时,如果不存在 data/.env.generated,OpenWA 会创建该文件,使用 SQLite、本地存储并禁用队列,同时打印包含 API key 的欢迎横幅。
app.module.ts 中配置了两个 TypeORM 数据库:
main连接——始终使用 SQLite。存储 API key 和审计日志。始终保留在本地节点(不要尝试迁移它)。data连接——使用 SQLite 或 PostgreSQL。存储会话、消息和 Webhook。SQLite 默认启用同步,Postgres 默认禁用(此时运行npm run migration:run:prod)。
完整的环境变量参考、.env.minimal、双数据库示意图以及 QUEUE_ENABLED 控制逻辑:configuration.md。
SDK
import { OpenWAClient } from '@openwa/sdk';
const client = new OpenWAClient({ baseUrl: 'http://localhost:2785', apiKey: KEY });
await client.sessions.create({ name: 'bot-1' });
await client.sessions.start(id);
await client.messages.sendText(id, { chatId: '[email protected]', text: 'hi' });
已发布的 @openwa/sdk 提供精简的手写接口(sdk/javascript/src/index.ts),并计划根据 OpenAPI 规范重新生成。对于尚未封装的端点,可调用 client.request('POST', '/api/...', body),或使用带有 X-API-Key 的 fetch。Python SDK 位于 sdk/python/openwa/。
SDK 安装、类型化封装、生成流程及 Python 对应内容:sdk.md。
架构与可扩展性
OpenWA 通过接口边界而非单靠功能开关来实现可插拔性:
IWhatsAppEngine(src/engine/interfaces/)——抽象whatsapp-web.js;可通过engine.factory.ts接入替代引擎(Baileys 等)。由ENGINE_TYPE选择。StorageService——本地文件系统或 S3/MinIO,通过STORAGE_TYPE切换。CacheService——内存或 Redis,由REDIS_ENABLED控制。- 插件钩子——
core/hooks/会运行具名钩子链。消息发送流水线会在分发前触发message:sending(插件可修改或拦截),并在成功后触发message:sent。当PLUGINS_ENABLED=true时会自动加载插件。 - 队列控制——仅当
QUEUE_ENABLED === 'true'时才会requireQueueModule(src/app.module.ts:31-38)。未启用时,Webhook 重试仅以尽力而为的同步方式执行。
模块映射、钩子列表、插件加载器、扩展模型(引擎固定在各节点上;API key 保留在本地;数据数据库可以共享):architecture.md。
注意事项
以下几个行为容易让只读文档、不看代码的人踩坑:
.env.generated的优先级是最低,不是最高。- 每次 API 重启都会强制将所有
READY/INITIALIZING/QR_READY/AUTHENTICATING会话重置为DISCONNECTED(引擎在内存中;重启会丢失它们)。 QUEUE_ENABLED=false(默认值)意味着Webhook 不会重试——采用同步尽力分发。- SQLite 的默认设置是
synchronize: true,在生产环境中很危险;使用 Postgres 时应切换为迁移。 - API 密钥存储在 SQLite
main数据库中。将data数据库切换为 Postgres 不会迁移这些密钥。 - 在会话达到
READY之前,phone和pushName都为null。 - 聊天 ID 的格式必须是
<phone>@c.us/<id>@g.us——格式错误会导致静默失败。 - Chromium 是必需的;Docker 镜像将
PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium硬编码。
完整的注释列表(含文件和行号引用):gotchas.md。
参考索引
| 参考资料 | 内容 |
|---|---|
| deployment.md | Dockerfile 阶段、compose 配置文件、Traefik、K8s 探针、卷 |
| configuration.md | 环境变量参考、优先级、双数据库布局、队列开关 |
| operation.md | 会话生命周期、QR 身份验证、API 密钥引导与生命周期、仪表板 |
| rest-api.md | 完整的控制器→路由目录、角色装饰器、请求/响应格式 |
| webhooks-and-events.md | Webhook 请求头、HMAC、重试、幂等性、Socket.IO /events 线格式 |
| sdk.md | JS/TS 和 Python 客户端用法、原始 fetch 备用方案、重新生成说明 |
| architecture.md | 模块映射、引擎/存储/缓存的可插拔性、插件钩子、扩展 |
| gotchas.md | 根据源代码验证的非显而易见行为 |