mcpField
O
openwa

openwa

github.com/thatjuanその他149 回インストール3 週間前に更新
リポジトリ

openwa について

OpenWA は、WhatsApp 自動化を構築するチーム向けのオープンソースでセルフホスト可能な API ゲートウェイです。REST API、ダッシュボード、複数セッション、Webhook、リアルタイムイベントに加え、JavaScript/TypeScript と Python の SDK を備えています。

主な機能

  1. 01REST API と React ダッシュボード
  2. 02複数の WhatsApp アカウントセッション管理
  3. 03メッセージ、連絡先、グループ、チャンネルの API
  4. 04署名と再試行に対応する Webhook
  5. 05Socket.IO によるリアルタイムイベント
  6. 06JavaScript/TypeScript と Python の SDK

活用シーン

  1. 01複数の WhatsApp アカウントでメッセージを自動化
  2. 02Webhook で受信メッセージイベントを処理
  3. 03セッションとメッセージイベントをリアルタイム監視
  4. 04SDK を使って WhatsApp 操作を統合

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/thatjuan/agent-skills --skill openwa

インストール後、Claude Code で/openwaを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

README.md
references/
architecture.md
configuration.md
deployment.md
gotchas.md
operation.md
rest-api.md
sdk.md
webhooks-and-events.md

詳細

OpenWA

OpenWA はセルフホスト可能なオープンソースの WhatsApp API ゲートウェイです(MIT、NestJS 11/TypeScript/Node 22)。whatsapp-web.js(Puppeteer + Chromium)をポート 2785 の REST API の背後でラップし、ポート 2886 で React ダッシュボードを提供します。また、Webhook、Socket.IO のリアルタイムイベント、プラグ可能なストレージ/キャッシュ/データベース、プラグインフックシステムを備えた、複数セッションの WhatsApp 自動化に対応しています。

製品の構成

コンポーネントポート役割
openwa-api(NestJS)2785REST + WebSocket + Webhook ディスパッチャー
dashboard(React 19 + Vite)2886セッション/API キー/Webhook の UI
Swagger UI2785/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.xpackage.json
WA エンジンwhatsapp-web.js 1.26.1(Puppeteer + Chromium)package.json、src/engine/engine.factory.ts
メイン DBSQLite(常時使用 — API キー、監査ログを保存)src/app.module.ts
データ DBSQLite または PostgreSQL(セッション、メッセージ、Webhook)src/app.module.ts
ORMTypeORM 0.3.xpackage.json
キューBullMQ 5.x(QUEUE_ENABLED で有効化)src/app.module.ts:31
キャッシュRedis(オプション、REDIS_ENABLED で有効化)src/common/cache/
ストレージローカルまたは S3/MinIOsrc/common/storage/
リアルタイム名前空間 /events の Socket.IO 4.8src/modules/events/events.gateway.ts
バリデーションclass-validator、class-transformerpackage.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

認証には、X-API-Key ヘッダーで送信するハッシュ化された API キーを使用します(main.ts:122 の CORS 許可リストに従い、Authorization: Bearer も使用できます)。キーはメインの SQLite DB にハッシュ化して保存され、ロール(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 はキーを1つ作成して data/.api-key に書き込み、起動バナーに表示します。開発環境(NODE_ENV=development)では、ブートストラップキーは文字列 dev-admin-key です。
  • ロールによる制限:書き込みエンドポイントには @RequireRole(ApiKeyRole.OPERATOR) が設定されています。読み取りは大部分が API キーによって公開されています。API キーの CRUD には ADMIN が必要です。
  • キーごとの任意のスコープ設定:IP 許可リスト(allowedIps)とセッション許可リスト(allowedSessions)。

キーの作成/失効のフローについては、認証と API キーのライフサイクルを参照してください。

セッション — 複数アカウントの WhatsApp

各 WhatsApp アカウントは、永続化される Session 行1件と、セッション ID をキーとするメモリ内エンジン(IWhatsAppEngine)1つに対応します(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/overviewsession.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/cancelmessage.controller.ts
Webhook/sessions/:sessionId/webhooks 配下の POST/GET/GET :id/PUT :id/DELETE :id、および POST :id/testwebhook.controller.ts
API キーPOST /auth/api-keys (ADMIN)、GET、GET :id、PUT :id、DELETE :id、POST :id/revokeauth.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 は URL、events 配列、および任意の secret/カスタム headers を指定して、セッションごとに作成します(POST /api/sessions/:sessionId/webhooks)。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-Signaturewebhook.secret を使って JSON ボディから計算した sha256=<hex hmac>(シークレットがない場合は省略)

デフォルト値:WEBHOOK_TIMEOUT=10000 ms、WEBHOOK_MAX_RETRIES=3、WEBHOOK_RETRY_DELAY=5000 ms。

購読可能なイベントタイプ(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 と同じイベント分類が、/events 名前空間の Socket.IO 経由で配信されます。プロトコルはカスタム 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 を参照してください。

デプロイ

ドキュメントに記載されている3つの方法:

方法コマンド
ローカル開発(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

イメージは、Chromium を組み込んだマルチステージの node:22-slim で、PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium を設定しています。コンテナのヘルスチェックは、30秒ごとに node -e "require('http').get('http://localhost:2785/api/health', ...)" を実行します。

Compose プロファイル(postgres、redis、minio、with-dashboard、with-proxy、full)、ボリュームの配置(openwa-data:/app/data)、Docker ソケットのマウント(/var/run/docker.sock:ro — オーケストレーションに modules/docker が使用)、Traefik の静的/動的設定、K8s のヘルスプローブについては、deployment.md を参照してください。

設定 — 環境変数による3層の優先順位

ブートストラップ(src/main.ts:11-65)では、優先順位の最上位はプロセス環境変数となるよう、override: false を指定して dotenv を読み込みます。

process.env  >  ./.env  >  ./data/.env.generated

.env.generated はダッシュボードが書き込むファイルであり、優先順位は最下位です。よくある落とし穴は、ダッシュボードでの保存が Docker の environment: ブロックを上書きすると期待してしまうことですが、上書きされません。

初回起動時に data/.env.generated が存在しない場合、OpenWA は SQLite、ローカルストレージ、キュー無効の設定でファイルを書き込み、API キーを含むウェルカムバナーを表示します。

app.module.ts では、2つの TypeORM データベースを設定しています。

  • main 接続 — 常に SQLite です。API キーと監査ログを保存します。ノード内にとどめてください(移行しようとしないでください)。
  • data 接続 — SQLite または PostgreSQL です。セッション、メッセージ、Webhook を保存します。同期のデフォルトは SQLite では true、Postgres では false です(その場合は npm run migration:run:prod を実行します)。

環境変数の完全なリファレンス、.env.minimal、2つのデータベースの図、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 は、手書きの最小限の API(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 を抽象化します。代替エンジン(Baileys など)は、engine.factory.ts を介してその背後に組み込めます。ENGINE_TYPE で選択します。
  • StorageService — ローカルファイルシステムまたは S3/MinIO を使用し、STORAGE_TYPE で切り替えます。
  • CacheService — インメモリまたは Redis を使用し、REDIS_ENABLED で制御します。
  • プラグインフック — core/hooks/ が名前付きのフックチェーンを実行します。メッセージ送信パイプラインでは、ディスパッチ前に message:sending が実行され(プラグインは変更またはブロックが可能)、成功時に message:sent が実行されます。PLUGINS_ENABLED=true の場合、プラグインは自動的に読み込まれます。
  • キューの制御 — QUEUE_ENABLED === 'true' の場合にのみ、QueueModule を require します(src/app.module.ts:31-38)。無効の場合、Webhook の再試行はベストエフォートの同期処理のみです。

モジュールマップ、フック一覧、プラグインローダー、スケーリングモデル(エンジンはノードに固定、API キーはローカルに保持、データベースは共有可能)については、architecture.md を参照してください。

注意点

ドキュメントを読んでも、コードを確認しないと見落としがちな挙動をいくつか紹介します。

  1. .env.generated の優先順位は最も低く、最も高いわけではありません。
  2. API を再起動すると、すべての READY/INITIALIZING/QR_READY/AUTHENTICATING セッションが強制的に DISCONNECTED にリセットされます(エンジンはメモリ上にあるため、再起動すると失われます)。
  3. QUEUE_ENABLED=false(デフォルト)の場合、Webhook に再試行はありません。同期的なベストエフォート方式でディスパッチされます。
  4. SQLite のデフォルトは synchronize: true であり、本番環境では危険です。Postgres ではマイグレーションに切り替えてください。
  5. API キーは SQLite の main DB に保存されます。data DB を Postgres に切り替えても、API キーは移行されません。
  6. phone と pushName は、セッションが READY に達するまで null です。
  7. チャット ID の形式は <phone>@c.us / <id>@g.us である必要があります。形式が間違っていると、何も通知されずに失敗します。
  8. Chromium は必須です。Docker イメージでは PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium がハードコードされています。

ファイル名と行番号を含む注釈付きの全リスト:gotchas.md。

リファレンス一覧

リファレンス内容
deployment.mdDockerfile のステージ、Compose プロファイル、Traefik、K8s プローブ、ボリューム
configuration.md環境変数のリファレンス、優先順位、2 つの DB の構成、キューの制御
operation.mdセッションのライフサイクル、QR 認証、API キーの初期設定とライフサイクル、ダッシュボード
rest-api.mdコントローラーからルートまでの全カタログ、ロールデコレーター、リクエスト/レスポンスの形式
webhooks-and-events.mdWebhook ヘッダー、HMAC、再試行、冪等性、Socket.IO /events の通信形式
sdk.mdJS/TS および Python クライアントの使い方、fetch による代替方法、再生成に関する注意事項
architecture.mdモジュール構成、エンジン/ストレージ/キャッシュの差し替え、プラグインフック、スケーリング
gotchas.mdソースコードで確認した、直感的には分かりにくい挙動

コメント