Files
whatshooked/README.md
2025-12-29 06:23:16 +02:00

19 KiB

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

TODO LIST - Things I still need to do

Rules when using AI

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

make build

Or manually:

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:

cp config.example.json config.json

Edit the configuration file to add your WhatsApp accounts and webhooks:

{
  "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:

{
  "server": {
    "host": "localhost",
    "port": 8080,
    "username": "admin",
    "password": "secure_password"
  }
}

Clients must provide credentials in the Authorization header:

curl -u admin:secure_password http://localhost:8080/api/hooks

2. API Key Authentication

Set auth_key in the server configuration:

{
  "server": {
    "host": "localhost",
    "port": 8080,
    "auth_key": "your-secret-api-key"
  }
}

Clients can provide the API key using either:

  • x-api-key header:
    curl -H "x-api-key: your-secret-api-key" http://localhost:8080/api/hooks
    
  • Authorization Bearer token:
    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
  2. WhatsApp Business App: Create a WhatsApp Business app in the Meta for Developers console
  3. Phone Number: Register a business phone number with WhatsApp Business API

Getting Your Credentials

  1. Go to Meta for Developers and select your app
  2. Navigate to WhatsAppAPI 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:

{
  "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):
    ngrok http 8080
    
  3. In Meta for Developers, go to WhatsAppConfiguration
  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:

./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:

./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:

{
  "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

./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):

cp .whatshooked-cli.example.json .whatshooked-cli.json

Or set via environment variable:

export WHATSHOOKED_SERVER_URL=http://localhost:8080

Or use command-line flag:

./bin/whatshook-cli --server http://localhost:8080 health

Commands

Get help:

./bin/whatshook-cli --help
./bin/whatshook-cli hooks --help

Check server health:

./bin/whatshook-cli health

List all hooks:

./bin/whatshook-cli hooks list
# or just
./bin/whatshook-cli hooks

Add a new hook:

./bin/whatshook-cli hooks add

Remove a hook:

./bin/whatshook-cli hooks remove <hook_id>

List WhatsApp accounts:

./bin/whatshook-cli accounts list
# or just
./bin/whatshook-cli accounts

Add a WhatsApp account:

./bin/whatshook-cli accounts add

Send a message:

./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:

{
  "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:

{
  "send_message": true,
  "to": "0834606792",
  "text": "This is a response message",
  "account_id": "account1"
}

Or using full JID format:

{
  "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":

  • 083460679227834606792@s.whatsapp.net (replaces leading 0 with 27)
  • 083-460-679227834606792@s.whatsapp.net (removes dashes, replaces 0)
  • 2783460679227834606792@s.whatsapp.net (already has country code)
  • +2783460679227834606792@s.whatsapp.net (+ indicates country code present)
  • 27834606792@s.whatsapp.net27834606792@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 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

go test ./...

Building

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.