# WhatsHooked A service that connects to WhatsApp and forwards messages to registered webhooks. Supports both personal WhatsApp accounts (via whatsmeow) and WhatsApp Business API. Enables two-way communication by allowing webhooks to respond with messages to be sent through WhatsApp. ![1.00](./assets/image/whatshooked.jpg) [TODO LIST](TODO.md) - Things I still need to do [Rules when using AI](AI_USE.md) ## Phase 1 Features - **Multi-Account Support**: Connect to multiple WhatsApp accounts simultaneously - **Dual Client Types**: Support for both personal WhatsApp (whatsmeow) and WhatsApp Business API - **Webhook Integration**: Register multiple webhooks to receive WhatsApp messages - **Two-Way Communication**: Webhooks can respond with messages to send back to WhatsApp - **Instance/Config Level Hooks**: Global hooks that receive all messages from all accounts - **Media Support**: Send and receive images, videos, and documents - **CLI Management**: Command-line tool for managing accounts and hooks - **Structured Logging**: JSON-based logging with configurable log levels - **Authentication**: HTTP Basic Auth and API key authentication for server endpoints ## Architecture The project uses an event-driven architecture with the following packages: - **internal/config**: Configuration management and persistence - **internal/logging**: Structured logging using Go's slog package - **internal/events**: Event bus for publish/subscribe messaging between components - **internal/whatsapp**: WhatsApp client management (supports both whatsmeow and Business API) - **whatsmeow/**: Personal WhatsApp client implementation - **businessapi/**: WhatsApp Business API client implementation - **internal/hooks**: Webhook management and message forwarding - **cmd/server**: Main server application - **cmd/cli**: Command-line interface for management ### Event-Driven Architecture The system uses a central event bus to decouple components: 1. **WhatsApp Events** → Event Bus → Hook Manager - Connection/disconnection events - Message received events - Message sent/failed events 2. **Hook Events** → Event Bus → WhatsApp Manager - Hook triggered events - Hook success/failure events - Webhook responses trigger message sends This architecture enables: - Loose coupling between WhatsApp and webhooks - Easy addition of new event subscribers - Centralized event logging and monitoring - Two-way communication through event responses - Context propagation for cancellation and timeout handling - Proper request lifecycle management across components ## Installation ### Build from source ```bash make build ``` Or manually: ```bash mkdir -p bin go build -o bin/whatshook-server ./cmd/server go build -o bin/whatshook-cli ./cmd/cli ``` ## Configuration Create a `config.json` file based on the example: ```bash cp config.example.json config.json ``` Edit the configuration file to add your WhatsApp accounts and webhooks: ```json { "server": { "host": "localhost", "port": 8080, "default_country_code": "27" }, "whatsapp": [ { "id": "personal", "type": "whatsmeow", "phone_number": "+1234567890", "session_path": "./sessions/personal", "show_qr": true }, { "id": "business", "type": "business-api", "phone_number": "+9876543210", "business_api": { "phone_number_id": "123456789012345", "access_token": "EAAxxxxxxxxxxxx", "business_account_id": "987654321098765", "api_version": "v21.0", "verify_token": "my-secure-verify-token" } } ], "hooks": [ { "id": "hook1", "name": "My Webhook", "url": "https://example.com/webhook", "method": "POST", "headers": { "Authorization": "Bearer token" }, "active": true, "description": "Webhook description" } ], "log_level": "info" } ``` ### Configuration Options **Server Configuration:** - `host`: Server hostname (default: "localhost") - `port`: Server port (default: 8080) - `default_country_code`: Default country code for phone number formatting (e.g., "27" for South Africa, "1" for US/Canada) - `username`: Username for HTTP Basic Authentication (optional) - `password`: Password for HTTP Basic Authentication (optional) - `auth_key`: API key for x-api-key header or Authorization Bearer token authentication (optional) **WhatsApp Account Configuration:** - `id`: Unique identifier for this account - `type`: Client type - `"whatsmeow"` for personal or `"business-api"` for Business API (defaults to "whatsmeow") - `phone_number`: Phone number with country code **For whatsmeow (personal) accounts:** - `session_path`: Path to store session data (default: `./sessions/{id}`) - `show_qr`: Display QR code in terminal for pairing (default: false) **For business-api accounts:** - `business_api`: Business API configuration object - `phone_number_id`: WhatsApp Business Phone Number ID from Meta - `access_token`: Access token from Meta Business Manager - `business_account_id`: Business Account ID (optional) - `api_version`: Graph API version (default: "v21.0") - `verify_token`: Token for webhook verification (required for receiving messages) **Hook Configuration:** - `id`: Unique identifier for this hook - `name`: Human-readable name - `url`: Webhook URL to call - `method`: HTTP method (usually "POST") - `headers`: Optional HTTP headers - `active`: Whether this hook is enabled - `description`: Optional description ### Server Authentication The server supports two authentication methods to protect API endpoints: #### 1. HTTP Basic Authentication Set both `username` and `password` in the server configuration: ```json { "server": { "host": "localhost", "port": 8080, "username": "admin", "password": "secure_password" } } ``` Clients must provide credentials in the Authorization header: ```bash curl -u admin:secure_password http://localhost:8080/api/hooks ``` #### 2. API Key Authentication Set `auth_key` in the server configuration: ```json { "server": { "host": "localhost", "port": 8080, "auth_key": "your-secret-api-key" } } ``` Clients can provide the API key using either: - **x-api-key header**: ```bash curl -H "x-api-key: your-secret-api-key" http://localhost:8080/api/hooks ``` - **Authorization Bearer token**: ```bash curl -H "Authorization: Bearer your-secret-api-key" http://localhost:8080/api/hooks ``` #### Authentication Notes - If no authentication is configured (all fields empty), the server operates without authentication - The `/health` endpoint is always accessible without authentication - All `/api/*` endpoints require authentication when enabled - Both authentication methods can be configured simultaneously - the server will accept either valid credentials or a valid API key ## WhatsApp Business API Setup WhatsHooked supports the official WhatsApp Business Cloud API alongside personal WhatsApp accounts. This allows you to use official business phone numbers with enhanced features and reliability. ### Prerequisites 1. **Meta Business Account**: Sign up at [Meta Business Suite](https://business.facebook.com/) 2. **WhatsApp Business App**: Create a WhatsApp Business app in the [Meta for Developers](https://developers.facebook.com/) console 3. **Phone Number**: Register a business phone number with WhatsApp Business API ### Getting Your Credentials 1. Go to [Meta for Developers](https://developers.facebook.com/) and select your app 2. Navigate to **WhatsApp** → **API Setup** 3. Obtain the following: - **Phone Number ID**: Found in the API Setup page - **WhatsApp Business Account ID**: Found in the API Setup page (optional but recommended) - **Access Token**: Generate a permanent token (not the temporary 24-hour token) - **API Version**: Use the current stable version (e.g., `v21.0`) ### Configuring the Account Add a Business API account to your `config.json`: ```json { "whatsapp": [ { "id": "business", "type": "business-api", "phone_number": "+1234567890", "business_api": { "phone_number_id": "123456789012345", "access_token": "EAAxxxxxxxxxxxx_your_permanent_token", "business_account_id": "987654321098765", "api_version": "v21.0", "verify_token": "my-secure-random-token-12345" } } ] } ``` **Important Notes:** - Use a **permanent access token**, not the temporary 24-hour token - The `verify_token` is a random string you create - it will be used to verify Meta's webhook requests - Keep your access token secure and never commit it to version control ### Setting Up Webhooks (Required for Receiving Messages) To receive incoming messages from WhatsApp Business API, you must register your webhook with Meta: 1. **Start the WhatsHooked server** with your Business API configuration 2. **Ensure your server is publicly accessible** (use ngrok for testing): ```bash ngrok http 8080 ``` 3. **In Meta for Developers**, go to **WhatsApp** → **Configuration** 4. **Add Webhook URL**: - **Callback URL**: `https://your-domain.com/webhooks/whatsapp/{accountID}` - Replace `your-domain.com` with your public domain or ngrok URL - Replace `{accountID}` with your account ID from config (e.g., `business`) - Example: `https://abc123.ngrok.io/webhooks/whatsapp/business` - **Verify Token**: Enter the same `verify_token` from your config 5. **Subscribe to Webhook Fields**: - Check **messages** (required for receiving messages) - Check **message_status** (optional, for delivery/read receipts) 6. Click **Verify and Save** ### Testing Your Business API Connection Once configured, start the server and the Business API account will connect automatically: ```bash ./bin/whatshook-server -config config.json ``` Look for logs indicating successful connection: ``` Business API client connected account_id=business phone=+1234567890 ``` Send a test message: ```bash ./bin/whatshook-cli send # Select your business account # Enter recipient phone number # Type your message ``` ### Business API Features **Supported:** - ✅ Send/receive text messages - ✅ Send/receive images with captions - ✅ Send/receive videos with captions - ✅ Send/receive documents with filenames - ✅ Media upload via Meta CDN - ✅ Delivery and read receipts - ✅ Event publishing to webhooks (same format as whatsmeow) **Differences from whatsmeow:** - No QR code pairing (uses access token authentication) - Rate limits apply based on your Meta Business tier - Official support from Meta - Better reliability for business use cases - Costs apply based on conversation pricing ### Running Both Client Types Simultaneously You can run both personal (whatsmeow) and Business API accounts at the same time: ```json { "whatsapp": [ { "id": "personal", "type": "whatsmeow", "phone_number": "+1234567890", "session_path": "./sessions/personal" }, { "id": "business", "type": "business-api", "phone_number": "+9876543210", "business_api": { "phone_number_id": "123456789012345", "access_token": "EAAxxxxxxxxxxxx" } } ] } ``` Both accounts will: - Receive messages independently - Trigger the same webhooks - Publish identical event formats - Support the same API endpoints ## Usage ### Starting the Server ```bash ./bin/whatshook-server -config config.json ``` On first run, you'll need to pair your WhatsApp account. The QR code will be displayed directly in the terminal for easy scanning: ``` ======================================== WhatsApp QR Code for account: account1 Phone: +1234567890 ======================================== Scan this QR code with WhatsApp on your phone: [QR CODE DISPLAYED HERE] ======================================== ``` The QR code is also published as an event (`whatsapp.qr.code`) so you can handle it programmatically if needed. ### Using the CLI The CLI uses Cobra and supports configuration from multiple sources with the following priority: 1. Command-line flags (highest priority) 2. Environment variables 3. Configuration file (lowest priority) #### Configuration Create a CLI configuration file (optional): ```bash cp .whatshooked-cli.example.json .whatshooked-cli.json ``` Or set via environment variable: ```bash export WHATSHOOKED_SERVER_URL=http://localhost:8080 ``` Or use command-line flag: ```bash ./bin/whatshook-cli --server http://localhost:8080 health ``` #### Commands Get help: ```bash ./bin/whatshook-cli --help ./bin/whatshook-cli hooks --help ``` Check server health: ```bash ./bin/whatshook-cli health ``` List all hooks: ```bash ./bin/whatshook-cli hooks list # or just ./bin/whatshook-cli hooks ``` Add a new hook: ```bash ./bin/whatshook-cli hooks add ``` Remove a hook: ```bash ./bin/whatshook-cli hooks remove ``` List WhatsApp accounts: ```bash ./bin/whatshook-cli accounts list # or just ./bin/whatshook-cli accounts ``` Add a WhatsApp account: ```bash ./bin/whatshook-cli accounts add ``` Send a message: ```bash ./bin/whatshook-cli send ``` #### Configuration Priority The CLI loads configuration with the following priority (highest to lowest): 1. **Command-line flags**: `--server http://example.com:8080` 2. **Environment variables**: `WHATSHOOKED_SERVER_URL=http://example.com:8080` 3. **Config file**: `.whatshooked-cli.json` in current directory or `$HOME/.whatshooked/cli.json` 4. **Defaults**: `http://localhost:8080` ## Webhook Integration ### Incoming Message Format When a WhatsApp message is received, all active webhooks receive a POST request with the following JSON payload: ```json { "account_id": "account1", "message_id": "3EB0123456789ABCDEF", "from": "1234567890@s.whatsapp.net", "to": "9876543210@s.whatsapp.net", "text": "Hello, World!", "timestamp": "2025-12-28T10:30:00Z", "is_group": false, "group_name": "", "sender_name": "" } ``` ### Webhook Response Format Webhooks can respond with a JSON payload to send a message back to WhatsApp: ```json { "send_message": true, "to": "0834606792", "text": "This is a response message", "account_id": "account1" } ``` Or using full JID format: ```json { "send_message": true, "to": "27834606792@s.whatsapp.net", "text": "This is a response message", "account_id": "account1" } ``` Fields: - `send_message`: Set to `true` to send a message - `to`: Recipient phone number or JID. Can be: - Plain phone number (e.g., `"0834606792"`) - will be formatted using `default_country_code` - Phone number with country code (e.g., `"27834606792"`) - Full JID format (e.g., `"27834606792@s.whatsapp.net"`) - `text`: Message text to send - `account_id`: (Optional) Which WhatsApp account to use. If not specified, uses the account that received the original message #### Phone Number Formatting The server automatically formats phone numbers to WhatsApp JID format: 1. If the number contains `@`, it's used as-is (already in JID format) 2. Otherwise, formatting rules apply: - Removes all non-digit characters (spaces, dashes, parentheses, etc.) - **If starts with 0**: Assumes no country code and replaces the 0 with the `default_country_code` - **If starts with +**: Assumes it already has a country code - **Otherwise**: Adds country code if configured and not already present - Appends `@s.whatsapp.net` suffix Examples with `default_country_code: "27"`: - `0834606792` → `27834606792@s.whatsapp.net` (replaces leading 0 with 27) - `083-460-6792` → `27834606792@s.whatsapp.net` (removes dashes, replaces 0) - `27834606792` → `27834606792@s.whatsapp.net` (already has country code) - `+27834606792` → `27834606792@s.whatsapp.net` (+ indicates country code present) - `27834606792@s.whatsapp.net` → `27834606792@s.whatsapp.net` (unchanged, already JID) ## API Endpoints The server exposes the following HTTP endpoints: **Public Endpoints:** - `GET /health` - Health check (no authentication required) - `GET/POST /webhooks/whatsapp/{accountID}` - Business API webhook verification and events (no authentication, validated by Meta's verify_token) **Protected Endpoints (require authentication if enabled):** - `GET /api/hooks` - List all hooks - `POST /api/hooks/add` - Add a new hook - `POST /api/hooks/remove` - Remove a hook - `GET /api/accounts` - List all WhatsApp accounts - `POST /api/accounts/add` - Add a new WhatsApp account - `POST /api/send` - Send a message - `POST /api/send/image` - Send an image - `POST /api/send/video` - Send a video - `POST /api/send/document` - Send a document - `GET /api/media/{accountID}/{filename}` - Serve media files ## WhatsApp JID Format WhatsApp uses JID (Jabber ID) format for addressing: - Individual: `1234567890@s.whatsapp.net` - Group: `123456789-1234567890@g.us` The server accepts both full JID format and plain phone numbers. When using plain phone numbers, they are automatically formatted to JID format based on the `default_country_code` configuration. See [Phone Number Formatting](#phone-number-formatting) for details. ## Development ### Project Structure ``` whatshooked/ ├── cmd/ │ ├── server/ # Main server application │ │ ├── main.go │ │ ├── routes.go │ │ ├── routes_*.go # Route handlers │ │ └── routes_businessapi.go # Business API webhooks │ └── cli/ # CLI tool ├── internal/ │ ├── config/ # Configuration management │ ├── events/ # Event bus and event types │ ├── logging/ # Structured logging │ ├── whatsapp/ # WhatsApp client management │ │ ├── interface.go # Client interface │ │ ├── manager.go # Multi-client manager │ │ ├── whatsmeow/ # Personal WhatsApp (QR code) │ │ │ └── client.go │ │ └── businessapi/ # WhatsApp Business API │ │ ├── client.go # API client │ │ ├── types.go # Request/response types │ │ ├── events.go # Webhook processing │ │ └── media.go # Media upload/download │ ├── hooks/ # Webhook management │ └── utils/ # Utility functions (phone formatting, etc.) ├── config.example.json # Example configuration └── go.mod # Go module definition ``` ### Event Types The system publishes the following event types: **WhatsApp Events:** - `whatsapp.connected` - WhatsApp client connected - `whatsapp.disconnected` - WhatsApp client disconnected - `whatsapp.pair.success` - Device pairing successful - `whatsapp.pair.failed` - Device pairing failed - `whatsapp.qr.code` - QR code generated for pairing (includes qr_code data) - `whatsapp.qr.timeout` - QR code expired - `whatsapp.qr.error` - QR code generation error - `whatsapp.pair.event` - Generic pairing event **Message Events:** - `message.received` - New message received from WhatsApp - `message.sent` - Message successfully sent to WhatsApp - `message.failed` - Message send failed **Hook Events:** - `hook.triggered` - Webhook is being called - `hook.success` - Webhook responded successfully - `hook.failed` - Webhook call failed ### Testing ```bash go test ./... ``` ### Building ```bash go build ./... ``` ## Future Phases ### Phase 2 (Planned) - User level hooks and WhatsApp accounts - Web server with frontend UI - Enhanced authentication with user roles and permissions ## License See LICENSE file for details.