Production-ready Node.js server for WhatsApp Flows with automated CI/CD, multi-arch Docker support, and DDD architecture
Features β’ Quick Start β’ Documentation β’ Architecture β’ Contributing
WhatsApp Flow Server is a robust, production-ready TypeScript server that implements the WhatsApp Flows API using Domain-Driven Design (DDD) principles. It provides a complete solution for handling WhatsApp Flow interactions with built-in encryption, webhook processing, and comprehensive CI/CD automation.
WhatsApp Flows enable rich, interactive experiences within WhatsApp, but implementing them requires:
- Complex encryption (RSA-2048 + AES-128-GCM with mandatory IV flip)
- Dual endpoint architecture (Flow Data API + Webhooks)
- Strict performance requirements (<3s response time)
- Secure key management and Meta API integration
- Production-ready infrastructure with monitoring and scaling
This server solves all these challenges with:
- β Pre-configured encryption with IV flip pattern
- β Dual endpoint architecture out-of-the-box
- β Automatic database migrations
- β Multi-architecture Docker support (AMD64 + ARM64)
- β Complete CI/CD pipeline with semantic versioning
- β Production-ready with health checks and logging
- ποΈ Domain-Driven Design - Clean architecture with separated layers (Domain, Application, Infrastructure)
- π WhatsApp Flow Encryption - Complete RSA-2048 + AES-128-GCM implementation with mandatory IV flip
- π Dual Endpoint System - Flow Data API + Webhook receiver with signature validation
- π PostgreSQL Storage - Persistent storage for Flows, Sessions, and Responses
- β Schema Validation - Type-safe with Zod v4
- π Structured Logging - Winston with rotation and multiple transports
- π³ Multi-Arch Docker - Native support for AMD64 (Intel/AMD) and ARM64 (Apple Silicon, AWS Graviton)
- π Automated CI/CD - GitHub Actions with semantic release and Docker Hub publishing
- π¦ Conventional Commits - Automated versioning and changelog generation
- π Auto Migrations - Database migrations run automatically on container startup
- πͺ Production Ready - Health checks, monitoring, and graceful shutdown
- π οΈ TypeScript 5.9 - Full type safety with strict mode
- π¨ Modern Stack - Express 5.x, PostgreSQL 18, Node.js 20+
- π§ Developer Tools - ESLint, Prettier, Husky, Commitlint
- π Comprehensive Docs - Complete guides for setup, deployment, and troubleshooting
- π§ͺ Testing Ready - Structure prepared for unit and integration tests
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β WhatsApp Platform β
ββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββ¬ββββββββββββββ
β β
β Encrypted Flow Data β Webhook Events
β (RSA-2048 + AES-128-GCM) β (nfm_reply)
βΌ βΌ
βββββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββ
β Flow Endpoint (Data API) β β Webhook Endpoint β
β POST /flows/endpoint/:id β β POST /webhooks/whatsappβ
β β β β
β - Decrypt request β β - Validate signature β
β - Process action β β - Parse response_json β
β - Return encrypted data β β - Forward to callback β
β - < 3s response time β β - Store in database β
ββββββββββββββββ¬βββββββββββββββ ββββββββββββ¬ββββββββββββββββ
β β
β β
βΌ βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Application Layer β
β β
β ββββββββββββββββββββββββ βββββββββββββββββββββββββββ β
β β HandleFlowRequest β β ProcessWebhook β β
β β UseCase β β UseCase β β
β ββββββββββββ¬ββββββββββββ βββββββββββββ¬ββββββββββββββ β
β β β β
β βΌ βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Domain Layer (Business Logic) β β
β β β β
β β β’ FlowEngine - Navigation and data exchange β β
β β β’ Flow - Immutable Flow templates β β
β β β’ FlowSession - User session tracking β β
β β β’ FlowResponse - Completed Flow data β β
β β β’ EncryptionService - RSA/AES with IV flip β β
β ββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ β
β β β
βββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Infrastructure Layer β
β β
β ββββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββ β
β β PostgreSQL β β Express HTTP β β Axios HTTP β β
β β Repositories β β Server β β Client β β
β ββββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββ β
β β
β Database Tables: β
β β’ flows - Flow JSON templates β
β β’ flow_sessions - Active/completed sessions β
β β’ flow_responses - Completed Flow data β
β β’ webhook_events - Webhook audit trail β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
User WhatsApp Flow Server Database Your System
β β β β β
β Click Flow Button β β β β
ββββββββββββββββββββ>β β β β
β β β β β
β β POST /flows/endpoint (INIT) β β
β ββββββββββββββββββββ>β β β
β β β Create Session β β
β β βββββββββββββββββ>β β
β β β Return INIT β β
β β<ββββββββββββββββββββ€ β β
β β β β β
β Display Screen 1 β β β β
β<ββββββββββββββββββββ€ β β β
β β β β β
β Fill & Submit β β β β
ββββββββββββββββββββ>β β β β
β β POST /flows/endpoint (data_exchange) β β
β ββββββββββββββββββββ>β β β
β β β Update Session β β
β β βββββββββββββββββ>β β
β β β Return Screen 2 β β
β β<ββββββββββββββββββββ€ β β
β β β β β
β Display Screen 2 β β β β
β<ββββββββββββββββββββ€ β β β
β β β β β
β Complete Flow β β β β
ββββββββββββββββββββ>β β β β
β β POST /flows/endpoint (complete) β β
β ββββββββββββββββββββ>β β β
β β β Mark Complete β β
β β βββββββββββββββββ>β β
β β β β β
β β POST /webhooks/whatsapp (nfm_reply) β β
β ββββββββββββββββββββ>β β β
β β β Store Response β β
β β βββββββββββββββββ>β β
β β β Forward Data β β
β β βββββββββββββββββββββββββββββββββ>β
β β β β β
β "Thank you!" β β β β
β<ββββββββββββββββββββ€ β β β
WhatsApp Request Server Response
β β
β Encrypted with: β Encrypted with:
β β’ AES key encrypted by RSA β β’ FLIPPED IV β οΈ
β β’ Normal IV β β’ Same AES key
β β
βΌ βΌ
ββββββββββββββββββ ββββββββββββββββββ
β Decrypt AES Keyβ β Flip IV Buffer β
β with RSA β β (reverse bytes)β
βββββββββ¬βββββββββ ββββββββββ¬ββββββββ
β β
βΌ βΌ
ββββββββββββββββββ ββββββββββββββββββ
β Decrypt Payloadβ β Encrypt Payloadβ
β with AES β β with AES β
β (normal IV) β β (flipped IV) β
βββββββββ¬βββββββββ ββββββββββ¬ββββββββ
β β
βΌ βΌ
Flow Data Encrypted Response
- Node.js >= 20.0.0
- Docker & Docker Compose (recommended) or PostgreSQL 18+
- WhatsApp Business Account with Flows enabled
- Meta Developer Account for API credentials
# 1. Clone the repository
git clone https://github.com/guilhermejansen/whatsapp-flows-server.git
cd whatsapp-flows-server
# 2. Configure environment
cp .env.docker.example .env
nano .env # Edit with your credentials
# 3. Start services
docker-compose up -d
# 4. Generate encryption keys
docker-compose exec app npm run generate-keys
# Copy output to .env
# 5. Restart application
docker-compose restart app
# 6. Register public key with Meta
docker-compose exec app npm run register-key
# 7. Verify health
curl http://localhost:3000/healthYour server is now running! π
Configure WhatsApp Manager:
- Flow Endpoint:
https://your-domain.com/flows/endpoint/csat-feedback - Webhook URL:
https://your-domain.com/webhooks/whatsapp
# 1. Clone and install
git clone https://github.com/guilhermejansen/whatsapp-flows-server.git
cd whatsapp-flows-server
npm install
# 2. Setup PostgreSQL
createdb whatsapp_flows
npm run migrate
# 3. Generate keys
npm run generate-keys
# Copy output to .env
# 4. Configure environment
cp .env.example .env
nano .env # Edit with your credentials
# 5. Register public key
npm run register-key
# 6. Start development server
npm run devPre-built images available for AMD64 (Intel/AMD) and ARM64 (Apple Silicon, AWS Graviton):
# Pull latest version
docker pull setupautomatizado/whatsapp-flows-server:latest
# Or specific version
docker pull setupautomatizado/whatsapp-flows-server:1.0.0# Create directory
mkdir -p ~/whatsapp-flows-server-production
cd ~/whatsapp-flows-server-production
# Download compose file
curl -O https://raw.githubusercontent.com/guilhermejansen/whatsapp-flows-server/main/docker-compose.yml
# Configure environment
curl -O https://raw.githubusercontent.com/guilhermejansen/whatsapp-flows-server/main/.env.docker.example
cp .env.docker.example .env
nano .env# Install Nginx + Certbot
sudo apt update
sudo apt install nginx certbot python3-certbot-nginx -y
# Configure Nginx
sudo nano /etc/nginx/sites-available/whatsapp-flows-serverNginx Configuration:
server {
listen 443 ssl http2;
server_name your-domain.com;
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WhatsApp requires < 3s response
proxy_connect_timeout 2s;
proxy_send_timeout 2s;
proxy_read_timeout 2s;
}
}# Enable site
sudo ln -s /etc/nginx/sites-available/whatsapp-flows-server /etc/nginx/sites-enabled/
sudo nginx -t
# Get SSL certificate
sudo certbot --nginx -d your-domain.com
# Restart Nginx
sudo systemctl restart nginx# Start services
docker-compose up -d
# Generate keys
docker-compose exec app npm run generate-keys
# Add keys to .env
# Restart
docker-compose restart app
# Register public key
docker-compose exec app npm run register-key
# Verify
curl https://your-domain.com/health# View logs
docker-compose logs -f app
# Shell access
docker-compose exec app sh
# Database access
docker-compose exec postgres psql -U whatsapp_flow -d whatsapp_flows
# Run migrations manually
docker-compose exec app npm run migrate
# Backup database
docker-compose exec postgres pg_dump -U whatsapp_flow whatsapp_flows > backup.sql
# Stop services
docker-compose down| Variable | Description | Required | Example |
|---|---|---|---|
NODE_ENV |
Environment mode | β | production |
PORT |
Server port | β | 3000 |
DATABASE_URL |
PostgreSQL connection string | β | postgresql://user:pass@localhost:5432/db |
PRIVATE_KEY |
RSA private key (PEM format) | β | -----BEGIN RSA PRIVATE KEY-----\n... |
PUBLIC_KEY |
RSA public key (PEM format) | β | -----BEGIN PUBLIC KEY-----\n... |
META_APP_SECRET |
Meta app secret | β | your_app_secret |
META_VERIFY_TOKEN |
Webhook verify token | β | your_verify_token |
META_ACCESS_TOKEN |
WhatsApp API access token | β | EAAB... |
CALLBACK_WEBHOOK_URL |
Your callback URL for completed flows | β | https://yourapi.com/webhook |
DEFAULT_FLOW_NAME |
Default flow when not specified | csat-feedback |
|
FLOW_ENDPOINT_TIMEOUT |
Max response time (< 3000ms) | 2500 |
|
CORS_ORIGINS |
Allowed CORS origins | https://app.com |
|
API_TOKEN |
API authentication token | Generated with openssl rand -hex 32 |
Legend: β
Required |
# Generate RSA-2048 key pair
npm run generate-keys
# Validate keys
npm run validate-keys
# Register public key with Meta
npm run register-keyThis server implements WhatsApp's mandatory IV flip pattern for encryption:
// Decryption (incoming from WhatsApp) - Normal IV
const iv = Buffer.from(initialVector, 'base64');
const decipher = crypto.createDecipheriv('aes-128-gcm', aesKey, iv);
// Encryption (outgoing to WhatsApp) - FLIPPED IV β οΈ
const iv = Buffer.from(initialVector, 'base64');
const flippedIV = Buffer.from(iv).reverse(); // Must reverse!
const cipher = crypto.createCipheriv('aes-128-gcm', aesKey, flippedIV);Critical: If IV is not flipped, WhatsApp returns error 421.
- β Never commit private keys to Git
- β Use environment variables for all secrets
- β Rotate tokens every 3-6 months
- β Enable HTTPS in production (required by WhatsApp)
- β Validate webhooks with X-Hub-Signature-256
- β Run as non-root user in Docker
- β Keep dependencies updated via Dependabot
See SECURITY.md for vulnerability reporting.
Endpoint: POST /flows/endpoint/:flowName
Handles encrypted interactions during Flow execution.
Actions:
ping- Health checkINIT- Initialize Flow sessiondata_exchange- Process user input and navigatenavigate- Explicit screen navigationcomplete- Mark Flow as completed
Headers:
Content-Type: application/json
Example Request (INIT):
{
"version": "3.0",
"action": "INIT",
"flow_token": "unique_token_123",
"encrypted_flow_data": "...",
"encrypted_aes_key": "...",
"initial_vector": "..."
}Response: Encrypted Flow data with next screen
Endpoint: POST /webhooks/whatsapp
Receives nfm_reply events when user completes Flow.
Headers:
Content-Type: application/json
X-Hub-Signature-256: sha256=...
Example Payload:
{
"entry": [{
"changes": [{
"value": {
"messages": [{
"type": "interactive",
"interactive": {
"type": "nfm_reply",
"nfm_reply": {
"response_json": "{\"flow_token\":\"...\",\"data\":...}",
"name": "flow_name"
}
}
}]
}
}]
}]
}Important: response_json is a string, must be parsed with JSON.parse().
Endpoint: GET /health
Response:
{
"status": "ok",
"timestamp": "2025-01-27T12:00:00.000Z",
"version": "1.0.0",
"uptime": 3600,
"database": "connected"
}Interactive API docs available at /docs when server is running.
- WhatsApp Flows Overview
- Flow Endpoint Implementation
- Receiving Flow Response
- Flow JSON Reference
- Encryption Guide
whatsapp-flow/
βββ src/
β βββ domain/ # Business entities and rules
β β βββ flows/ # Flow, FlowSession entities
β β βββ encryption/ # Encryption services
β β βββ webhooks/ # Webhook events
β βββ application/ # Use cases (business logic)
β β βββ dtos/ # Data Transfer Objects
β β βββ use-cases/ # HandleFlowRequest, ProcessWebhook
β βββ infrastructure/ # External implementations
β β βββ database/ # PostgreSQL repositories
β β βββ http/ # Express server & routes
β β βββ security/ # Encryption implementation
β βββ shared/ # Common utilities
β βββ main.ts # Application entry point
βββ scripts/ # Utility scripts
β βββ migrations/ # SQL migration files
β βββ generate-keys.ts # RSA key generator
β βββ seed-*.ts # Database seeders
βββ .github/ # CI/CD workflows
βββ docker-compose.yml # Docker orchestration
βββ Dockerfile # Multi-arch container
βββ tsconfig.json # TypeScript configuration
# Development
npm run dev # Start with watch mode
npm run build # Build TypeScript
npm start # Start production server
# Database
npm run migrate # Run migrations
# Encryption
npm run generate-keys # Generate RSA keys
npm run validate-keys # Validate configuration
npm run register-key # Register public key with Meta
# Code Quality
npm run lint # Run ESLint
npm run format # Format with Prettier
npm run format:check # Check formatting
# Git
npm run commit # Interactive commit helper (Conventional Commits)Migrations run automatically on container startup. To run manually:
# Local
npm run migrate
# Docker
docker-compose exec app npm run migrateMethod 1: Via API
curl -X POST http://localhost:3000/api/flows \
-H "Content-Type: application/json" \
-d '{
"name": "my-flow",
"version": "7.2",
"flow_json": {"version":"7.2","screens":[...]},
"description": "My custom flow"
}'Configure in WhatsApp Manager:
https://your-domain.com/flows/endpoint/my-flow
This project includes complete CI/CD automation:
- β ESLint validation
- β Prettier format check
- β TypeScript compilation check
- β Application build test
- β Security audit (npm audit)
- β Analyze commits (Conventional Commits)
- β Calculate next version (major/minor/patch)
- β Generate CHANGELOG.md
- β Create GitHub Release
- β Build multi-arch Docker image (AMD64 + ARM64)
- β Publish to Docker Hub with semantic tags
# Patch version (1.0.0 β 1.0.1)
git commit -m "fix: resolve webhook signature validation"
# Minor version (1.0.0 β 1.1.0)
git commit -m "feat: add support for multiple flows"
# Major version (1.0.0 β 2.0.0)
git commit -m "feat!: migrate to PostgreSQL 18
BREAKING CHANGE: Database volume path changed"
# No release
git commit -m "docs: update README"
git commit -m "chore: update dependencies"For automated Docker publishing:
DOCKER_USERNAME = your_dockerhub_username
DOCKER_TOKEN = your_dockerhub_token
Contributions are welcome! Please follow these guidelines:
- Fork the repository
- Clone your fork:
git clone https://github.com/YOUR_USERNAME/whatsapp-flow.git - Create a branch:
git checkout -b feat/amazing-feature - Install dependencies:
npm install - Make your changes
- Test thoroughly
- Commit using Conventional Commits:
git commit -m "feat: add amazing feature" - Push to your fork:
git push origin feat/amazing-feature - Open a Pull Request
- β Follow TypeScript strict mode
- β Use Conventional Commits format
- β Pass all CI checks (lint, format, typecheck, build)
- β Add tests for new features
- β Update documentation as needed
- β Follow DDD architecture patterns
- Ensure CI passes (lint, format, typecheck, build)
- Update README.md if adding features
- Request review from maintainers
- Address review comments
- Squash commits before merge (if requested)
| Category | Technology | Version |
|---|---|---|
| Runtime | Node.js | β₯ 20.0.0 |
| Language | TypeScript | 5.9 |
| Framework | Express | 5.x |
| Database | PostgreSQL | 18 |
| Encryption | Node RSA + Crypto | Native |
| Validation | Zod | 4.x |
| Logging | Winston | 3.x |
| Container | Docker | Multi-arch |
| CI/CD | GitHub Actions | Latest |
| Versioning | Semantic Release | 23.x |
- β‘ Response Time: < 3s (WhatsApp requirement)
- β‘ Default Timeout: 2.5s (configurable)
- π¦ Docker Image: ~150MB (multi-stage build)
- π Startup Time: ~5-10s (includes migrations)
- πΎ Memory Usage: ~50-100MB (base)
1. "Failed to decrypt AES key"
# Regenerate keys
npm run generate-keys
# Test encryption
npm run test-encryption
# Verify .env has correct format (with \n)2. "Webhook signature validation failed"
# Verify META_APP_SECRET matches Meta dashboard
# Check webhook payload is valid JSON
# Ensure X-Hub-Signature-256 header is present3. "Database connection refused"
# Check PostgreSQL is running
docker-compose ps
# Verify DATABASE_URL in .env
# Check network connectivity4. "Migrations failed"
# Run manually with logs
docker-compose exec app npm run migrate
# Check database permissions
# Verify SQL syntax in migration files5. "WhatsApp error 421"
# Verify IV flip is implemented
# Check encryption format (RSA-2048 + AES-128-GCM)
# Ensure public key is registered with Meta
npm run register-keyThis project is licensed under the MIT License - see the LICENSE file for details.
TL;DR: You can use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of this software. Just include the original copyright notice.
Guilherme Jansen - Initial work & Maintainer
- Website: setupautomatizado.com.br
- GitHub: @guilhermejansen
- Email: guilherme@setupautomatizado.com.br
Want to join the board? Check the contributing guide and open your first PR!
- Meta/WhatsApp team for the Flows API
- DDD community for architectural patterns
- Open source contributors
If this project helped you, please consider giving it a β on GitHub!
- π Bug Reports: GitHub Issues
- π‘ Feature Requests: GitHub Discussions
- π Documentation: Check docs in repository
- π¬ Questions: Open a discussion
For enterprise support, custom integrations, or consulting:
- π§ Email: guilherme@setupautomatizado.com.br
- π Website: setupautomatizado.com.br
- Unit and integration tests
- GraphQL API option
- Admin dashboard (Flow management UI)
- Multi-tenancy support
- Flow analytics and metrics
- Flow template marketplace
- Kubernetes deployment guides
- Horizontal scaling documentation
- Rate limiting per Flow
- Webhook retry mechanism
Made with β€οΈ by Guilherme Jansen