WhatsApp REST API powered by Baileys WA Sockets. Built with Hono + TypeScript and features Dual-Runtime Support (runs natively on Bun or Node.js). Includes a built-in Visual Dashboard for easy management, keep clean simple and avoid heavy over-engineering.
Note
This project is not meant to be a full-fledged WhatsApp server. It is a wrapper around the Baileys library, providing an HTTP interface for easier integration with other applications, don't use it for spamming or any activities that's prohibited by WhatsApp META.
Disclaimer: This project is 100% AI-assisted and intended for educational purposes only. It will be maintained as a side project in spare time only, with no guarantees of ongoing support, updates, or production readiness.
Thus, we do not store WhatsApp messages or any other data (aside from credentials for auto-reconnecting).
| Feature | Description |
|---|---|
| Dual Runtime Support | Run on ultra-fast Bun or standard Node.js (cPanel/VPS compatible) |
| Visual Dashboard | Built-in UI to manage sessions, webhooks, and send messages |
| Dashboard RBAC | Role-based access (admin, manager, assistant) + approvals |
| Session Assignment ACL | Optional per-user assigned sessions (dashboard scope only) |
| Multi-Session | Manage multiple WhatsApp accounts simultaneously |
| QR Code & Pairing Code | Connect via QR scan or 8-digit pairing code |
| Complete Chat API | Send text, media, forward, delete, read messages |
| Broadcast Queue | Bulk message sending with anti-spam delays |
| Group & Profile | Full management (create, participants, status, picture) |
| Media Handling | Download, process, retrieve, and auto-cleanup old media |
| Webhook System | Retries, exponential backoff, and signature modes |
| Dual Auth State | Save session data to Files (dev) or Redis (production) |
| API Authentication | Bearer token or Redis-stored API keys with roles |
| Hardened Dashboard Auth | JWT auth, stream token for SSE, password policy, approval flow |
| Swagger/OpenAPI | Built-in interactive API documentation at /docs |
| Docker Support | Ready-to-use Dockerfiles for both Bun and Node.js |
- Bun: Ultra-fast, ideal for VPS or Home Servers (Recommended).
- Node.js: Standard, portable, ideal for cPanel VPS or traditional Node.js hosting.
- Docker: Containerized deployment. Ensure you have Docker Compose installed.
# Clone the repository
git clone <repository-url>
cd baileys-wa-api
# Configure Environment
cp .env.example .env
# Edit .env and configure DASHBOARD_JWT_SECRETbun install
# Development (Auto-reload)
bun run dev
# Production Build
bun run startnpm install
# Development (via tsx watch)
npm run dev:node
# Production Build
npm run start:nodeThe API will start at http://localhost:3000. Access the following default routes:
- π₯οΈ Dashboard:
http://localhost:3000/dashboard/ - π Swagger Docs:
http://localhost:3000/docs - π Health Check:
http://localhost:3000/status
The project provides configurations for both runtimes. Redis is highly recommended and included in the docker-compose setups.
docker compose up -d
docker compose logs -f apiIf you prefer forcing the native Node.js container:
docker compose -f docker-compose.node.yml up -d
docker compose -f docker-compose.node.yml logs -f apiTo stop containers: docker compose down
The API includes an intuitive, modular web dashboard to manage everything visually without touching the CLI.
DASHBOARD_ENABLED=true
DASHBOARD_REGISTRATION_ENABLED=false
DASHBOARD_REGISTRATION_REQUIRE_APPROVAL=true
DASHBOARD_JWT_SECRET=super-secret-key-change-me
DASHBOARD_PASSWORD_MIN_LENGTH=6- Open
http://localhost:3000/dashboard/in your browser. - If
data/dashboard-users.jsonis empty, you will be prompted to create the very first Admin Account. - Create your account with a secure password (hashed via
bcryptjs). - Once created, recommended to set
DASHBOARD_REGISTRATION_ENABLED=falsein.envto prevent public sign-ups.
admin: full dashboard access (users/approval/roles, session lifecycle, webhooks, all messaging).manager: operational access for chats/outbound/groups, without admin-level account controls.assistant: reply-focused dashboard role (no proactive outbound), for safer delegated handling.- Optional
assignedSessions: per-user session scoping in dashboard APIs/UI only.
DASHBOARD_REGISTRATION_ENABLED=false: registration form is disabled for additional users.DASHBOARD_REGISTRATION_REQUIRE_APPROVAL=true: newly registered users remain pending until approved by admin.- The first bootstrap admin (when user file is empty) is created immediately.
- Sessions: Add WhatsApp accounts (QR/Pairing Code), Delete accounts safely (auto-cleans media/logs).
- Messaging: Test sending texts, images, and bulk broadcasts interactively.
- Webhooks: Configure webhook URLs and event subscriptions per-session.
- Events: Real-time SSE (Server-Sent Events) live log for WhatsApp events.
The raw REST API /chats, /groups, etc., supports two authentication methods:
Set AUTH_GLOBAL_TOKEN in .env:
AUTH_GLOBAL_TOKEN=your-secret-token-hereSupported headers for simple token mode:
Authorization: Bearer <token>x-api-key: <token>x-access-token: <token>token: <token>
Use in requests:
curl -H "Authorization: Bearer your-secret-token-here" http://localhost:3000/sessionsRequires REDIS_ENABLED=true. Manage keys using the CLI:
# Bun Runtime
bun run manage-api-keys create user
# Node.js Runtime
npm run manage-api-keys:node create adminUse header: x-api-key: <your-api-key>
# Create user API key
bun run manage-api-keys create user
# Create admin API key
bun run manage-api-keys create admin
# List all keys
bun run manage-api-keys list
# Delete a key
bun run manage-api-keys delete <api-key>Use in requests:
curl -H "x-api-key: <your-api-key>" http://localhost:3000/sessionsNote: In
developmentmode (NODE_ENV=development), API authentication is skipped entirely.
- Dashboard endpoints (
/dashboard/api/*) use JWT-based auth. - SSE/Event stream endpoints use short-lived stream-scoped tokens.
- Stream token endpoint:
GET /dashboard/api/auth/stream-token
POST /sessions/my-session
Content-Type: application/json
{
"usePairingCode": true,
"phoneNumber": "+6281234567890",
"webhookUrl": "http://your-server.com/webhook"
}POST /chats/my-session/send
Content-Type: application/json
{
"receiver": "6281234567890",
"message": {
"image": { "url": "https://example.com/image.jpg" },
"caption": "Check this out!"
}
}POST /chats/my-session/send-bulk
Content-Type: application/json
{
"messages": [
{ "receiver": "6281234567890", "message": { "text": "Hello #1" } },
{ "receiver": "6281234567891", "message": { "text": "Hello #2" } }
]
}Response:
{
"success": true,
"message": "Broadcast job created",
"data": { "jobId": "bc_1709271000_abc123", "total": 3, "status": "pending" }
}Track progress:
GET /chats/my-session/broadcast/bc_1709271000_abc123POST /groups/my-session/create
Content-Type: application/json
{
"groupName": "API Test Group",
"participants": ["6281234567890", "6281234567891"]
}Set WEBHOOK_URL in .env or per-session. Events are sent as POST:
{
"sessionId": "my-session",
"event": "messages.upsert",
"data": { "messages": [...], "type": "notify" }
}When signature mode is enabled, webhook requests can include:
x-webhook-timestampx-webhook-signature: sha256=<hmac>
Controlled by:
WEBHOOK_SIGNATURE_MODE=off|optional|requiredWEBHOOK_ALLOW_GLOBAL_TOKEN_FALLBACK=true|false
Fallback order for webhook auth/signing secret:
- Per-session webhook secret
AUTH_GLOBAL_TOKEN(only when fallback is enabled)
Available events:
connection.updateβ Connection state changes (QR, open, close)messages.upsertβ New messages receivedmessages.updateβ Message status updates (sent, delivered, read)messages.deleteβ Messages deletedmessages.reactionβ Reactions added/removedchats.upsert,chats.update,chats.deletecontacts.upsert,contacts.updategroups.upsert,groups.updategroup-participants.updatepresence.updateblocklist.set,blocklist.update
baileys-wa-api/
βββ data/ # Dashboard users and internal dashboard data (JSON)
βββ media/ # Downloaded media files
βββ sessions/ # Auth/session state per WhatsApp session
βββ scripts/
β βββ manage-api-keys.ts # API key management CLI
βββ src/
β βββ index.ts # Runtime entry point (Bun/Node)
β βββ app.ts # Hono app bootstrap + routes + docs
β βββ config.ts # Centralized environment config
β βββ baileys/
β β βββ connection.ts # BaileysConnection class
β β βββ connectionManager.ts # Multi-session manager
β β βββ types.ts # Type definitions
β β βββ authState/
β β β βββ index.ts # Auth state factory
β β β βββ file.ts # File-based auth
β β β βββ redis.ts # Redis-based auth
β β βββ store/
β β β βββ memoryStore.ts # In-memory message store
β β βββ helpers/
β β βββ downloadMedia.ts # Media download utilities
β β βββ shouldIgnoreJid.ts # JID filtering
β βββ dashboard/
β β βββ api.ts # Dashboard backend APIs (stats/events/webhooks)
β β βββ auth.ts # Dashboard auth + users/roles/approval
β β βββ eventBus.ts # In-process event bus for SSE
β β βββ loader.ts # Dashboard route/static loader
β βββ dashboard-ui/
β β βββ index.html # Dashboard SPA shell
β β βββ css/
β β β βββ styles.css
β β βββ js/
β β βββ api.js
β β βββ app.js
β β βββ auth.js
β β βββ theme.js
β β βββ components/
β β β βββ modal.js
β β β βββ toast.js
β β βββ pages/ # overview/sessions/chatrooms/groups/webhooks/events/settings
β βββ lib/
β β βββ logger.ts # Pino logger
β β βββ redis.ts # Redis client helpers
β β βββ response.ts # API response helpers
β β βββ runtime.ts # Bun/Node runtime abstraction
β βββ middleware/
β β βββ auth.ts # API authentication
β β βββ rateLimit.ts # API rate limiting
β β βββ sessionValidator.ts # Session existence check
β βββ routes/
β β βββ session.ts # Session CRUD
β β βββ chat.ts # Chat operations
β β βββ group.ts # Group management
β β βββ profile.ts # Profile management
β β βββ media.ts # Media handling
β β βββ story.ts # Story broadcasting
β β βββ status.ts # Server health
β βββ schemas/
β β βββ chat.ts # Chat schemas
β β βββ group.ts # Group schemas
β β βββ session.ts # Session schemas
β βββ services/
β β βββ broadcastQueue.ts # Broadcast queue with delays
β β βββ mediaCleanup.ts # Media file cleanup
β β βββ webhookLog.ts # Webhook delivery log storage
β βββ utils/
β βββ asyncSleep.ts # Async sleep utilities
β βββ phone.ts # Phone/JID formatting
β βββ validation.ts # Validation utilities
βββ .env.example
βββ biome.jsonc
βββ docker-compose.yml
βββ docker-compose.node.yml
βββ Dockerfile
βββ Dockerfile.node
βββ package.json
βββ tsconfig.json
βββ README.md
| Variable | Default | Description |
|---|---|---|
NODE_ENV |
development |
Environment (development / production) |
HOST |
0.0.0.0 |
Server host |
PORT |
3000 |
Server port |
LOG_LEVEL |
info |
Log level (debug, info, warn, error) |
AUTH_GLOBAL_TOKEN |
β | Simple auth token |
REDIS_ENABLED |
false |
Enable Redis integration |
REDIS_URL |
redis://localhost:6379 |
Redis connection URL |
REDIS_PASSWORD |
β | Redis password |
BAILEYS_LOG_LEVEL |
warn |
Baileys internal log level |
MAX_RETRIES |
5 |
Max reconnection attempts |
RECONNECT_INTERVAL |
5000 |
Reconnection delay (ms) |
MAX_SESSIONS |
50 |
Maximum concurrent WhatsApp sessions |
WEBHOOK_URL |
β | Default webhook URL |
WEBHOOK_SIGNATURE_MODE |
off |
Webhook signature mode (off, optional, required) |
WEBHOOK_ALLOW_GLOBAL_TOKEN_FALLBACK |
true |
Allow fallback to AUTH_GLOBAL_TOKEN for webhook secret/signature |
WEBHOOK_ALLOWED_EVENTS |
ALL |
Comma-separated event filter |
WEBHOOK_RETRY_MAX |
3 |
Webhook delivery retry count |
WEBHOOK_RETRY_INTERVAL |
5000 |
Initial webhook retry delay (ms) |
WEBHOOK_BACKOFF_FACTOR |
3 |
Exponential backoff multiplier |
BROADCAST_MIN_DELAY_MS |
1500 |
Min delay between bulk messages |
BROADCAST_MAX_DELAY_MS |
3000 |
Max delay between bulk messages |
BROADCAST_BATCH_SIZE |
10 |
Messages per batch before pause |
BROADCAST_BATCH_PAUSE_MS |
5000 |
Pause between batches |
MEDIA_INCLUDE_BASE64 |
false |
Include media in webhooks |
MEDIA_CLEANUP_ENABLED |
true |
Auto-delete old media files |
MEDIA_CLEANUP_INTERVAL_MS |
3600000 |
Media cleanup interval (ms) |
MEDIA_MAX_AGE_HOURS |
24 |
Max age of media files |
CORS_ORIGIN |
* |
CORS allowed origins |
DASHBOARD_ENABLED |
true |
Enable internal UI dashboard |
DASHBOARD_REGISTRATION_ENABLED |
false |
Allow account creation |
DASHBOARD_REGISTRATION_REQUIRE_APPROVAL |
true |
Require admin approval before new user can login |
DASHBOARD_PASSWORD_MIN_LENGTH |
6 |
Minimum password length for dashboard users |
DASHBOARD_JWT_SECRET |
change-this-to-a-random-secret |
JWT secret for dashboard auth |
SIMULATE_TYPING_BEFORE_SEND |
true |
Auto-send "composing" presence before each message (default: true) |
SIMULATE_TYPING_DELAY_MIN_MS |
1500 |
Typing delay range in ms (random between min-max) |
SIMULATE_TYPING_DELAY_MAX_MS |
3000 |
Typing delay range in ms (random between min-max) |
AUTO_READ_MESSAGES |
false |
Auto-mark incoming messages as read (default: false, like WA Web toggle) |
AUTO_MARK_ONLINE |
true |
Auto-set presence to "available" when sending messages (default: true) |
Use these commands for validation and maintenance:
# Type-check only
npm run build-check
# Lint with error-level gate
npm run lint
# Full lint diagnostics
npm run lint:all
# Auto-format/fix source files
npm run formatAPI key helper:
# Bun runtime
bun run manage-api-keys create admin
# Node runtime
npm run manage-api-keys:node create adminThis project is licensed under the MIT License - see the LICENSE file for details.