* Add registration process for new phone numbers * Clarify importance of registration for sending messages and 2FA * Improve formatting and clarity throughout the document
1041 lines
29 KiB
Markdown
1041 lines
29 KiB
Markdown
# WhatsApp Business API Setup Guide
|
|
|
|
This guide will help you set up WhatsApp Business API credentials for use with WhatsHooked.
|
|
|
|
## Common Error: "Object does not exist or missing permissions"
|
|
|
|
If you see this error:
|
|
|
|
```
|
|
Failed to connect client account_id=test error="API returned status 400:
|
|
{\"error\":{\"message\":\"Unsupported get request. Object with ID 'XXXXXXXXX' does not exist,
|
|
cannot be loaded due to missing permissions, or does not support this operation...\",
|
|
\"type\":\"GraphMethodException\",\"code\":100,\"error_subcode\":33...}}"
|
|
```
|
|
|
|
This means your **access token lacks the required WhatsApp Business API permissions**.
|
|
|
|
## Prerequisites
|
|
|
|
Before you begin, ensure you have:
|
|
|
|
1. A Meta Business Account
|
|
2. WhatsApp Business API access (approved by Meta)
|
|
3. A verified WhatsApp Business phone number
|
|
4. Admin access to your Meta Business Manager
|
|
|
|
## Step 1: Access Meta Business Manager
|
|
|
|
1. Go to [Meta Business Manager](https://business.facebook.com/)
|
|
2. Select your business account
|
|
3. Navigate to **Business Settings** (gear icon)
|
|
|
|
## Step 2: Create a System User (Recommended for Production)
|
|
|
|
System Users provide permanent access tokens that don't expire with user sessions.
|
|
|
|
1. In Business Settings, go to **Users** → **System Users**
|
|
2. Click **Add** to create a new system user
|
|
3. Enter a name (e.g., "WhatsHooked API Access")
|
|
4. Select **Admin** role
|
|
5. Click **Create System User**
|
|
|
|
## Step 3: Assign the System User to WhatsApp
|
|
|
|
1. In the System User details, scroll to **Assign Assets**
|
|
2. Click **Add Assets**
|
|
3. Select **Apps**
|
|
4. Choose your WhatsApp Business app
|
|
5. Grant **Full Control**
|
|
6. Click **Add People**
|
|
7. Select **WhatsApp Accounts**
|
|
8. Choose your WhatsApp Business Account
|
|
9. Grant **Full Control**
|
|
10. Click **Save Changes**
|
|
|
|
## Step 4: Generate Access Token with Required Permissions
|
|
|
|
1. In the System User details, click **Generate New Token**
|
|
2. Select your app from the dropdown
|
|
3. **IMPORTANT**: Check these permissions:
|
|
- ✅ `whatsapp_business_management`
|
|
- ✅ `whatsapp_business_messaging`
|
|
4. Set token expiration (choose "Never" for permanent tokens)
|
|
5. Click **Generate Token**
|
|
6. **CRITICAL**: Copy the token immediately - you won't see it again!
|
|
|
|
### Verify Token Permissions
|
|
|
|
You can verify your token has the correct permissions:
|
|
|
|
```bash
|
|
# Replace YOUR_TOKEN with your actual access token
|
|
curl -X GET 'https://graph.facebook.com/v21.0/debug_token?input_token=YOUR_TOKEN' \
|
|
-H 'Authorization: Bearer YOUR_TOKEN'
|
|
```
|
|
|
|
Look for `"scopes"` in the response - it should include:
|
|
|
|
```json
|
|
{
|
|
"data": {
|
|
"scopes": [
|
|
"whatsapp_business_management",
|
|
"whatsapp_business_messaging",
|
|
...
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
## Step 5: Get Your Phone Number ID
|
|
|
|
The Phone Number ID is **NOT** your actual phone number - it's a unique identifier from Meta.
|
|
|
|
### Method 1: Via WhatsApp Manager (Easiest)
|
|
|
|
1. Go to [WhatsApp Manager](https://business.facebook.com/wa/manage/home/)
|
|
2. Select your WhatsApp Business Account
|
|
3. Click **API Setup** in the left sidebar
|
|
4. Copy the **Phone Number ID** (looks like: `123456789012345`)
|
|
|
|
### Method 2: Via API
|
|
|
|
```bash
|
|
# Replace YOUR_TOKEN and YOUR_BUSINESS_ACCOUNT_ID
|
|
curl -X GET 'https://graph.facebook.com/v21.0/YOUR_BUSINESS_ACCOUNT_ID/phone_numbers' \
|
|
-H 'Authorization: Bearer YOUR_TOKEN'
|
|
```
|
|
|
|
Response:
|
|
|
|
```json
|
|
{
|
|
"data": [
|
|
{
|
|
"verified_name": "Your Business Name",
|
|
"display_phone_number": "+1 234-567-8900",
|
|
"id": "123456789012345", // <- This is your Phone Number ID
|
|
"quality_rating": "GREEN"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Step 6: Get Your Business Account ID (Optional)
|
|
|
|
```bash
|
|
# Get all WhatsApp Business Accounts you have access to
|
|
curl -X GET 'https://graph.facebook.com/v21.0/me/businesses' \
|
|
-H 'Authorization: Bearer YOUR_TOKEN'
|
|
```
|
|
|
|
Or find it in WhatsApp Manager:
|
|
|
|
1. Go to WhatsApp Manager
|
|
2. Click on **Settings** (gear icon)
|
|
3. The Business Account ID is shown in the URL: `https://business.facebook.com/wa/manage/home/?waba_id=XXXXXXXXX`
|
|
|
|
## Step 7: Register Your Phone Number (Required for New Numbers)
|
|
|
|
If this is a new phone number that hasn't been used for WhatsApp Business API before, you need to register it first.
|
|
|
|
### Why Registration is Needed
|
|
|
|
Phone numbers must be registered with WhatsApp to:
|
|
|
|
- Activate the number for sending messages
|
|
- Set up two-factor authentication (2FA)
|
|
- Verify ownership of the phone number
|
|
|
|
### Registration Process
|
|
|
|
**1. Get your 2FA PIN:**
|
|
|
|
You should have received a 6-digit PIN when you set up your WhatsApp Business phone number. If you don't have it:
|
|
|
|
- Go to [WhatsApp Manager](https://business.facebook.com/wa/manage/home/)
|
|
- Select your phone number
|
|
- Go to **Settings** → **Two-step verification**
|
|
- Note or reset your PIN
|
|
|
|
**2. Register the phone number:**
|
|
|
|
```bash
|
|
# Replace PHONE_NUMBER_ID with your Phone Number ID
|
|
# Replace YOUR_TOKEN with your access token
|
|
# Replace 890523 with your actual 2FA PIN
|
|
curl -X POST 'https://graph.facebook.com/v21.0/PHONE_NUMBER_ID/register' \
|
|
-H 'Authorization: Bearer YOUR_TOKEN' \
|
|
-H 'Content-Type: application/json' \
|
|
-d '{
|
|
"messaging_product": "whatsapp",
|
|
"pin": "123123"
|
|
}'
|
|
```
|
|
|
|
**Successful Response:**
|
|
|
|
```json
|
|
{
|
|
"success": true
|
|
}
|
|
```
|
|
|
|
**Error Response (if already registered):**
|
|
|
|
```json
|
|
{
|
|
"error": {
|
|
"message": "(#131030) Phone number has already been registered",
|
|
"type": "OAuthException",
|
|
"code": 131030,
|
|
"fbtrace_id": "..."
|
|
}
|
|
}
|
|
```
|
|
|
|
**Note:** If you get error code 131030, it means your number is already registered and you can skip this step.
|
|
|
|
### Important Notes
|
|
|
|
- ⚠️ **You only need to register once** - don't repeat this step unless you're setting up a new number
|
|
- ⚠️ **Keep your PIN secure** - it's used for two-factor authentication
|
|
- ⚠️ **Registration can take a few minutes** - wait before sending messages
|
|
- ⚠️ **If registration fails**, verify:
|
|
- Your PIN is correct (6 digits)
|
|
- Your access token has `whatsapp_business_management` permission
|
|
- The phone number is verified in Meta Business Manager
|
|
|
|
## Step 8: Test Your Credentials
|
|
|
|
After registration, test your credentials to confirm everything is working:
|
|
|
|
```bash
|
|
# Replace PHONE_NUMBER_ID and YOUR_TOKEN
|
|
curl -X GET 'https://graph.facebook.com/v21.0/PHONE_NUMBER_ID' \
|
|
-H 'Authorization: Bearer YOUR_TOKEN'
|
|
```
|
|
|
|
If successful, you'll get a response like:
|
|
|
|
```json
|
|
{
|
|
"verified_name": "Your Business Name",
|
|
"display_phone_number": "+1 234-567-8900",
|
|
"id": "123456789012345",
|
|
"quality_rating": "GREEN"
|
|
}
|
|
```
|
|
|
|
If you get an error like `"error_subcode":33`, your token lacks permissions - go back to Step 4.
|
|
|
|
## Step 9: Configure WhatsHooked
|
|
|
|
Update your `config.json` with the Business API configuration:
|
|
|
|
```json
|
|
{
|
|
"whatsapp": [
|
|
{
|
|
"id": "business",
|
|
"type": "business-api",
|
|
"phone_number": "+1234567890",
|
|
"business_api": {
|
|
"phone_number_id": "123456789012345",
|
|
"access_token": "EAAxxxxxxxxxxxx_your_permanent_token_here",
|
|
"business_account_id": "987654321098765",
|
|
"api_version": "v21.0",
|
|
"verify_token": "your_secure_random_token_here"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Configuration Fields
|
|
|
|
| Field | Required | Description |
|
|
| --------------------- | -------- | ------------------------------------------------------ |
|
|
| `id` | Yes | Unique identifier for this account in WhatsHooked |
|
|
| `type` | Yes | Must be `"business-api"` |
|
|
| `phone_number` | Yes | Your WhatsApp Business phone number (E.164 format) |
|
|
| `phone_number_id` | Yes | Phone Number ID from Meta (from Step 5) |
|
|
| `access_token` | Yes | Permanent access token (from Step 4) |
|
|
| `business_account_id` | No | WhatsApp Business Account ID (optional, for reference) |
|
|
| `api_version` | No | Graph API version (defaults to `"v21.0"`) |
|
|
| `verify_token` | Yes | Random string for webhook verification (see Step 9a) |
|
|
|
|
### Step 9a: Generate Verify Token
|
|
|
|
The verify token is used by Meta to verify your webhook endpoint. Generate a secure random string:
|
|
|
|
```bash
|
|
# Generate a random token
|
|
openssl rand -hex 32
|
|
|
|
# Or use any secure random string like:
|
|
# "my_secure_verify_token_abc123xyz789"
|
|
```
|
|
|
|
Add this token to your `config.json` (see above) and save it - you'll need it for webhook configuration in Step 11.
|
|
|
|
## Step 10: Start WhatsHooked
|
|
|
|
```bash
|
|
./bin/whatshook-server -config config.json
|
|
```
|
|
|
|
You should see:
|
|
|
|
```
|
|
INFO Business API client connected account_id=business phone=+1234567890
|
|
INFO Hook manager started and subscribed to events event_types=13
|
|
```
|
|
|
|
If you see `Failed to connect client`, check the error message and verify:
|
|
|
|
1. Phone Number ID is correct
|
|
2. Access token has required permissions
|
|
3. Access token hasn't expired
|
|
4. Business Account has WhatsApp API access enabled
|
|
|
|
## Step 11: Configure Webhook in Meta Developer Console
|
|
|
|
WhatsHooked provides a webhook endpoint to receive incoming messages and status updates from WhatsApp.
|
|
|
|
### 11.1: Webhook URL Format
|
|
|
|
Your webhook URL should be:
|
|
|
|
```
|
|
https://your-domain.com/webhooks/whatsapp/{account_id}
|
|
```
|
|
|
|
Where `{account_id}` matches the `id` field in your config (e.g., "business").
|
|
|
|
**Example**: If your domain is `api.example.com` and account ID is `business`:
|
|
|
|
```
|
|
https://api.example.com/webhooks/whatsapp/business
|
|
```
|
|
|
|
### 11.2: Configure in Meta Developer Console
|
|
|
|
1. Go to [Meta Developers](https://developers.facebook.com/)
|
|
2. Select your app
|
|
3. Navigate to **WhatsApp** → **Configuration**
|
|
4. Under "Webhook", click **Edit**
|
|
5. Enter:
|
|
- **Callback URL**: `https://your-domain.com/webhooks/whatsapp/business`
|
|
- **Verify Token**: The same token from your `config.json` (`verify_token` field)
|
|
6. Click **Verify and Save**
|
|
|
|
Meta will send a GET request to verify your endpoint. If verification succeeds, you'll see a green checkmark.
|
|
|
|
### 11.3: Subscribe to Webhook Events
|
|
|
|
After verification, subscribe to these webhook fields:
|
|
|
|
- ✅ **messages** - Incoming messages and message status updates
|
|
- ✅ **message_template_status_update** - Template approval/rejection (optional)
|
|
- ✅ **account_update** - Account changes (optional)
|
|
- ✅ **phone_number_quality_update** - Quality rating changes (optional)
|
|
|
|
Click **Subscribe** for each field you want to receive.
|
|
|
|
## Supported Webhook Events
|
|
|
|
WhatsHooked supports all WhatsApp Business API webhook events and message types:
|
|
|
|
### Message Types
|
|
|
|
| Type | Supported | Downloads Media | Description |
|
|
| ------------- | --------- | --------------- | --------------------------------- |
|
|
| `text` | ✅ | N/A | Text messages |
|
|
| `image` | ✅ | ✅ | Images with optional caption |
|
|
| `video` | ✅ | ✅ | Videos with optional caption |
|
|
| `document` | ✅ | ✅ | PDFs, docs, etc. with filename |
|
|
| `audio` | ✅ | ✅ | Voice messages and audio files |
|
|
| `sticker` | ✅ | ✅ | Animated and static stickers |
|
|
| `location` | ✅ | N/A | GPS coordinates with name/address |
|
|
| `contacts` | ✅ | N/A | Shared contact cards (vCard) |
|
|
| `interactive` | ✅ | N/A | Button/list/flow replies |
|
|
| `button` | ✅ | N/A | Quick reply button responses |
|
|
| `reaction` | ✅ | N/A | Emoji reactions to messages |
|
|
| `order` | ✅ | N/A | Catalog/commerce orders |
|
|
| `system` | ✅ | N/A | System notifications |
|
|
|
|
### Status Updates
|
|
|
|
| Status | Event | Description |
|
|
| ----------- | ------------------- | ------------------------------ |
|
|
| `sent` | `message.sent` | Message sent from your number |
|
|
| `delivered` | `message.delivered` | Message delivered to recipient |
|
|
| `read` | `message.read` | Message read by recipient |
|
|
| `failed` | `message.failed` | Message delivery failed |
|
|
|
|
### Webhook Notification Types
|
|
|
|
| Field | Description | Events Published |
|
|
| -------------------------------- | ---------------------- | ------------------------------------------ |
|
|
| `messages` | Message events | `message.received`, message status updates |
|
|
| `message_template_status_update` | Template changes | Logged to console |
|
|
| `account_update` | Account config changes | Logged to console |
|
|
| `phone_number_quality_update` | Quality rating changes | Logged to console |
|
|
| `phone_number_name_update` | Display name changes | Logged to console |
|
|
| `account_alerts` | Important alerts | Logged to console |
|
|
|
|
## Webhook Security
|
|
|
|
WhatsHooked implements proper webhook security:
|
|
|
|
1. **Verification**: Uses the `verify_token` to verify Meta's webhook setup request
|
|
2. **Account isolation**: Each account has its own webhook endpoint path
|
|
3. **No authentication required**: Meta's webhooks don't support custom auth headers
|
|
4. **Validation**: Verifies webhook payload structure
|
|
|
|
### Webhook Verification Flow
|
|
|
|
```
|
|
Meta sends: GET /webhooks/whatsapp/business?hub.mode=subscribe&hub.verify_token=YOUR_TOKEN&hub.challenge=CHALLENGE
|
|
↓
|
|
WhatsHooked verifies token
|
|
↓
|
|
Returns CHALLENGE (200 OK) if valid
|
|
403 Forbidden if invalid
|
|
```
|
|
|
|
### Receiving Messages
|
|
|
|
```
|
|
Meta sends: POST /webhooks/whatsapp/business
|
|
↓
|
|
WhatsHooked processes webhook
|
|
↓
|
|
Downloads media (if present)
|
|
↓
|
|
Publishes to event bus
|
|
↓
|
|
Triggers your configured hooks
|
|
↓
|
|
Returns 200 OK
|
|
```
|
|
|
|
## Testing Webhooks
|
|
|
|
### Test with Meta's Test Button
|
|
|
|
1. In WhatsApp Configuration → Webhooks
|
|
2. Click **Test** next to "messages"
|
|
3. Select a sample event (e.g., "Text Message")
|
|
4. Click **Send to My Server**
|
|
5. Check WhatsHooked logs for the received event
|
|
|
|
### Test with Real Messages
|
|
|
|
1. Send a message to your WhatsApp Business number
|
|
2. Check WhatsHooked logs (set `"log_level": "debug"` for details):
|
|
|
|
```
|
|
DEBUG Publishing message received event account_id=business message_id=wamid.xxx from=1234567890 type=text
|
|
DEBUG Hook manager received event event_type=message.received
|
|
DEBUG Hook matches event hook_id=message_hook event_type=message.received
|
|
DEBUG Found relevant hooks for event event_type=message.received hook_count=1
|
|
DEBUG Sending to hook hook_id=message_hook url=https://your-webhook.com/messages
|
|
```
|
|
|
|
3. Your webhook should receive the payload
|
|
|
|
### Webhook Payload Example
|
|
|
|
```json
|
|
{
|
|
"account_id": "business",
|
|
"message_id": "wamid.HBgNMTIzNDU2Nzg5MAUCABEYEjQyMzRGRDhENzk5MkY5OUFBMQA",
|
|
"from": "1234567890",
|
|
"to": "1234567890",
|
|
"text": "Hello World",
|
|
"timestamp": "2026-01-30T12:00:00Z",
|
|
"is_group": false,
|
|
"sender_name": "John Doe",
|
|
"message_type": "text"
|
|
}
|
|
```
|
|
|
|
## Step 12: Configure Your Webhooks
|
|
|
|
WhatsHooked forwards events to your own webhook URLs. Configure them in `config.json`:
|
|
|
|
```json
|
|
{
|
|
"hooks": [
|
|
{
|
|
"id": "message_hook",
|
|
"name": "Message Handler",
|
|
"url": "https://your-app.com/api/whatsapp/messages",
|
|
"method": "POST",
|
|
"headers": {
|
|
"Authorization": "Bearer your-app-token"
|
|
},
|
|
"active": true,
|
|
"events": [
|
|
"message.received",
|
|
"message.sent",
|
|
"message.delivered",
|
|
"message.read"
|
|
],
|
|
"description": "Receives all message events"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Hook Configuration Fields
|
|
|
|
| Field | Required | Description |
|
|
| ------------- | -------- | ------------------------------------------- |
|
|
| `id` | Yes | Unique identifier for this hook |
|
|
| `name` | Yes | Human-readable name |
|
|
| `url` | Yes | Your webhook URL to receive events |
|
|
| `method` | Yes | HTTP method (usually "POST") |
|
|
| `headers` | No | Custom headers (for authentication, etc.) |
|
|
| `active` | Yes | Enable/disable this hook |
|
|
| `events` | No | Event types to receive (empty = all events) |
|
|
| `description` | No | Description for documentation |
|
|
|
|
### Available Event Types
|
|
|
|
**Message Events:**
|
|
|
|
- `message.received` - Incoming messages
|
|
- `message.sent` - Outgoing messages
|
|
- `message.delivered` - Delivery confirmations
|
|
- `message.read` - Read receipts
|
|
- `message.failed` - Delivery failures
|
|
|
|
**Connection Events:**
|
|
|
|
- `whatsapp.connected` - Account connected
|
|
- `whatsapp.disconnected` - Account disconnected
|
|
|
|
**QR Code Events** (whatsmeow only):
|
|
|
|
- `whatsapp.qr.code` - QR code for pairing
|
|
- `whatsapp.qr.timeout` - QR code expired
|
|
- `whatsapp.qr.error` - QR code error
|
|
|
|
**Hook Events:**
|
|
|
|
- `hook.triggered` - Hook was called
|
|
- `hook.success` - Hook responded successfully
|
|
- `hook.failed` - Hook call failed
|
|
|
|
### Query Parameters
|
|
|
|
WhatsHooked automatically adds query parameters to your webhook URL:
|
|
|
|
```
|
|
https://your-app.com/api/whatsapp/messages?event=message.received&account_id=business
|
|
```
|
|
|
|
- `event` - The event type
|
|
- `account_id` - The WhatsApp account that triggered the event
|
|
|
|
## Message Cache System
|
|
|
|
WhatsHooked includes a message cache that stores events when no active webhooks are configured. This ensures zero message loss.
|
|
|
|
### Enable Message Cache
|
|
|
|
Add to your `config.json`:
|
|
|
|
```json
|
|
{
|
|
"message_cache": {
|
|
"enabled": true,
|
|
"data_path": "./data/message_cache",
|
|
"max_age_days": 7,
|
|
"max_events": 10000
|
|
}
|
|
}
|
|
```
|
|
|
|
### When Events Are Cached
|
|
|
|
Events are automatically cached when:
|
|
|
|
- No webhooks are configured for the event type
|
|
- All webhooks are inactive (`"active": false`)
|
|
- No webhooks match the event in their `events` array
|
|
|
|
### Cache Management API
|
|
|
|
**List cached events:**
|
|
|
|
```bash
|
|
curl -u username:password http://localhost:8080/api/cache
|
|
```
|
|
|
|
**Get cache statistics:**
|
|
|
|
```bash
|
|
curl -u username:password http://localhost:8080/api/cache/stats
|
|
```
|
|
|
|
**Replay all cached events:**
|
|
|
|
```bash
|
|
curl -X POST -u username:password http://localhost:8080/api/cache/replay
|
|
```
|
|
|
|
**Replay specific event:**
|
|
|
|
```bash
|
|
curl -X POST -u username:password \
|
|
"http://localhost:8080/api/cache/event/replay?id=EVENT_ID"
|
|
```
|
|
|
|
**Delete cached event:**
|
|
|
|
```bash
|
|
curl -X DELETE -u username:password \
|
|
"http://localhost:8080/api/cache/event/delete?id=EVENT_ID"
|
|
```
|
|
|
|
**Clear all cache:**
|
|
|
|
```bash
|
|
curl -X DELETE -u username:password \
|
|
"http://localhost:8080/api/cache/clear?confirm=true"
|
|
```
|
|
|
|
### Cache Workflow Example
|
|
|
|
1. **Disable webhooks** → New messages get cached
|
|
2. **Configure/enable webhooks** → Future messages delivered immediately
|
|
3. **Call replay API** → Cached messages delivered to webhooks
|
|
4. **Successful delivery** → Events removed from cache automatically
|
|
|
|
## Troubleshooting
|
|
|
|
### Webhooks Not Receiving Events
|
|
|
|
**Check these items:**
|
|
|
|
1. **Verify token is correct** in both `config.json` and Meta Developer Console
|
|
2. **Check webhook is active** in Meta console (green checkmark)
|
|
3. **Verify URL is accessible** from internet (Meta needs to reach it)
|
|
4. **Check logs** with `"log_level": "debug"`:
|
|
```
|
|
DEBUG Publishing message received event account_id=business
|
|
DEBUG Hook manager received event event_type=message.received
|
|
DEBUG Hook matches event hook_id=message_hook
|
|
```
|
|
5. **Test with curl**:
|
|
```bash
|
|
# Send test message to your WhatsApp Business number
|
|
# Check if webhook receives it
|
|
```
|
|
|
|
### Webhook Verification Fails
|
|
|
|
**Error**: "The callback URL or verify token couldn't be validated"
|
|
|
|
**Causes**:
|
|
|
|
- `verify_token` mismatch between config.json and Meta console
|
|
- WhatsHooked server not running
|
|
- Firewall blocking Meta's IP ranges
|
|
- Wrong webhook URL format
|
|
|
|
**Fix**:
|
|
|
|
1. Ensure server is running: `./bin/whatshook-server -config config.json`
|
|
2. Check logs for verification attempt
|
|
3. Verify token matches exactly (case-sensitive)
|
|
4. Test URL is accessible: `curl https://your-domain.com/webhooks/whatsapp/business`
|
|
|
|
### Messages Not Cached
|
|
|
|
**Check**:
|
|
|
|
1. `message_cache.enabled` is `true` in config
|
|
2. Hooks are actually inactive or not matching events
|
|
3. Check cache stats: `curl -u user:pass http://localhost:8080/api/cache/stats`
|
|
|
|
### No Hooks Configured Error
|
|
|
|
If events are being cached but you have hooks configured, check:
|
|
|
|
- Hook `"active"` is `true`
|
|
- Hook `"events"` array includes the event type (or is empty for all events)
|
|
- Hook URL is reachable and responding with 2xx status
|
|
|
|
Enable debug logging to trace the issue:
|
|
|
|
```json
|
|
{
|
|
"log_level": "debug"
|
|
}
|
|
```
|
|
|
|
## Webhook Payload Examples
|
|
|
|
### Text Message
|
|
|
|
```json
|
|
{
|
|
"account_id": "business",
|
|
"message_id": "wamid.HBgNMTIzNDU2Nzg5MAUCABEYEjQyMzRGRDhENzk5MkY5OUFBMQA",
|
|
"from": "1234567890",
|
|
"to": "1234567890",
|
|
"text": "Hello, how can I help?",
|
|
"timestamp": "2026-01-30T12:00:00Z",
|
|
"is_group": false,
|
|
"sender_name": "John Doe",
|
|
"message_type": "text"
|
|
}
|
|
```
|
|
|
|
### Image Message (with media)
|
|
|
|
```json
|
|
{
|
|
"account_id": "business",
|
|
"message_id": "wamid.xxx",
|
|
"from": "1234567890",
|
|
"to": "1234567890",
|
|
"text": "Check this out!",
|
|
"timestamp": "2026-01-30T12:00:00Z",
|
|
"is_group": false,
|
|
"sender_name": "John Doe",
|
|
"message_type": "image",
|
|
"media": {
|
|
"type": "image",
|
|
"mime_type": "image/jpeg",
|
|
"filename": "wamid.xxx_a1b2c3d4.jpg",
|
|
"url": "http://localhost:8080/api/media/business/wamid.xxx_a1b2c3d4.jpg",
|
|
"base64": "..." // Only if media.mode is "base64" or "both"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Location Message
|
|
|
|
```json
|
|
{
|
|
"account_id": "business",
|
|
"message_id": "wamid.xxx",
|
|
"from": "1234567890",
|
|
"to": "1234567890",
|
|
"text": "Location: Office (123 Main St) - 40.712800, -74.006000",
|
|
"timestamp": "2026-01-30T12:00:00Z",
|
|
"is_group": false,
|
|
"sender_name": "John Doe",
|
|
"message_type": "location"
|
|
}
|
|
```
|
|
|
|
### Button Reply (Interactive)
|
|
|
|
```json
|
|
{
|
|
"account_id": "business",
|
|
"message_id": "wamid.xxx",
|
|
"from": "1234567890",
|
|
"to": "1234567890",
|
|
"text": "Yes, I'm interested",
|
|
"timestamp": "2026-01-30T12:00:00Z",
|
|
"is_group": false,
|
|
"sender_name": "John Doe",
|
|
"message_type": "interactive"
|
|
}
|
|
```
|
|
|
|
### Delivery Status
|
|
|
|
```json
|
|
{
|
|
"event_type": "message.delivered",
|
|
"timestamp": "2026-01-30T12:00:05Z",
|
|
"data": {
|
|
"account_id": "business",
|
|
"message_id": "wamid.xxx",
|
|
"from": "1234567890",
|
|
"timestamp": "2026-01-30T12:00:05Z"
|
|
}
|
|
}
|
|
```
|
|
|
|
## Complete Configuration Example
|
|
|
|
Here's a complete `config.json` with all Business API features:
|
|
|
|
```json
|
|
{
|
|
"server": {
|
|
"host": "0.0.0.0",
|
|
"port": 8080,
|
|
"default_country_code": "1",
|
|
"username": "admin",
|
|
"password": "secure_password",
|
|
"auth_key": "optional_api_key"
|
|
},
|
|
"whatsapp": [
|
|
{
|
|
"id": "business",
|
|
"type": "business-api",
|
|
"phone_number": "+1234567890",
|
|
"business_api": {
|
|
"phone_number_id": "123456789012345",
|
|
"access_token": "EAAxxxxxxxxxxxx",
|
|
"business_account_id": "987654321098765",
|
|
"api_version": "v21.0",
|
|
"verify_token": "my_secure_random_token_abc123"
|
|
}
|
|
}
|
|
],
|
|
"hooks": [
|
|
{
|
|
"id": "message_hook",
|
|
"name": "Message Handler",
|
|
"url": "https://your-app.com/api/whatsapp/messages",
|
|
"method": "POST",
|
|
"headers": {
|
|
"Authorization": "Bearer your-app-secret-token",
|
|
"X-Custom-Header": "value"
|
|
},
|
|
"active": true,
|
|
"events": [
|
|
"message.received",
|
|
"message.sent",
|
|
"message.delivered",
|
|
"message.read"
|
|
],
|
|
"description": "Handles all message events"
|
|
},
|
|
{
|
|
"id": "status_hook",
|
|
"name": "Connection Monitor",
|
|
"url": "https://your-app.com/api/whatsapp/status",
|
|
"method": "POST",
|
|
"active": true,
|
|
"events": ["whatsapp.connected", "whatsapp.disconnected"],
|
|
"description": "Monitors connection status"
|
|
}
|
|
],
|
|
"media": {
|
|
"data_path": "./data/media",
|
|
"mode": "link",
|
|
"base_url": "https://your-domain.com"
|
|
},
|
|
"message_cache": {
|
|
"enabled": true,
|
|
"data_path": "./data/message_cache",
|
|
"max_age_days": 7,
|
|
"max_events": 10000
|
|
},
|
|
"event_logger": {
|
|
"enabled": true,
|
|
"targets": ["file", "sqlite"],
|
|
"file_dir": "./data/events",
|
|
"table_name": "event_logs"
|
|
},
|
|
"log_level": "info"
|
|
}
|
|
```
|
|
|
|
## Advanced Features
|
|
|
|
### Media Handling Modes
|
|
|
|
WhatsHooked supports three media delivery modes:
|
|
|
|
**1. Link Mode** (default, recommended)
|
|
|
|
```json
|
|
{
|
|
"media": {
|
|
"mode": "link",
|
|
"base_url": "https://your-domain.com"
|
|
}
|
|
}
|
|
```
|
|
|
|
- Downloads media and stores locally
|
|
- Webhooks receive URL: `https://your-domain.com/api/media/business/filename.jpg`
|
|
- Efficient for large media files
|
|
|
|
**2. Base64 Mode**
|
|
|
|
```json
|
|
{
|
|
"media": {
|
|
"mode": "base64"
|
|
}
|
|
}
|
|
```
|
|
|
|
- Encodes media as base64 in webhook payload
|
|
- No separate download needed
|
|
- Good for small files, increases payload size
|
|
|
|
**3. Both Mode**
|
|
|
|
```json
|
|
{
|
|
"media": {
|
|
"mode": "both"
|
|
}
|
|
}
|
|
```
|
|
|
|
- Provides both URL and base64
|
|
- Maximum flexibility, largest payloads
|
|
|
|
### Event Logger
|
|
|
|
Track all events to file and/or database:
|
|
|
|
```json
|
|
{
|
|
"event_logger": {
|
|
"enabled": true,
|
|
"targets": ["file", "sqlite", "postgres"],
|
|
"file_dir": "./data/events",
|
|
"table_name": "event_logs"
|
|
},
|
|
"database": {
|
|
"type": "postgres",
|
|
"host": "localhost",
|
|
"port": 5432,
|
|
"username": "whatshooked",
|
|
"password": "password",
|
|
"database": "whatshooked"
|
|
}
|
|
}
|
|
```
|
|
|
|
Logged events include:
|
|
|
|
- All message events
|
|
- Connection status changes
|
|
- Hook success/failure
|
|
- Webhook triggers
|
|
|
|
### Two-Way Communication
|
|
|
|
Your webhooks can respond to trigger outgoing messages:
|
|
|
|
**Webhook Response Format:**
|
|
|
|
```json
|
|
{
|
|
"send_message": true,
|
|
"to": "1234567890",
|
|
"text": "Thanks for your message!",
|
|
"account_id": "business"
|
|
}
|
|
```
|
|
|
|
This sends a reply immediately when your webhook receives an event.
|
|
|
|
## Production Deployment Checklist
|
|
|
|
Before going live:
|
|
|
|
- [ ] Use a System User token (not personal user token)
|
|
- [ ] Set `verify_token` to a secure random string (32+ characters)
|
|
- [ ] Configure webhooks in Meta Developer Console
|
|
- [ ] Subscribe to required webhook fields (messages, etc.)
|
|
- [ ] Test webhook verification succeeds
|
|
- [ ] Enable HTTPS for production (required by Meta)
|
|
- [ ] Set up firewall rules to allow Meta's webhook IPs
|
|
- [ ] Configure authentication (`username`/`password` or `auth_key`)
|
|
- [ ] Enable message cache for reliability
|
|
- [ ] Set up event logging for audit trail
|
|
- [ ] Test sending and receiving messages
|
|
- [ ] Monitor logs for errors
|
|
- [ ] Set up log rotation for production
|
|
- [ ] Document your webhook endpoints
|
|
- [ ] Set up monitoring/alerts for webhook failures
|
|
|
|
## Troubleshooting Common Issues
|
|
|
|
### Error: "Object with ID does not exist" (error_subcode: 33)
|
|
|
|
**Cause**: One of the following:
|
|
|
|
- Incorrect Phone Number ID
|
|
- Access token lacks permissions
|
|
- Access token expired
|
|
|
|
**Fix**:
|
|
|
|
1. Verify token permissions (see Step 4)
|
|
2. Double-check Phone Number ID (see Step 5)
|
|
3. Generate a new token if needed
|
|
|
|
### Error: "Invalid OAuth access token"
|
|
|
|
**Cause**: Token is invalid or expired
|
|
|
|
**Fix**: Generate a new access token (Step 4)
|
|
|
|
### Error: "Application does not have permission"
|
|
|
|
**Cause**: App not added to WhatsApp Business Account
|
|
|
|
**Fix**: Complete Step 3 to assign System User to WhatsApp
|
|
|
|
### Token Expires Too Quickly
|
|
|
|
**Issue**: Using a User Access Token instead of System User token
|
|
|
|
**Fix**:
|
|
|
|
- Use a System User (Step 2) for permanent tokens
|
|
- User Access Tokens expire in 60 days
|
|
- System User tokens can be set to "Never expire"
|
|
|
|
## Security Best Practices
|
|
|
|
1. **Never commit tokens to version control**
|
|
- Add `config.json` to `.gitignore`
|
|
- Use environment variables for sensitive data
|
|
|
|
2. **Rotate tokens regularly**
|
|
- Even "permanent" tokens should be rotated periodically
|
|
- Revoke old tokens when generating new ones
|
|
|
|
3. **Use System Users for production**
|
|
- Don't use personal User Access Tokens
|
|
- System Users provide better security and permanence
|
|
|
|
4. **Limit token permissions**
|
|
- Only grant the minimum required permissions
|
|
- For WhatsHooked, you only need:
|
|
- `whatsapp_business_management`
|
|
- `whatsapp_business_messaging`
|
|
|
|
5. **Monitor token usage**
|
|
- Check token status regularly via debug_token endpoint
|
|
- Watch for unexpected API calls
|
|
|
|
## Additional Resources
|
|
|
|
- [WhatsApp Business Platform Documentation](https://developers.facebook.com/docs/whatsapp)
|
|
- [Graph API Reference](https://developers.facebook.com/docs/graph-api)
|
|
- [System Users Guide](https://www.facebook.com/business/help/503306463479099)
|
|
- [WhatsApp Business API Getting Started](https://developers.facebook.com/docs/whatsapp/cloud-api/get-started)
|
|
|
|
## Support
|
|
|
|
If you continue to have issues:
|
|
|
|
1. Verify your Meta Business Account has WhatsApp API access
|
|
2. Check that your phone number is verified in WhatsApp Manager
|
|
3. Ensure you're using Graph API v21.0 or later
|
|
4. Review the [WhatsApp Business API changelog](https://developers.facebook.com/docs/whatsapp/changelog) for updates
|