Self-hosted WhatsApp API Gateway Platform
Send messages, manage multiple instances, configure webhooks, and monitor delivery — all via REST API.
🌐 Official Website: wavo.lumicloud.my.id
| Feature | Description |
|---|---|
| 📱 Multi-Instance WhatsApp | Connect and manage multiple WhatsApp accounts simultaneously |
| 📤 REST API Messaging | Send text, images, documents, and bulk broadcasts via API |
| 🔐 JWT + Refresh Token Rotation | Secure authentication with automatic token refresh and replay protection |
| 🔑 API Keys | Scoped server-to-server keys for programmatic access (wavo_sk_*) |
| 📊 Real-time Dashboard | Beautiful Next.js dashboard with live QR scanning, message logs, and analytics |
| 🪝 Webhooks | HMAC-signed webhook delivery for incoming messages and status updates |
| 📊 Message Queues | BullMQ-powered queues with plan-based priority (Enterprise → Pro → Free) |
| 🗄️ Object Storage | MinIO/S3-compatible media storage with local fallback |
| 📋 Audit Logs | Track all user actions for compliance and debugging |
| 🐳 Docker Ready | One-command deploy with Docker Compose |
wavo-monorepo/
├── apps/
│ ├── api/ # Fastify REST API + WebSocket (Baileys engine)
│ └── engine/ # Next.js 16 Dashboard (React 19, shadcn/ui)
├── packages/
│ └── database/ # Prisma ORM (schema, migrations, client)
├── docker/
│ └── api.Dockerfile # Multi-stage production Dockerfile
├── docker-compose.yml # Full-stack local development
└── docker-compose.dokploy.yml # Dokploy deployment
| Layer | Technology |
|---|---|
| API Server | Fastify 5, Socket.IO 4 |
| WhatsApp Engine | Baileys (unofficial WA Web API) |
| Message Queue | BullMQ + Redis 7 |
| Database | PostgreSQL 15 + Prisma 6 |
| Frontend | Next.js 16, React 19, Tailwind CSS 4, shadcn/ui, Framer Motion |
| Object Storage | MinIO (S3-compatible) with local fallback |
| Auth | JWT (access + refresh tokens), bcrypt, API keys |
| Runtime | Node.js 20 |
- Node.js ≥ 20
- PostgreSQL 15+
- Redis 7+
- npm ≥ 9 (uses npm workspaces)
git clone https://github.com/wahyujhoo17/WavoApp.git
cd WavoApp
npm install# Copy example env files
cp apps/api/.env.example apps/api/.env
cp apps/engine/.env.example apps/engine/.envEdit apps/api/.env:
DATABASE_URL=postgresql://postgres:password@localhost:5432/wavo?schema=public
REDIS_URL=redis://localhost:6379
JWT_PRIVATE_KEY=your_32_char_secret_key_here_ok
JWT_PUBLIC_KEY=your_32_char_secret_key_here_ok
ENCRYPTION_KEY=your_32_char_encryption_key_ok
PORT=4000Edit apps/engine/.env:
NEXT_PUBLIC_API_URL=http://localhost:4000/api/v1
NEXT_PUBLIC_WS_URL=ws://localhost:4000
NEXT_PUBLIC_APP_NAME=Wavo# Generate Prisma client
cd packages/database
npx prisma generate
# Run migrations
npx prisma migrate dev
# (Optional) Seed demo data
npx prisma db seed
cd ../..# Terminal 1 — API Server
cd apps/api
npm run dev
# → http://localhost:4000
# Terminal 2 — Dashboard
npm run dev:engine
# → http://localhost:3001docker compose up --buildThis spins up the entire stack:
| Service | Port | Description |
|---|---|---|
api |
4000 | Fastify API + WebSocket |
wavo-frontend |
3000 | Next.js Dashboard |
postgres |
5432 | PostgreSQL database |
redis |
6379 | Redis (BullMQ queues) |
minio |
9000 | Object storage |
⚠️ Important on Docker Environment Variables: When running the application inside Docker containers, do not uselocalhostor127.0.0.1for external services like Database and Redis in your.env. Instead, use the container service names defined indocker-compose.yml:
- Database URL:
DATABASE_URL=postgresql://postgres:postgres_password@postgres:5432/wavo?schema=public- Redis URL:
REDIS_URL=redis://redis:6379
See DOKPLOY.md for detailed Dokploy deployment instructions.
Quick setup:
- Create a Compose app in Dokploy pointing to
docker-compose.dokploy.yml - Add environment variables (see env-examples/.env.dokploy)
- Set domains for API and Frontend services
- Deploy
⚠️ Important: The API Dockerfile requires the repository root as build context becauseapps/apidepends on the workspace packagepackages/database(Prisma).
Base URL: http://localhost:4000/api/v1
# Register
curl -X POST http://localhost:4000/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com", "password": "secret123", "fullName": "John Doe"}'
# Login
curl -X POST http://localhost:4000/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com", "password": "secret123"}'# Send text message
curl -X POST http://localhost:4000/api/v1/send/text \
-H "Authorization: Bearer <TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"serviceId": "your-service-uuid",
"to": "6281234567890",
"message": "Hello from Wavo!"
}'| Method | Path | Description | Auth |
|---|---|---|---|
POST |
/auth/register |
Create account | — |
POST |
/auth/login |
Sign in → JWT + refresh token | — |
POST |
/auth/refresh |
Rotate refresh token | — |
POST |
/auth/logout |
Revoke session | JWT |
GET |
/services |
List WhatsApp instances | JWT |
POST |
/services |
Create instance | JWT |
POST |
/services/:id/connect |
Connect & get QR code | JWT |
POST |
/services/:id/disconnect |
Disconnect instance | JWT |
POST |
/send/text |
Send text message | JWT / API Key |
POST |
/send/bulk |
Broadcast (up to 500) | JWT / API Key |
POST |
/send/image |
Send image (multipart) | JWT / API Key |
GET |
/logs |
Message logs (cursor pagination) | JWT |
GET |
/analytics |
Stats & metrics | JWT |
POST |
/webhooks |
Configure webhook | JWT |
POST |
/api-keys |
Generate API key | JWT |
Full interactive API documentation available at the Dashboard → Docs page.
Wavo delivers real-time HTTP POST notifications signed with HMAC SHA-256:
Events:
message.received— Incoming message from a contactmessage.sent— Outgoing message deliveredmessage.failed— Delivery failureinstance.connected— WhatsApp connectedinstance.disconnected— WhatsApp disconnected
Verification:
const crypto = require('crypto');
app.post('/webhook', (req, res) => {
const signature = req.headers['x-wavo-signature'];
const computed = crypto
.createHmac('sha256', process.env.WAVO_WEBHOOK_SECRET)
.update(JSON.stringify(req.body))
.digest('hex');
if (signature === computed) {
// ✓ Authentic — process event
res.status(200).send('OK');
} else {
res.status(401).send('Invalid signature');
}
});Key models managed by Prisma:
| Model | Description |
|---|---|
User |
Accounts with role (USER/ADMIN) and plan (FREE/PRO/BUSINESS/ENTERPRISE) |
Session |
JWT refresh tokens with token family tracking for RTR |
WhatsAppService |
Connected WhatsApp instances with encrypted session storage |
ApiKey |
Scoped API keys with SHA-256 hashing (wavo_sk_* prefix) |
WebhookConfig |
Webhook URLs with HMAC signing secrets |
MessageLog |
Full message history with status tracking |
QueueJob |
BullMQ job tracking with priority queues |
AuditLog |
User action audit trail |
# View database in Prisma Studio
cd packages/database
npx prisma studioapps/
├── api/
│ └── src/
│ ├── config/ # Environment validation
│ ├── routes/ # Fastify route handlers
│ │ ├── auth.ts # Register, login, refresh, logout, profile
│ │ ├── services.ts # WhatsApp instance CRUD + connect/disconnect
│ │ ├── messaging.ts # Send text, bulk, image
│ │ └── logs.ts # Message logs + analytics
│ ├── services/ # Business logic
│ │ ├── whatsapp.ts # Baileys session manager
│ │ ├── queue.ts # BullMQ queue workers
│ │ ├── webhook.ts # Webhook dispatcher
│ │ └── storage.ts # MinIO/local file storage
│ ├── server.ts # Fastify + Socket.IO setup
│ └── index.ts # Bootstrap entry point
└── engine/
└── src/
├── app/ # Next.js App Router pages
├── components/ # React components (shadcn/ui)
└── lib/ # API client, utilities
packages/
└── database/
├── prisma/
│ ├── schema.prisma # Database schema
│ └── migrations/ # Migration history
└── src/ # Prisma client export
- Password Hashing — bcrypt with configurable rounds (default: 12)
- JWT — Short-lived access tokens (15m) + refresh token rotation with family tracking
- Token Replay Detection — Reusing a revoked refresh token terminates the entire session family
- API Key Hashing — Keys stored as SHA-256 hashes; full key shown only once at creation
- Webhook Signing — HMAC SHA-256 signatures on all webhook deliveries
- Session Encryption — WhatsApp session credentials encrypted with AES-256-GCM
- Input Validation — Zod schemas on all API endpoints
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is private and proprietary.
Built with ❤️ by the Wavo team


