feat(docker): 🚀 Update server port to 8025
Some checks failed
CI / Test (1.22) (push) Failing after -24m19s
CI / Test (1.23) (push) Failing after -24m15s
CI / Lint (push) Successful in -26m35s
CI / Build (push) Successful in -26m34s

- Change default server port from 8080 to 8025 across all configurations.
- Update Dockerfile, docker-compose.yml, and related documentation.
- Ensure all CLI commands and API endpoints reflect the new port.
- Adjust example configurations and health check URLs accordingly.
This commit is contained in:
Hein
2026-02-04 13:37:38 +02:00
parent 947761313b
commit c1dbff318d
16 changed files with 270 additions and 125 deletions

View File

@@ -18,6 +18,7 @@ Get a list of all configured WhatsApp accounts.
**Endpoint:** `GET /api/accounts` **Endpoint:** `GET /api/accounts`
**Response:** **Response:**
```json ```json
[ [
{ {
@@ -45,6 +46,7 @@ Add a new WhatsApp account to the system.
**Endpoint:** `POST /api/accounts/add` **Endpoint:** `POST /api/accounts/add`
**Request Body (WhatsApp Web/WhatsMe ow):** **Request Body (WhatsApp Web/WhatsMe ow):**
```json ```json
{ {
"id": "my-account", "id": "my-account",
@@ -57,6 +59,7 @@ Add a new WhatsApp account to the system.
``` ```
**Request Body (Business API):** **Request Body (Business API):**
```json ```json
{ {
"id": "business-account", "id": "business-account",
@@ -74,6 +77,7 @@ Add a new WhatsApp account to the system.
``` ```
**Response:** **Response:**
```json ```json
{ {
"status": "ok", "status": "ok",
@@ -82,6 +86,7 @@ Add a new WhatsApp account to the system.
``` ```
**Status Codes:** **Status Codes:**
- `201 Created` - Account added successfully - `201 Created` - Account added successfully
- `400 Bad Request` - Invalid request body - `400 Bad Request` - Invalid request body
- `500 Internal Server Error` - Failed to connect or save config - `500 Internal Server Error` - Failed to connect or save config
@@ -95,6 +100,7 @@ Update an existing WhatsApp account configuration.
**Endpoint:** `POST /api/accounts/update` or `PUT /api/accounts/update` **Endpoint:** `POST /api/accounts/update` or `PUT /api/accounts/update`
**Request Body:** **Request Body:**
```json ```json
{ {
"id": "business-account", "id": "business-account",
@@ -112,6 +118,7 @@ Update an existing WhatsApp account configuration.
``` ```
**Response:** **Response:**
```json ```json
{ {
"status": "ok", "status": "ok",
@@ -120,12 +127,14 @@ Update an existing WhatsApp account configuration.
``` ```
**Notes:** **Notes:**
- The `id` field is required to identify which account to update - The `id` field is required to identify which account to update
- The `type` field cannot be changed (preserved from original) - The `type` field cannot be changed (preserved from original)
- If the account is enabled, it will be disconnected and reconnected with new settings - If the account is enabled, it will be disconnected and reconnected with new settings
- Configuration is saved to disk after successful update - Configuration is saved to disk after successful update
**Status Codes:** **Status Codes:**
- `200 OK` - Account updated successfully - `200 OK` - Account updated successfully
- `400 Bad Request` - Invalid request or missing ID - `400 Bad Request` - Invalid request or missing ID
- `404 Not Found` - Account not found - `404 Not Found` - Account not found
@@ -140,6 +149,7 @@ Disable a WhatsApp account (disconnect and prevent auto-connect on restart).
**Endpoint:** `POST /api/accounts/disable` **Endpoint:** `POST /api/accounts/disable`
**Request Body:** **Request Body:**
```json ```json
{ {
"id": "my-account" "id": "my-account"
@@ -147,6 +157,7 @@ Disable a WhatsApp account (disconnect and prevent auto-connect on restart).
``` ```
**Response:** **Response:**
```json ```json
{ {
"status": "ok", "status": "ok",
@@ -155,12 +166,14 @@ Disable a WhatsApp account (disconnect and prevent auto-connect on restart).
``` ```
**Behavior:** **Behavior:**
- Disconnects the account immediately - Disconnects the account immediately
- Sets `disabled: true` in config - Sets `disabled: true` in config
- Account will not auto-connect on server restart - Account will not auto-connect on server restart
- Account remains in config (can be re-enabled) - Account remains in config (can be re-enabled)
**Status Codes:** **Status Codes:**
- `200 OK` - Account disabled successfully - `200 OK` - Account disabled successfully
- `400 Bad Request` - Invalid request body - `400 Bad Request` - Invalid request body
- `404 Not Found` - Account not found - `404 Not Found` - Account not found
@@ -175,6 +188,7 @@ Enable a previously disabled WhatsApp account.
**Endpoint:** `POST /api/accounts/enable` **Endpoint:** `POST /api/accounts/enable`
**Request Body:** **Request Body:**
```json ```json
{ {
"id": "my-account" "id": "my-account"
@@ -182,6 +196,7 @@ Enable a previously disabled WhatsApp account.
``` ```
**Response:** **Response:**
```json ```json
{ {
"status": "ok", "status": "ok",
@@ -190,12 +205,14 @@ Enable a previously disabled WhatsApp account.
``` ```
**Behavior:** **Behavior:**
- Sets `disabled: false` in config - Sets `disabled: false` in config
- Connects the account immediately - Connects the account immediately
- Account will auto-connect on server restart - Account will auto-connect on server restart
- If connection fails, account remains disabled - If connection fails, account remains disabled
**Status Codes:** **Status Codes:**
- `200 OK` - Account enabled and connected successfully - `200 OK` - Account enabled and connected successfully
- `400 Bad Request` - Invalid request body - `400 Bad Request` - Invalid request body
- `404 Not Found` - Account not found - `404 Not Found` - Account not found
@@ -210,6 +227,7 @@ Permanently remove a WhatsApp account from the system.
**Endpoint:** `POST /api/accounts/remove` or `DELETE /api/accounts/remove` **Endpoint:** `POST /api/accounts/remove` or `DELETE /api/accounts/remove`
**Request Body:** **Request Body:**
```json ```json
{ {
"id": "my-account" "id": "my-account"
@@ -217,6 +235,7 @@ Permanently remove a WhatsApp account from the system.
``` ```
**Response:** **Response:**
```json ```json
{ {
"status": "ok" "status": "ok"
@@ -224,11 +243,13 @@ Permanently remove a WhatsApp account from the system.
``` ```
**Behavior:** **Behavior:**
- Disconnects the account - Disconnects the account
- Removes from config permanently - Removes from config permanently
- Session data is NOT deleted (manual cleanup required) - Session data is NOT deleted (manual cleanup required)
**Status Codes:** **Status Codes:**
- `200 OK` - Account removed successfully - `200 OK` - Account removed successfully
- `400 Bad Request` - Invalid request body - `400 Bad Request` - Invalid request body
- `404 Not Found` - Account not found - `404 Not Found` - Account not found
@@ -271,7 +292,7 @@ Account settings are stored in `config.json`:
### Configuration Fields ### Configuration Fields
| Field | Type | Required | Description | | Field | Type | Required | Description |
|-------|------|----------|-------------| | -------------- | ------- | ----------- | --------------------------------------------------- |
| `id` | string | Yes | Unique identifier for the account | | `id` | string | Yes | Unique identifier for the account |
| `type` | string | Yes | Account type: `whatsmeow` or `business-api` | | `type` | string | Yes | Account type: `whatsmeow` or `business-api` |
| `phone_number` | string | Yes | Phone number with country code | | `phone_number` | string | Yes | Phone number with country code |
@@ -283,7 +304,7 @@ Account settings are stored in `config.json`:
### Business API Configuration ### Business API Configuration
| Field | Type | Required | Description | | Field | Type | Required | Description |
|-------|------|----------|-------------| | --------------------- | ------ | -------- | --------------------------------- |
| `phone_number_id` | string | Yes | WhatsApp Business phone number ID | | `phone_number_id` | string | Yes | WhatsApp Business phone number ID |
| `access_token` | string | Yes | Meta Graph API access token | | `access_token` | string | Yes | Meta Graph API access token |
| `business_account_id` | string | No | Business account ID | | `business_account_id` | string | No | Business account ID |
@@ -297,11 +318,13 @@ Account settings are stored in `config.json`:
### cURL Examples ### cURL Examples
**List accounts:** **List accounts:**
```bash ```bash
curl -u username:password http://localhost:8080/api/accounts curl -u username:password http://localhost:8025/api/accounts
``` ```
**Add account:** **Add account:**
```bash ```bash
curl -u username:password \ curl -u username:password \
-X POST \ -X POST \
@@ -313,10 +336,11 @@ curl -u username:password \
"session_path": "./sessions/new-account", "session_path": "./sessions/new-account",
"show_qr": true "show_qr": true
}' \ }' \
http://localhost:8080/api/accounts/add http://localhost:8025/api/accounts/add
``` ```
**Update account:** **Update account:**
```bash ```bash
curl -u username:password \ curl -u username:password \
-X POST \ -X POST \
@@ -331,34 +355,37 @@ curl -u username:password \
"api_version": "v21.0" "api_version": "v21.0"
} }
}' \ }' \
http://localhost:8080/api/accounts/update http://localhost:8025/api/accounts/update
``` ```
**Disable account:** **Disable account:**
```bash ```bash
curl -u username:password \ curl -u username:password \
-X POST \ -X POST \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"id": "my-account"}' \ -d '{"id": "my-account"}' \
http://localhost:8080/api/accounts/disable http://localhost:8025/api/accounts/disable
``` ```
**Enable account:** **Enable account:**
```bash ```bash
curl -u username:password \ curl -u username:password \
-X POST \ -X POST \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"id": "my-account"}' \ -d '{"id": "my-account"}' \
http://localhost:8080/api/accounts/enable http://localhost:8025/api/accounts/enable
``` ```
**Remove account:** **Remove account:**
```bash ```bash
curl -u username:password \ curl -u username:password \
-X POST \ -X POST \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"id": "my-account"}' \ -d '{"id": "my-account"}' \
http://localhost:8080/api/accounts/remove http://localhost:8025/api/accounts/remove
``` ```
--- ---
@@ -419,11 +446,13 @@ All endpoints return proper HTTP status codes and JSON error messages:
``` ```
Or plain text for simple errors: Or plain text for simple errors:
``` ```
Account ID required in path Account ID required in path
``` ```
Common error scenarios: Common error scenarios:
- Account already exists (when adding) - Account already exists (when adding)
- Account not found (when updating/removing) - Account not found (when updating/removing)
- Connection failed (when enabling) - Connection failed (when enabling)

32
CLI.md
View File

@@ -52,7 +52,7 @@ Create a configuration file at `~/.whatshooked/cli.json`:
```json ```json
{ {
"server_url": "http://localhost:8080", "server_url": "http://localhost:8025",
"auth_key": "your-api-key-here", "auth_key": "your-api-key-here",
"username": "", "username": "",
"password": "" "password": ""
@@ -63,7 +63,7 @@ Or use API key authentication:
```json ```json
{ {
"server_url": "http://localhost:8080", "server_url": "http://localhost:8025",
"auth_key": "your-secure-api-key" "auth_key": "your-secure-api-key"
} }
``` ```
@@ -72,7 +72,7 @@ Or use username/password authentication:
```json ```json
{ {
"server_url": "http://localhost:8080", "server_url": "http://localhost:8025",
"username": "admin", "username": "admin",
"password": "your-secure-password" "password": "your-secure-password"
} }
@@ -90,14 +90,14 @@ cp .whatshooked-cli.example.json .whatshooked-cli.json
Set environment variables (useful for CI/CD): Set environment variables (useful for CI/CD):
```bash ```bash
export WHATSHOOKED_SERVER_URL="http://localhost:8080" export WHATSHOOKED_SERVER_URL="http://localhost:8025"
export WHATSHOOKED_AUTH_KEY="your-api-key-here" export WHATSHOOKED_AUTH_KEY="your-api-key-here"
``` ```
Or with username/password: Or with username/password:
```bash ```bash
export WHATSHOOKED_SERVER_URL="http://localhost:8080" export WHATSHOOKED_SERVER_URL="http://localhost:8025"
export WHATSHOOKED_USERNAME="admin" export WHATSHOOKED_USERNAME="admin"
export WHATSHOOKED_PASSWORD="your-password" export WHATSHOOKED_PASSWORD="your-password"
``` ```
@@ -107,7 +107,7 @@ export WHATSHOOKED_PASSWORD="your-password"
Pass credentials via command-line flags: Pass credentials via command-line flags:
```bash ```bash
./bin/whatshook-cli --server http://localhost:8080 health ./bin/whatshook-cli --server http://localhost:8025 health
``` ```
Note: Currently, authentication credentials can only be set via config file or environment variables. Command-line flags for auth credentials may be added in future versions. Note: Currently, authentication credentials can only be set via config file or environment variables. Command-line flags for auth credentials may be added in future versions.
@@ -118,7 +118,7 @@ If your server doesn't require authentication, simply omit the authentication fi
```json ```json
{ {
"server_url": "http://localhost:8080" "server_url": "http://localhost:8025"
} }
``` ```
@@ -135,8 +135,8 @@ The CLI looks for configuration files in the following locations (in order):
### Configuration Options ### Configuration Options
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| | ------------ | ------ | ----------------------- | -------------------------- |
| `server_url` | string | `http://localhost:8080` | WhatsHooked server URL | | `server_url` | string | `http://localhost:8025` | WhatsHooked server URL |
| `auth_key` | string | `""` | API key for authentication | | `auth_key` | string | `""` | API key for authentication |
| `username` | string | `""` | Username for Basic Auth | | `username` | string | `""` | Username for Basic Auth |
| `password` | string | `""` | Password for Basic Auth | | `password` | string | `""` | Password for Basic Auth |
@@ -178,6 +178,7 @@ Add a new webhook interactively:
``` ```
You'll be prompted for: You'll be prompted for:
- Hook ID - Hook ID
- Hook Name - Hook Name
- Webhook URL - Webhook URL
@@ -188,6 +189,7 @@ You'll be prompted for:
**Available Event Types:** **Available Event Types:**
WhatsApp Connection Events: WhatsApp Connection Events:
- `whatsapp.connected` - WhatsApp client connected - `whatsapp.connected` - WhatsApp client connected
- `whatsapp.disconnected` - WhatsApp client disconnected - `whatsapp.disconnected` - WhatsApp client disconnected
- `whatsapp.qr.code` - QR code generated for pairing - `whatsapp.qr.code` - QR code generated for pairing
@@ -198,6 +200,7 @@ WhatsApp Connection Events:
- `whatsapp.pair.event` - Generic pairing event - `whatsapp.pair.event` - Generic pairing event
Message Events: Message Events:
- `message.received` - Message received from WhatsApp - `message.received` - Message received from WhatsApp
- `message.sent` - Message sent successfully - `message.sent` - Message sent successfully
- `message.failed` - Message sending failed - `message.failed` - Message sending failed
@@ -205,6 +208,7 @@ Message Events:
- `message.read` - Message read by recipient - `message.read` - Message read by recipient
Hook Events: Hook Events:
- `hook.triggered` - Hook was triggered - `hook.triggered` - Hook was triggered
- `hook.success` - Hook executed successfully - `hook.success` - Hook executed successfully
- `hook.failed` - Hook execution failed - `hook.failed` - Hook execution failed
@@ -239,6 +243,7 @@ Add a new WhatsApp account interactively:
``` ```
You'll be prompted for: You'll be prompted for:
- Account ID - Account ID
- Phone Number (with country code, e.g., +1234567890) - Phone Number (with country code, e.g., +1234567890)
- Session Path (where to store session data) - Session Path (where to store session data)
@@ -256,6 +261,7 @@ Send a text message interactively:
``` ```
You'll be prompted for: You'll be prompted for:
- Account ID - Account ID
- Recipient (phone number or JID) - Recipient (phone number or JID)
- Message text - Message text
@@ -299,7 +305,7 @@ Supported formats: PDF, DOC, DOCX, XLS, XLSX, TXT, ZIP, and more
mkdir -p ~/.whatshooked mkdir -p ~/.whatshooked
cat > ~/.whatshooked/cli.json <<EOF cat > ~/.whatshooked/cli.json <<EOF
{ {
"server_url": "http://localhost:8080", "server_url": "http://localhost:8025",
"auth_key": "my-secure-api-key" "auth_key": "my-secure-api-key"
} }
EOF EOF
@@ -315,7 +321,7 @@ EOF
```bash ```bash
# Set environment variables # Set environment variables
export WHATSHOOKED_SERVER_URL="https://my-server.com:8080" export WHATSHOOKED_SERVER_URL="https://my-server.com:8025"
export WHATSHOOKED_AUTH_KEY="production-api-key" export WHATSHOOKED_AUTH_KEY="production-api-key"
# Use CLI without config file # Use CLI without config file
@@ -375,7 +381,7 @@ export WHATSHOOKED_AUTH_KEY="production-api-key"
{ {
"server": { "server": {
"host": "0.0.0.0", "host": "0.0.0.0",
"port": 8080, "port": 8025,
"auth_key": "super-secret-production-key" "auth_key": "super-secret-production-key"
} }
} }
@@ -452,7 +458,7 @@ cp .whatshooked-cli.example.json ~/.whatshooked/cli.json
Verify the server is running: Verify the server is running:
```bash ```bash
curl http://localhost:8080/health curl http://localhost:8025/health
``` ```
### Authentication Required ### Authentication Required

View File

@@ -10,6 +10,7 @@ This guide explains how to run WhatsHooked using Docker and Docker Compose.
## Quick Start ## Quick Start
1. **Copy the example configuration file:** 1. **Copy the example configuration file:**
```bash ```bash
cp config.example.json config.json cp config.example.json config.json
``` ```
@@ -21,54 +22,64 @@ This guide explains how to run WhatsHooked using Docker and Docker Compose.
- Server settings (port, authentication) - Server settings (port, authentication)
3. **Create required directories:** 3. **Create required directories:**
```bash ```bash
mkdir -p sessions data/media mkdir -p sessions data/media
``` ```
4. **Build and start the server:** 4. **Build and start the server:**
```bash ```bash
docker-compose up -d docker-compose up -d
``` ```
5. **View logs to scan QR code (first run):** 5. **View logs to scan QR code (first run):**
```bash ```bash
docker-compose logs -f whatshooked docker-compose logs -f whatshooked
``` ```
Scan the QR code with WhatsApp on your phone to authenticate. Scan the QR code with WhatsApp on your phone to authenticate.
6. **Check server health:** 6. **Check server health:**
```bash ```bash
curl http://localhost:8080/health curl http://localhost:8025/health
``` ```
## Docker Commands ## Docker Commands
### Build the image ### Build the image
```bash ```bash
docker-compose build docker-compose build
``` ```
### Start the service ### Start the service
```bash ```bash
docker-compose up -d docker-compose up -d
``` ```
### Stop the service ### Stop the service
```bash ```bash
docker-compose down docker-compose down
``` ```
### View logs ### View logs
```bash ```bash
docker-compose logs -f docker-compose logs -f
``` ```
### Restart the service ### Restart the service
```bash ```bash
docker-compose restart docker-compose restart
``` ```
### Access the container shell ### Access the container shell
```bash ```bash
docker-compose exec whatshooked sh docker-compose exec whatshooked sh
``` ```
@@ -87,9 +98,10 @@ These volumes ensure your data persists across container restarts.
### Port Mapping ### Port Mapping
By default, the server runs on port 8080. To change the port: By default, the server runs on port 8025. To change the port:
**Option 1: Update config.json** **Option 1: Update config.json**
```json ```json
{ {
"server": { "server": {
@@ -97,16 +109,19 @@ By default, the server runs on port 8080. To change the port:
} }
} }
``` ```
Then update docker-compose.yml: Then update docker-compose.yml:
```yaml ```yaml
ports: ports:
- "9090:9090" - "9090:9090"
``` ```
**Option 2: Map to different host port** **Option 2: Map to different host port**
```yaml ```yaml
ports: ports:
- "3000:8080" # Access via localhost:3000, server still runs on 8080 internally - "3000:8025" # Access via localhost:3000, server still runs on 8025 internally
``` ```
### Authentication ### Authentication
@@ -114,6 +129,7 @@ ports:
Set authentication in config.json: Set authentication in config.json:
**Option 1: API Key** **Option 1: API Key**
```json ```json
{ {
"server": { "server": {
@@ -123,6 +139,7 @@ Set authentication in config.json:
``` ```
**Option 2: Username/Password** **Option 2: Username/Password**
```json ```json
{ {
"server": { "server": {
@@ -140,10 +157,10 @@ Uncomment the deploy section in docker-compose.yml to set resource limits:
deploy: deploy:
resources: resources:
limits: limits:
cpus: '1.0' cpus: "1.0"
memory: 512M memory: 512M
reservations: reservations:
cpus: '0.25' cpus: "0.25"
memory: 128M memory: 128M
``` ```
@@ -152,6 +169,7 @@ deploy:
When you first start the server, you'll need to scan a QR code to authenticate with WhatsApp. When you first start the server, you'll need to scan a QR code to authenticate with WhatsApp.
### View QR Code in Logs ### View QR Code in Logs
```bash ```bash
docker-compose logs -f whatshooked docker-compose logs -f whatshooked
``` ```
@@ -159,19 +177,22 @@ docker-compose logs -f whatshooked
The QR code will be displayed in ASCII art in the terminal along with a browser link. You have two options: The QR code will be displayed in ASCII art in the terminal along with a browser link. You have two options:
**Option 1: Scan from Terminal** **Option 1: Scan from Terminal**
1. Open WhatsApp 1. Open WhatsApp
2. Go to Settings > Linked Devices 2. Go to Settings > Linked Devices
3. Tap "Link a Device" 3. Tap "Link a Device"
4. Scan the QR code from the terminal 4. Scan the QR code from the terminal
**Option 2: View in Browser** **Option 2: View in Browser**
1. Look for the line: `Or open in browser: http://localhost:8080/api/qr/{account_id}`
1. Look for the line: `Or open in browser: http://localhost:8025/api/qr/{account_id}`
2. Open that URL in your web browser to see a larger PNG image 2. Open that URL in your web browser to see a larger PNG image
3. Scan the QR code from your browser 3. Scan the QR code from your browser
### Alternative: Use CLI Tool ### Alternative: Use CLI Tool
You can also use the CLI tool outside Docker to link accounts, then mount the session: You can also use the CLI tool outside Docker to link accounts, then mount the session:
```bash ```bash
./bin/whatshook-cli accounts add ./bin/whatshook-cli accounts add
``` ```
@@ -183,33 +204,39 @@ The Docker image includes both the server and CLI binaries in the `/app/bin` dir
### Available CLI Commands ### Available CLI Commands
List all hooks: List all hooks:
```bash ```bash
docker exec whatshooked-server /app/bin/whatshook-cli --server http://localhost:8080 hooks list docker exec whatshooked-server /app/bin/whatshook-cli --server http://localhost:8025 hooks list
``` ```
Add a new hook: Add a new hook:
```bash ```bash
docker exec -it whatshooked-server /app/bin/whatshook-cli --server http://localhost:8080 hooks add docker exec -it whatshooked-server /app/bin/whatshook-cli --server http://localhost:8025 hooks add
``` ```
Remove a hook: Remove a hook:
```bash ```bash
docker exec whatshooked-server /app/bin/whatshook-cli --server http://localhost:8080 hooks remove <hook_id> docker exec whatshooked-server /app/bin/whatshook-cli --server http://localhost:8025 hooks remove <hook_id>
``` ```
List WhatsApp accounts: List WhatsApp accounts:
```bash ```bash
docker exec whatshooked-server /app/bin/whatshook-cli --server http://localhost:8080 accounts list docker exec whatshooked-server /app/bin/whatshook-cli --server http://localhost:8025 accounts list
``` ```
Send a message: Send a message:
```bash ```bash
docker exec -it whatshooked-server /app/bin/whatshook-cli --server http://localhost:8080 send docker exec -it whatshooked-server /app/bin/whatshook-cli --server http://localhost:8025 send
``` ```
Check server health: Check server health:
```bash ```bash
docker exec whatshooked-server /app/bin/whatshook-cli --server http://localhost:8080 health docker exec whatshooked-server /app/bin/whatshook-cli --server http://localhost:8025 health
``` ```
### Authentication with CLI ### Authentication with CLI
@@ -217,9 +244,10 @@ docker exec whatshooked-server /app/bin/whatshook-cli --server http://localhost:
If your server has authentication enabled, you need to configure it in the CLI: If your server has authentication enabled, you need to configure it in the CLI:
**Option 1: Using command-line flags** **Option 1: Using command-line flags**
```bash ```bash
docker exec whatshooked-server /app/bin/whatshook-cli \ docker exec whatshooked-server /app/bin/whatshook-cli \
--server http://localhost:8080 \ --server http://localhost:8025 \
--api-key your-api-key \ --api-key your-api-key \
hooks list hooks list
``` ```
@@ -227,15 +255,17 @@ docker exec whatshooked-server /app/bin/whatshook-cli \
**Option 2: Create a CLI config file** **Option 2: Create a CLI config file**
1. Access the container: 1. Access the container:
```bash ```bash
docker exec -it whatshooked-server sh docker exec -it whatshooked-server sh
``` ```
2. Create the CLI config: 2. Create the CLI config:
```bash ```bash
cat > /app/.whatshooked-cli.json <<EOF cat > /app/.whatshooked-cli.json <<EOF
{ {
"server_url": "http://localhost:8080", "server_url": "http://localhost:8025",
"api_key": "your-api-key" "api_key": "your-api-key"
} }
EOF EOF
@@ -251,10 +281,11 @@ docker exec whatshooked-server /app/bin/whatshook-cli \
Create an alias on your host machine for easier CLI access: Create an alias on your host machine for easier CLI access:
```bash ```bash
alias whatshook-cli='docker exec -it whatshooked-server /app/bin/whatshook-cli --server http://localhost:8080' alias whatshook-cli='docker exec -it whatshooked-server /app/bin/whatshook-cli --server http://localhost:8025'
``` ```
Then use it like: Then use it like:
```bash ```bash
whatshook-cli hooks list whatshook-cli hooks list
whatshook-cli send whatshook-cli send
@@ -265,25 +296,33 @@ Add this to your `~/.bashrc` or `~/.zshrc` to make it permanent.
## Troubleshooting ## Troubleshooting
### Container won't start ### Container won't start
Check logs for errors: Check logs for errors:
```bash ```bash
docker-compose logs docker-compose logs
``` ```
### Config file not found ### Config file not found
Ensure config.json exists in the project root: Ensure config.json exists in the project root:
```bash ```bash
ls -la config.json ls -la config.json
``` ```
### Permission issues with volumes ### Permission issues with volumes
Fix ownership of mounted directories: Fix ownership of mounted directories:
```bash ```bash
sudo chown -R $(id -u):$(id -g) sessions data sudo chown -R $(id -u):$(id -g) sessions data
``` ```
### QR code not displaying ### QR code not displaying
Ensure `show_qr: true` is set in config.json: Ensure `show_qr: true` is set in config.json:
```json ```json
{ {
"whatsapp": [ "whatsapp": [
@@ -295,12 +334,15 @@ Ensure `show_qr: true` is set in config.json:
``` ```
### Cannot connect to server ### Cannot connect to server
Check if the container is running: Check if the container is running:
```bash ```bash
docker-compose ps docker-compose ps
``` ```
Check health status: Check health status:
```bash ```bash
docker inspect whatshooked-server | grep -A 10 Health docker inspect whatshooked-server | grep -A 10 Health
``` ```
@@ -332,11 +374,13 @@ docker inspect whatshooked-server | grep -A 10 Health
### Example with Reverse Proxy (nginx) ### Example with Reverse Proxy (nginx)
Create a network: Create a network:
```bash ```bash
docker network create whatshooked-net docker network create whatshooked-net
``` ```
Update docker-compose.yml: Update docker-compose.yml:
```yaml ```yaml
services: services:
whatshooked: whatshooked:
@@ -344,7 +388,7 @@ services:
- whatshooked-net - whatshooked-net
# Don't expose ports to host, only to network # Don't expose ports to host, only to network
# ports: # ports:
# - "8080:8080" # - "8025:8025"
networks: networks:
whatshooked-net: whatshooked-net:
@@ -352,6 +396,7 @@ networks:
``` ```
Configure nginx to proxy to the container: Configure nginx to proxy to the container:
```nginx ```nginx
server { server {
listen 443 ssl; listen 443 ssl;
@@ -361,7 +406,7 @@ server {
ssl_certificate_key /path/to/key.pem; ssl_certificate_key /path/to/key.pem;
location / { location / {
proxy_pass http://whatshooked:8080; proxy_pass http://whatshooked:8025;
proxy_set_header Host $host; proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
} }
@@ -373,6 +418,7 @@ server {
### Health Checks ### Health Checks
The compose file includes a health check that runs every 30 seconds: The compose file includes a health check that runs every 30 seconds:
```bash ```bash
docker inspect --format='{{.State.Health.Status}}' whatshooked-server docker inspect --format='{{.State.Health.Status}}' whatshooked-server
``` ```
@@ -380,6 +426,7 @@ docker inspect --format='{{.State.Health.Status}}' whatshooked-server
### Log Management ### Log Management
Limit log size to prevent disk space issues: Limit log size to prevent disk space issues:
```yaml ```yaml
services: services:
whatshooked: whatshooked:
@@ -395,11 +442,13 @@ services:
To update to the latest version: To update to the latest version:
1. Pull latest code: 1. Pull latest code:
```bash ```bash
git pull git pull
``` ```
2. Rebuild the image: 2. Rebuild the image:
```bash ```bash
docker-compose build --no-cache docker-compose build --no-cache
``` ```

View File

@@ -34,7 +34,7 @@ COPY --from=builder /build/bin ./bin
RUN mkdir -p /app/sessions /app/data/media /app/data/certs RUN mkdir -p /app/sessions /app/data/media /app/data/certs
# Expose the default server port # Expose the default server port
EXPOSE 8080 EXPOSE 8025
# Run the server # Run the server
ENTRYPOINT ["/app/bin/whatshook-server"] ENTRYPOINT ["/app/bin/whatshook-server"]

View File

@@ -56,11 +56,13 @@ Add the following to your `config.json`:
### Published Events ### Published Events
Events are published to topics in the format: Events are published to topics in the format:
``` ```
{topic_prefix}/{account_id}/{event_type} {topic_prefix}/{account_id}/{event_type}
``` ```
Examples: Examples:
- `whatshooked/my-account/message.received` - `whatshooked/my-account/message.received`
- `whatshooked/my-account/whatsapp.connected` - `whatshooked/my-account/whatsapp.connected`
- `whatshooked/business-account/message.sent` - `whatshooked/business-account/message.sent`
@@ -68,6 +70,7 @@ Examples:
### Sending Messages (Subscribe Mode) ### Sending Messages (Subscribe Mode)
When `subscribe: true` is enabled, you can send WhatsApp messages by publishing to: When `subscribe: true` is enabled, you can send WhatsApp messages by publishing to:
``` ```
{topic_prefix}/{account_id}/send {topic_prefix}/{account_id}/send
``` ```
@@ -145,6 +148,7 @@ When `subscribe: true` is enabled, you can send WhatsApp messages by publishing
``` ```
**Payload Fields:** **Payload Fields:**
- `type`: Message type - "text", "image", "video", or "document" (default: "text") - `type`: Message type - "text", "image", "video", or "document" (default: "text")
- `to`: Phone number in JID format (required) - `to`: Phone number in JID format (required)
- `text`: Message text (required for text messages) - `text`: Message text (required for text messages)
@@ -161,6 +165,7 @@ When `subscribe: true` is enabled, you can send WhatsApp messages by publishing
Available event types for filtering: Available event types for filtering:
### WhatsApp Connection Events ### WhatsApp Connection Events
- `whatsapp.connected` - `whatsapp.connected`
- `whatsapp.disconnected` - `whatsapp.disconnected`
- `whatsapp.pair.success` - `whatsapp.pair.success`
@@ -171,6 +176,7 @@ Available event types for filtering:
- `whatsapp.pair.event` - `whatsapp.pair.event`
### Message Events ### Message Events
- `message.received` - `message.received`
- `message.sent` - `message.sent`
- `message.failed` - `message.failed`
@@ -178,6 +184,7 @@ Available event types for filtering:
- `message.read` - `message.read`
### Hook Events ### Hook Events
- `hook.triggered` - `hook.triggered`
- `hook.success` - `hook.success`
- `hook.failed` - `hook.failed`
@@ -263,7 +270,7 @@ script:
{ {
"server": { "server": {
"host": "0.0.0.0", "host": "0.0.0.0",
"port": 8080 "port": 8025
}, },
"whatsapp": [ "whatsapp": [
{ {

118
README.md
View File

@@ -3,6 +3,7 @@
A Go library and 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. A Go library and 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.
**Use WhatsHooked as:** **Use WhatsHooked as:**
- 📦 **Go Library** - Import into your own applications for programmatic WhatsApp integration - 📦 **Go Library** - Import into your own applications for programmatic WhatsApp integration
- 🚀 **Standalone Server** - Run as a service with HTTP API and CLI management - 🚀 **Standalone Server** - Run as a service with HTTP API and CLI management
- 🔧 **Custom Integration** - Mount individual handlers in your existing HTTP servers - 🔧 **Custom Integration** - Mount individual handlers in your existing HTTP servers
@@ -59,7 +60,7 @@ Or with programmatic configuration:
```go ```go
wh, err := whatshooked.New( wh, err := whatshooked.New(
whatshooked.WithServer("0.0.0.0", 8080), whatshooked.WithServer("0.0.0.0", 8025),
whatshooked.WithAuth("my-api-key", "", ""), whatshooked.WithAuth("my-api-key", "", ""),
whatshooked.WithWhatsmeowAccount("personal", "+1234567890", "./session", true), whatshooked.WithWhatsmeowAccount("personal", "+1234567890", "./session", true),
) )
@@ -79,7 +80,9 @@ make build
When using personal WhatsApp accounts (whatsmeow), you'll need to pair the device on first launch. The QR code will be displayed in two ways: When using personal WhatsApp accounts (whatsmeow), you'll need to pair the device on first launch. The QR code will be displayed in two ways:
### Terminal Display ### Terminal Display
The QR code is shown as ASCII art directly in the terminal: The QR code is shown as ASCII art directly in the terminal:
``` ```
======================================== ========================================
WhatsApp QR Code for account: personal WhatsApp QR Code for account: personal
@@ -89,25 +92,29 @@ Scan this QR code with WhatsApp on your phone:
[ASCII QR Code displayed here] [ASCII QR Code displayed here]
Or open in browser: http://localhost:8080/api/qr/personal Or open in browser: http://localhost:8025/api/qr/personal
======================================== ========================================
``` ```
### Browser Display ### Browser Display
For easier scanning, open the provided URL in your browser to view a larger PNG image: For easier scanning, open the provided URL in your browser to view a larger PNG image:
- URL format: `http://localhost:8080/api/qr/{account_id}`
- URL format: `http://localhost:8025/api/qr/{account_id}`
- No authentication required for this endpoint - No authentication required for this endpoint
- The QR code updates automatically when a new code is generated - The QR code updates automatically when a new code is generated
### Webhook Events ### Webhook Events
The QR code URL is also included in the `whatsapp.qr.code` event: The QR code URL is also included in the `whatsapp.qr.code` event:
```json ```json
{ {
"type": "whatsapp.qr.code", "type": "whatsapp.qr.code",
"data": { "data": {
"account_id": "personal", "account_id": "personal",
"qr_code": "2@...", "qr_code": "2@...",
"qr_url": "http://localhost:8080/api/qr/personal" "qr_url": "http://localhost:8025/api/qr/personal"
} }
} }
``` ```
@@ -152,6 +159,7 @@ The system uses a central event bus to decouple components:
- Webhook responses trigger message sends - Webhook responses trigger message sends
This architecture enables: This architecture enables:
- Loose coupling between WhatsApp and webhooks - Loose coupling between WhatsApp and webhooks
- Easy addition of new event subscribers - Easy addition of new event subscribers
- Centralized event logging and monitoring - Centralized event logging and monitoring
@@ -202,7 +210,7 @@ func main() {
// Your own handlers // Your own handlers
mux.HandleFunc("/api/v1/custom", yourCustomHandler) mux.HandleFunc("/api/v1/custom", yourCustomHandler)
http.ListenAndServe(":8080", mux) http.ListenAndServe(":8025", mux)
} }
``` ```
@@ -212,7 +220,7 @@ Configure WhatsHooked entirely in code without a config file:
```go ```go
wh, err := whatshooked.New( wh, err := whatshooked.New(
whatshooked.WithServer("0.0.0.0", 8080), whatshooked.WithServer("0.0.0.0", 8025),
whatshooked.WithAuth("my-api-key", "", ""), whatshooked.WithAuth("my-api-key", "", ""),
whatshooked.WithWhatsmeowAccount( whatshooked.WithWhatsmeowAccount(
"personal", "personal",
@@ -347,6 +355,7 @@ make build
``` ```
Or manually: Or manually:
```bash ```bash
mkdir -p bin mkdir -p bin
go build -o bin/whatshook-server ./cmd/server go build -o bin/whatshook-server ./cmd/server
@@ -362,6 +371,7 @@ cp config.example.json config.json
``` ```
Or use one of the HTTPS examples: Or use one of the HTTPS examples:
```bash ```bash
# Self-signed certificate (development) # Self-signed certificate (development)
cp config.https-self-signed.example.json config.json cp config.https-self-signed.example.json config.json
@@ -379,7 +389,7 @@ Edit the configuration file to add your WhatsApp accounts and webhooks:
{ {
"server": { "server": {
"host": "localhost", "host": "localhost",
"port": 8080, "port": 8025,
"default_country_code": "27" "default_country_code": "27"
}, },
"whatsapp": [ "whatsapp": [
@@ -423,23 +433,27 @@ Edit the configuration file to add your WhatsApp accounts and webhooks:
### Configuration Options ### Configuration Options
**Server Configuration:** **Server Configuration:**
- `host`: Server hostname (default: "localhost") - `host`: Server hostname (default: "localhost")
- `port`: Server port (default: 8080) - `port`: Server port (default: 8025)
- `default_country_code`: Default country code for phone number formatting (e.g., "27" for South Africa, "1" for US/Canada) - `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) - `username`: Username for HTTP Basic Authentication (optional)
- `password`: Password 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) - `auth_key`: API key for x-api-key header or Authorization Bearer token authentication (optional)
**WhatsApp Account Configuration:** **WhatsApp Account Configuration:**
- `id`: Unique identifier for this account - `id`: Unique identifier for this account
- `type`: Client type - `"whatsmeow"` for personal or `"business-api"` for Business API (defaults to "whatsmeow") - `type`: Client type - `"whatsmeow"` for personal or `"business-api"` for Business API (defaults to "whatsmeow")
- `phone_number`: Phone number with country code - `phone_number`: Phone number with country code
**For whatsmeow (personal) accounts:** **For whatsmeow (personal) accounts:**
- `session_path`: Path to store session data (default: `./sessions/{id}`) - `session_path`: Path to store session data (default: `./sessions/{id}`)
- `show_qr`: Display QR code in terminal for pairing (default: false) - `show_qr`: Display QR code in terminal for pairing (default: false)
**For business-api accounts:** **For business-api accounts:**
- `business_api`: Business API configuration object - `business_api`: Business API configuration object
- `phone_number_id`: WhatsApp Business Phone Number ID from Meta - `phone_number_id`: WhatsApp Business Phone Number ID from Meta
- `access_token`: Access token from Meta Business Manager - `access_token`: Access token from Meta Business Manager
@@ -448,6 +462,7 @@ Edit the configuration file to add your WhatsApp accounts and webhooks:
- `verify_token`: Token for webhook verification (required for receiving messages) - `verify_token`: Token for webhook verification (required for receiving messages)
**Hook Configuration:** **Hook Configuration:**
- `id`: Unique identifier for this hook - `id`: Unique identifier for this hook
- `name`: Human-readable name - `name`: Human-readable name
- `url`: Webhook URL to call - `url`: Webhook URL to call
@@ -480,6 +495,7 @@ Automatically generates and manages self-signed certificates. Ideal for developm
``` ```
Or programmatically: Or programmatically:
```go ```go
wh, err := whatshooked.New( wh, err := whatshooked.New(
whatshooked.WithServer("0.0.0.0", 8443), whatshooked.WithServer("0.0.0.0", 8443),
@@ -488,6 +504,7 @@ wh, err := whatshooked.New(
``` ```
**Features:** **Features:**
- Automatically generates certificates on first run - Automatically generates certificates on first run
- Certificates valid for 1 year - Certificates valid for 1 year
- Auto-renewal when expiring within 30 days - Auto-renewal when expiring within 30 days
@@ -516,6 +533,7 @@ Use your own certificate files from a trusted Certificate Authority (CA) or an e
``` ```
Or programmatically: Or programmatically:
```go ```go
wh, err := whatshooked.New( wh, err := whatshooked.New(
whatshooked.WithServer("0.0.0.0", 8443), whatshooked.WithServer("0.0.0.0", 8443),
@@ -524,6 +542,7 @@ wh, err := whatshooked.New(
``` ```
**Features:** **Features:**
- Use certificates from any CA (Let's Encrypt, DigiCert, etc.) - Use certificates from any CA (Let's Encrypt, DigiCert, etc.)
- Full control over certificate lifecycle - Full control over certificate lifecycle
- Validates certificate files on startup - Validates certificate files on startup
@@ -551,6 +570,7 @@ Automatically obtains and renews SSL certificates from Let's Encrypt. Best for p
``` ```
Or programmatically: Or programmatically:
```go ```go
wh, err := whatshooked.New( wh, err := whatshooked.New(
whatshooked.WithServer("0.0.0.0", 443), whatshooked.WithServer("0.0.0.0", 443),
@@ -559,6 +579,7 @@ wh, err := whatshooked.New(
``` ```
**Features:** **Features:**
- Automatic certificate provisioning from Let's Encrypt - Automatic certificate provisioning from Let's Encrypt
- Automatic certificate renewal before expiration - Automatic certificate renewal before expiration
- Fully managed - no manual intervention required - Fully managed - no manual intervention required
@@ -566,6 +587,7 @@ wh, err := whatshooked.New(
- Production and staging modes available - Production and staging modes available
**Requirements:** **Requirements:**
- Server must be publicly accessible - Server must be publicly accessible
- Port 443 (HTTPS) must be open - Port 443 (HTTPS) must be open
- Port 80 (HTTP) must be open for ACME challenges - Port 80 (HTTP) must be open for ACME challenges
@@ -573,6 +595,7 @@ wh, err := whatshooked.New(
- Email address for Let's Encrypt notifications - Email address for Let's Encrypt notifications
**Important Notes:** **Important Notes:**
- Set `production: false` for testing to use Let's Encrypt staging environment (avoids rate limits) - Set `production: false` for testing to use Let's Encrypt staging environment (avoids rate limits)
- Set `production: true` for production deployments to get trusted certificates - Set `production: true` for production deployments to get trusted certificates
- Ensure your domain's DNS A/AAAA record points to your server's IP - Ensure your domain's DNS A/AAAA record points to your server's IP
@@ -614,7 +637,7 @@ To disable HTTPS and use HTTP, set `enabled: false` or omit the `tls` section en
{ {
"server": { "server": {
"host": "localhost", "host": "localhost",
"port": 8080 "port": 8025
} }
} }
``` ```
@@ -624,13 +647,14 @@ To disable HTTPS and use HTTP, set `enabled: false` or omit the `tls` section en
The server supports two authentication methods to protect API endpoints: The server supports two authentication methods to protect API endpoints:
#### 1. HTTP Basic Authentication #### 1. HTTP Basic Authentication
Set both `username` and `password` in the server configuration: Set both `username` and `password` in the server configuration:
```json ```json
{ {
"server": { "server": {
"host": "localhost", "host": "localhost",
"port": 8080, "port": 8025,
"username": "admin", "username": "admin",
"password": "secure_password" "password": "secure_password"
} }
@@ -638,31 +662,34 @@ Set both `username` and `password` in the server configuration:
``` ```
Clients must provide credentials in the Authorization header: Clients must provide credentials in the Authorization header:
```bash ```bash
curl -u admin:secure_password http://localhost:8080/api/hooks curl -u admin:secure_password http://localhost:8025/api/hooks
``` ```
#### 2. API Key Authentication #### 2. API Key Authentication
Set `auth_key` in the server configuration: Set `auth_key` in the server configuration:
```json ```json
{ {
"server": { "server": {
"host": "localhost", "host": "localhost",
"port": 8080, "port": 8025,
"auth_key": "your-secret-api-key" "auth_key": "your-secret-api-key"
} }
} }
``` ```
Clients can provide the API key using either: Clients can provide the API key using either:
- **x-api-key header**: - **x-api-key header**:
```bash ```bash
curl -H "x-api-key: your-secret-api-key" http://localhost:8080/api/hooks curl -H "x-api-key: your-secret-api-key" http://localhost:8025/api/hooks
``` ```
- **Authorization Bearer token**: - **Authorization Bearer token**:
```bash ```bash
curl -H "Authorization: Bearer your-secret-api-key" http://localhost:8080/api/hooks curl -H "Authorization: Bearer your-secret-api-key" http://localhost:8025/api/hooks
``` ```
#### Authentication Notes #### Authentication Notes
@@ -716,6 +743,7 @@ Add a Business API account to your `config.json`:
``` ```
**Important Notes:** **Important Notes:**
- Use a **permanent access token**, not the temporary 24-hour token - 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 - 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 - Keep your access token secure and never commit it to version control
@@ -727,7 +755,7 @@ To receive incoming messages from WhatsApp Business API, you must register your
1. **Start the WhatsHooked server** with your Business API configuration 1. **Start the WhatsHooked server** with your Business API configuration
2. **Ensure your server is publicly accessible** (use ngrok for testing): 2. **Ensure your server is publicly accessible** (use ngrok for testing):
```bash ```bash
ngrok http 8080 ngrok http 8025
``` ```
3. **In Meta for Developers**, go to **WhatsApp** → **Configuration** 3. **In Meta for Developers**, go to **WhatsApp** → **Configuration**
4. **Add Webhook URL**: 4. **Add Webhook URL**:
@@ -750,11 +778,13 @@ Once configured, start the server and the Business API account will connect auto
``` ```
Look for logs indicating successful connection: Look for logs indicating successful connection:
``` ```
Business API client connected account_id=business phone=+1234567890 Business API client connected account_id=business phone=+1234567890
``` ```
Send a test message: Send a test message:
```bash ```bash
./bin/whatshook-cli send ./bin/whatshook-cli send
# Select your business account # Select your business account
@@ -765,6 +795,7 @@ Send a test message:
### Business API Features ### Business API Features
**Supported:** **Supported:**
- ✅ Send/receive text messages - ✅ Send/receive text messages
- ✅ Send/receive images with captions - ✅ Send/receive images with captions
- ✅ Send/receive videos with captions - ✅ Send/receive videos with captions
@@ -783,6 +814,7 @@ Send a test message:
- ✅ Event publishing to webhooks (same format as whatsmeow) - ✅ Event publishing to webhooks (same format as whatsmeow)
**Differences from whatsmeow:** **Differences from whatsmeow:**
- No QR code pairing (uses access token authentication) - No QR code pairing (uses access token authentication)
- Rate limits apply based on your Meta Business tier - Rate limits apply based on your Meta Business tier
- Official support from Meta - Official support from Meta
@@ -816,6 +848,7 @@ You can run both personal (whatsmeow) and Business API accounts at the same time
``` ```
Both accounts will: Both accounts will:
- Receive messages independently - Receive messages independently
- Trigger the same webhooks - Trigger the same webhooks
- Publish identical event formats - Publish identical event formats
@@ -846,6 +879,7 @@ The QR code is also published as an event (`whatsapp.qr.code`) so you can handle
### Using the CLI ### Using the CLI
The CLI uses Cobra and supports configuration from multiple sources with the following priority: The CLI uses Cobra and supports configuration from multiple sources with the following priority:
1. Command-line flags (highest priority) 1. Command-line flags (highest priority)
2. Environment variables 2. Environment variables
3. Configuration file (lowest priority) 3. Configuration file (lowest priority)
@@ -853,34 +887,40 @@ The CLI uses Cobra and supports configuration from multiple sources with the fol
#### Configuration #### Configuration
Create a CLI configuration file (optional): Create a CLI configuration file (optional):
```bash ```bash
cp .whatshooked-cli.example.json .whatshooked-cli.json cp .whatshooked-cli.example.json .whatshooked-cli.json
``` ```
Or set via environment variable: Or set via environment variable:
```bash ```bash
export WHATSHOOKED_SERVER_URL=http://localhost:8080 export WHATSHOOKED_SERVER_URL=http://localhost:8025
``` ```
Or use command-line flag: Or use command-line flag:
```bash ```bash
./bin/whatshook-cli --server http://localhost:8080 health ./bin/whatshook-cli --server http://localhost:8025 health
``` ```
#### Commands #### Commands
Get help: Get help:
```bash ```bash
./bin/whatshook-cli --help ./bin/whatshook-cli --help
./bin/whatshook-cli hooks --help ./bin/whatshook-cli hooks --help
``` ```
Check server health: Check server health:
```bash ```bash
./bin/whatshook-cli health ./bin/whatshook-cli health
``` ```
List all hooks: List all hooks:
```bash ```bash
./bin/whatshook-cli hooks list ./bin/whatshook-cli hooks list
# or just # or just
@@ -888,16 +928,19 @@ List all hooks:
``` ```
Add a new hook: Add a new hook:
```bash ```bash
./bin/whatshook-cli hooks add ./bin/whatshook-cli hooks add
``` ```
Remove a hook: Remove a hook:
```bash ```bash
./bin/whatshook-cli hooks remove <hook_id> ./bin/whatshook-cli hooks remove <hook_id>
``` ```
List WhatsApp accounts: List WhatsApp accounts:
```bash ```bash
./bin/whatshook-cli accounts list ./bin/whatshook-cli accounts list
# or just # or just
@@ -905,11 +948,13 @@ List WhatsApp accounts:
``` ```
Add a WhatsApp account: Add a WhatsApp account:
```bash ```bash
./bin/whatshook-cli accounts add ./bin/whatshook-cli accounts add
``` ```
Send a message: Send a message:
```bash ```bash
./bin/whatshook-cli send ./bin/whatshook-cli send
``` ```
@@ -918,10 +963,10 @@ Send a message:
The CLI loads configuration with the following priority (highest to lowest): The CLI loads configuration with the following priority (highest to lowest):
1. **Command-line flags**: `--server http://example.com:8080` 1. **Command-line flags**: `--server http://example.com:8025`
2. **Environment variables**: `WHATSHOOKED_SERVER_URL=http://example.com:8080` 2. **Environment variables**: `WHATSHOOKED_SERVER_URL=http://example.com:8025`
3. **Config file**: `.whatshooked-cli.json` in current directory or `$HOME/.whatshooked/cli.json` 3. **Config file**: `.whatshooked-cli.json` in current directory or `$HOME/.whatshooked/cli.json`
4. **Defaults**: `http://localhost:8080` 4. **Defaults**: `http://localhost:8025`
## Webhook Integration ## Webhook Integration
@@ -968,6 +1013,7 @@ Or using full JID format:
``` ```
Fields: Fields:
- `send_message`: Set to `true` to send a message - `send_message`: Set to `true` to send a message
- `to`: Recipient phone number or JID. Can be: - `to`: Recipient phone number or JID. Can be:
- Plain phone number (e.g., `"0834606792"`) - will be formatted using `default_country_code` - Plain phone number (e.g., `"0834606792"`) - will be formatted using `default_country_code`
@@ -989,6 +1035,7 @@ The server automatically formats phone numbers to WhatsApp JID format:
- Appends `@s.whatsapp.net` suffix - Appends `@s.whatsapp.net` suffix
Examples with `default_country_code: "27"`: Examples with `default_country_code: "27"`:
- `0834606792` → `27834606792@s.whatsapp.net` (replaces leading 0 with 27) - `0834606792` → `27834606792@s.whatsapp.net` (replaces leading 0 with 27)
- `083-460-6792` → `27834606792@s.whatsapp.net` (removes dashes, replaces 0) - `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` (already has country code)
@@ -1000,12 +1047,14 @@ Examples with `default_country_code: "27"`:
The server exposes the following HTTP endpoints: The server exposes the following HTTP endpoints:
**Public Endpoints:** **Public Endpoints:**
- `GET /health` - Health check (no authentication required) - `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) - `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):** **Protected Endpoints (require authentication if enabled):**
*Hooks & Accounts:* _Hooks & Accounts:_
- `GET /api/hooks` - List all hooks - `GET /api/hooks` - List all hooks
- `POST /api/hooks/add` - Add a new hook - `POST /api/hooks/add` - Add a new hook
- `POST /api/hooks/remove` - Remove a hook - `POST /api/hooks/remove` - Remove a hook
@@ -1016,7 +1065,8 @@ The server exposes the following HTTP endpoints:
- `POST /api/accounts/disable` - Disable a WhatsApp account - `POST /api/accounts/disable` - Disable a WhatsApp account
- `POST /api/accounts/enable` - Enable a WhatsApp account - `POST /api/accounts/enable` - Enable a WhatsApp account
*Send Messages:* _Send Messages:_
- `POST /api/send` - Send a text message - `POST /api/send` - Send a text message
- `POST /api/send/image` - Send an image - `POST /api/send/image` - Send an image
- `POST /api/send/video` - Send a video - `POST /api/send/video` - Send a video
@@ -1031,12 +1081,14 @@ The server exposes the following HTTP endpoints:
- `POST /api/send/reaction` - React to a message with an emoji (Business API) - `POST /api/send/reaction` - React to a message with an emoji (Business API)
- `POST /api/messages/read` - Mark a message as read (Business API) - `POST /api/messages/read` - Mark a message as read (Business API)
*Templates (Business API):* _Templates (Business API):_
- `POST /api/templates` - List all message templates for an account - `POST /api/templates` - List all message templates for an account
- `POST /api/templates/upload` - Create a new message template - `POST /api/templates/upload` - Create a new message template
- `POST /api/templates/delete` - Delete a template by name and language - `POST /api/templates/delete` - Delete a template by name and language
*Flows (Business API):* _Flows (Business API):_
- `POST /api/flows` - List all flows for an account - `POST /api/flows` - List all flows for an account
- `POST /api/flows/create` - Create a new flow - `POST /api/flows/create` - Create a new flow
- `POST /api/flows/get` - Get details of a specific flow - `POST /api/flows/get` - Get details of a specific flow
@@ -1045,28 +1097,33 @@ The server exposes the following HTTP endpoints:
- `POST /api/flows/deprecate` - Deprecate a flow (blocks new sessions; existing sessions continue) - `POST /api/flows/deprecate` - Deprecate a flow (blocks new sessions; existing sessions continue)
- `POST /api/flows/delete` - Permanently delete a flow - `POST /api/flows/delete` - Permanently delete a flow
*Phone Numbers (Business API):* _Phone Numbers (Business API):_
- `POST /api/phone-numbers` - List phone numbers for an account - `POST /api/phone-numbers` - List phone numbers for an account
- `POST /api/phone-numbers/request-code` - Request a verification code (SMS or VOICE) - `POST /api/phone-numbers/request-code` - Request a verification code (SMS or VOICE)
- `POST /api/phone-numbers/verify-code` - Verify a phone number with the received code - `POST /api/phone-numbers/verify-code` - Verify a phone number with the received code
*Business Profile (Business API):* _Business Profile (Business API):_
- `POST /api/business-profile` - Retrieve the business profile for an account - `POST /api/business-profile` - Retrieve the business profile for an account
- `POST /api/business-profile/update` - Update business profile fields (about, address, description, email, websites, vertical) - `POST /api/business-profile/update` - Update business profile fields (about, address, description, email, websites, vertical)
*Catalog / Commerce (Business API):* _Catalog / Commerce (Business API):_
- `POST /api/catalogs` - List product catalogs linked to an account - `POST /api/catalogs` - List product catalogs linked to an account
- `POST /api/catalogs/products` - List products in a specific catalog - `POST /api/catalogs/products` - List products in a specific catalog
- `POST /api/send/catalog` - Send a catalog message (shares full product catalog) - `POST /api/send/catalog` - Send a catalog message (shares full product catalog)
- `POST /api/send/product` - Send a single-product interactive message - `POST /api/send/product` - Send a single-product interactive message
- `POST /api/send/product-list` - Send a multi-product list message (up to 30 products across 10 sections) - `POST /api/send/product-list` - Send a multi-product list message (up to 30 products across 10 sections)
*Media:* _Media:_
- `GET /api/media/{accountID}/{filename}` - Serve media files - `GET /api/media/{accountID}/{filename}` - Serve media files
- `POST /api/media/upload` - Upload a media file to Meta and return its media_id (Business API) - `POST /api/media/upload` - Upload a media file to Meta and return its media_id (Business API)
- `POST /api/media-delete` - Delete a previously uploaded media file from Meta (Business API) - `POST /api/media-delete` - Delete a previously uploaded media file from Meta (Business API)
*Message Cache:* _Message Cache:_
- `GET /api/cache` - List cached events - `GET /api/cache` - List cached events
- `GET /api/cache/stats` - Cache statistics - `GET /api/cache/stats` - Cache statistics
- `POST /api/cache/replay` - Replay all cached events - `POST /api/cache/replay` - Replay all cached events
@@ -1135,6 +1192,7 @@ whatshooked/
The system publishes the following event types: The system publishes the following event types:
**WhatsApp Events:** **WhatsApp Events:**
- `whatsapp.connected` - WhatsApp client connected - `whatsapp.connected` - WhatsApp client connected
- `whatsapp.disconnected` - WhatsApp client disconnected - `whatsapp.disconnected` - WhatsApp client disconnected
- `whatsapp.pair.success` - Device pairing successful - `whatsapp.pair.success` - Device pairing successful
@@ -1145,11 +1203,13 @@ The system publishes the following event types:
- `whatsapp.pair.event` - Generic pairing event - `whatsapp.pair.event` - Generic pairing event
**Message Events:** **Message Events:**
- `message.received` - New message received from WhatsApp - `message.received` - New message received from WhatsApp
- `message.sent` - Message successfully sent to WhatsApp - `message.sent` - Message successfully sent to WhatsApp
- `message.failed` - Message send failed - `message.failed` - Message send failed
**Hook Events:** **Hook Events:**
- `hook.triggered` - Webhook is being called - `hook.triggered` - Webhook is being called
- `hook.success` - Webhook responded successfully - `hook.success` - Webhook responded successfully
- `hook.failed` - Webhook call failed - `hook.failed` - Webhook call failed

View File

@@ -574,40 +574,40 @@ Events are automatically cached when:
**List cached events:** **List cached events:**
```bash ```bash
curl -u username:password http://localhost:8080/api/cache curl -u username:password http://localhost:8025/api/cache
``` ```
**Get cache statistics:** **Get cache statistics:**
```bash ```bash
curl -u username:password http://localhost:8080/api/cache/stats curl -u username:password http://localhost:8025/api/cache/stats
``` ```
**Replay all cached events:** **Replay all cached events:**
```bash ```bash
curl -X POST -u username:password http://localhost:8080/api/cache/replay curl -X POST -u username:password http://localhost:8025/api/cache/replay
``` ```
**Replay specific event:** **Replay specific event:**
```bash ```bash
curl -X POST -u username:password \ curl -X POST -u username:password \
"http://localhost:8080/api/cache/event/replay?id=EVENT_ID" "http://localhost:8025/api/cache/event/replay?id=EVENT_ID"
``` ```
**Delete cached event:** **Delete cached event:**
```bash ```bash
curl -X DELETE -u username:password \ curl -X DELETE -u username:password \
"http://localhost:8080/api/cache/event/delete?id=EVENT_ID" "http://localhost:8025/api/cache/event/delete?id=EVENT_ID"
``` ```
**Clear all cache:** **Clear all cache:**
```bash ```bash
curl -X DELETE -u username:password \ curl -X DELETE -u username:password \
"http://localhost:8080/api/cache/clear?confirm=true" "http://localhost:8025/api/cache/clear?confirm=true"
``` ```
### Cache Workflow Example ### Cache Workflow Example
@@ -662,7 +662,7 @@ curl -X DELETE -u username:password \
1. `message_cache.enabled` is `true` in config 1. `message_cache.enabled` is `true` in config
2. Hooks are actually inactive or not matching events 2. Hooks are actually inactive or not matching events
3. Check cache stats: `curl -u user:pass http://localhost:8080/api/cache/stats` 3. Check cache stats: `curl -u user:pass http://localhost:8025/api/cache/stats`
### No Hooks Configured Error ### No Hooks Configured Error
@@ -715,7 +715,7 @@ Enable debug logging to trace the issue:
"type": "image", "type": "image",
"mime_type": "image/jpeg", "mime_type": "image/jpeg",
"filename": "wamid.xxx_a1b2c3d4.jpg", "filename": "wamid.xxx_a1b2c3d4.jpg",
"url": "http://localhost:8080/api/media/business/wamid.xxx_a1b2c3d4.jpg", "url": "http://localhost:8025/api/media/business/wamid.xxx_a1b2c3d4.jpg",
"base64": "..." // Only if media.mode is "base64" or "both" "base64": "..." // Only if media.mode is "base64" or "both"
} }
} }
@@ -776,7 +776,7 @@ Here's a complete `config.json` with all Business API features:
{ {
"server": { "server": {
"host": "0.0.0.0", "host": "0.0.0.0",
"port": 8080, "port": 8025,
"default_country_code": "1", "default_country_code": "1",
"username": "admin", "username": "admin",
"password": "secure_password", "password": "secure_password",

View File

@@ -20,7 +20,7 @@ func LoadCLIConfig(configFile string, serverFlag string) (*CLIConfig, error) {
v := viper.New() v := viper.New()
// Set defaults // Set defaults
v.SetDefault("server_url", "http://localhost:8080") v.SetDefault("server_url", "http://localhost:8025")
v.SetDefault("auth_key", "") v.SetDefault("auth_key", "")
v.SetDefault("username", "") v.SetDefault("username", "")
v.SetDefault("password", "") v.SetDefault("password", "")

View File

@@ -36,7 +36,7 @@ var rootCmd = &cobra.Command{
func init() { func init() {
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default: $HOME/.whatshooked/cli.json)") rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default: $HOME/.whatshooked/cli.json)")
rootCmd.PersistentFlags().StringVar(&serverURL, "server", "", "server URL (default: http://localhost:8080)") rootCmd.PersistentFlags().StringVar(&serverURL, "server", "", "server URL (default: http://localhost:8025)")
// Add all command groups // Add all command groups
rootCmd.AddCommand(healthCmd) rootCmd.AddCommand(healthCmd)

View File

@@ -1,5 +1,5 @@
{ {
"server_url": "http://localhost:8080", "server_url": "http://localhost:8025",
"auth_key": "", "auth_key": "",
"username": "", "username": "",
"password": "" "password": ""

View File

@@ -1,7 +1,7 @@
{ {
"server": { "server": {
"host": "localhost", "host": "localhost",
"port": 8080, "port": 8025,
"default_country_code": "27", "default_country_code": "27",
"username": "", "username": "",
"password": "", "password": "",
@@ -66,10 +66,7 @@
"Authorization": "Bearer your-token-here" "Authorization": "Bearer your-token-here"
}, },
"active": true, "active": true,
"events": [ "events": ["whatsapp.connected", "whatsapp.disconnected"],
"whatsapp.connected",
"whatsapp.disconnected"
],
"description": "Monitors WhatsApp connection status changes" "description": "Monitors WhatsApp connection status changes"
}, },
{ {
@@ -100,7 +97,7 @@
"media": { "media": {
"data_path": "./data/media", "data_path": "./data/media",
"mode": "link", "mode": "link",
"base_url": "http://localhost:8080" "base_url": "http://localhost:8025"
}, },
"database": { "database": {
"type": "postgres", "type": "postgres",
@@ -113,10 +110,7 @@
}, },
"event_logger": { "event_logger": {
"enabled": false, "enabled": false,
"targets": [ "targets": ["file", "sqlite"],
"file",
"sqlite"
],
"file_dir": "./data/events", "file_dir": "./data/events",
"table_name": "event_logs" "table_name": "event_logs"
}, },

View File

@@ -7,7 +7,7 @@ services:
dockerfile: Dockerfile dockerfile: Dockerfile
container_name: whatshooked-server container_name: whatshooked-server
ports: ports:
- "8080:8080" - "8025:8025"
volumes: volumes:
# Mount config file # Mount config file
- ./bin/config.json:/app/config.json:ro - ./bin/config.json:/app/config.json:ro
@@ -15,14 +15,14 @@ services:
# Mount sessions directory for WhatsApp authentication persistence # Mount sessions directory for WhatsApp authentication persistence
- ./bin/sessions:/app/sessions - ./bin/sessions:/app/sessions
# Mount media directory for storing downloaded media files # Mount data directory for storing data files
- ./bin/data/media:/app/data/media - ./bin/data/:/app/data/
restart: unless-stopped restart: unless-stopped
# Health check # Health check
healthcheck: healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8080/health"] test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8025/health"]
interval: 30s interval: 30s
timeout: 10s timeout: 10s
retries: 3 retries: 3

View File

@@ -152,7 +152,7 @@ func Load(path string) (*Config, error) {
cfg.Server.Host = "localhost" cfg.Server.Host = "localhost"
} }
if cfg.Server.Port == 0 { if cfg.Server.Port == 0 {
cfg.Server.Port = 8080 cfg.Server.Port = 8025
} }
if cfg.Media.DataPath == "" { if cfg.Media.DataPath == "" {
cfg.Media.DataPath = "./data/media" cfg.Media.DataPath = "./data/media"

View File

@@ -432,7 +432,7 @@ func (c *Client) saveMediaFile(messageID string, data []byte, mimeType string) (
func (c *Client) generateMediaURL(messageID, filename string) string { func (c *Client) generateMediaURL(messageID, filename string) string {
baseURL := c.mediaConfig.BaseURL baseURL := c.mediaConfig.BaseURL
if baseURL == "" { if baseURL == "" {
baseURL = "http://localhost:8080" baseURL = "http://localhost:8025"
} }
return fmt.Sprintf("%s/api/media/%s/%s", baseURL, c.id, filename) return fmt.Sprintf("%s/api/media/%s/%s", baseURL, c.id, filename)
} }

View File

@@ -678,7 +678,7 @@ func (c *Client) saveMediaFile(messageID string, data []byte, mimeType string) (
func (c *Client) generateMediaURL(messageID, filename string) string { func (c *Client) generateMediaURL(messageID, filename string) string {
baseURL := c.mediaConfig.BaseURL baseURL := c.mediaConfig.BaseURL
if baseURL == "" { if baseURL == "" {
baseURL = "http://localhost:8080" baseURL = "http://localhost:8025"
} }
return fmt.Sprintf("%s/api/media/%s/%s", baseURL, c.id, filename) return fmt.Sprintf("%s/api/media/%s/%s", baseURL, c.id, filename)
} }
@@ -737,7 +737,7 @@ func getExtensionFromMimeType(mimeType string) string {
func (c *Client) generateQRCodeURL() string { func (c *Client) generateQRCodeURL() string {
baseURL := c.mediaConfig.BaseURL baseURL := c.mediaConfig.BaseURL
if baseURL == "" { if baseURL == "" {
baseURL = "http://localhost:8080" baseURL = "http://localhost:8025"
} }
return fmt.Sprintf("%s/api/qr/%s", baseURL, c.id) return fmt.Sprintf("%s/api/qr/%s", baseURL, c.id)
} }

View File

@@ -45,7 +45,7 @@ func New(opts ...Option) (*WhatsHooked, error) {
cfg := &config.Config{ cfg := &config.Config{
Server: config.ServerConfig{ Server: config.ServerConfig{
Host: "localhost", Host: "localhost",
Port: 8080, Port: 8025,
}, },
Media: config.MediaConfig{ Media: config.MediaConfig{
DataPath: "./data/media", DataPath: "./data/media",