docs(whatsapp): Update WhatsApp Business API setup guide
Some checks failed
CI / Test (1.22) (push) Failing after -24m48s
CI / Test (1.23) (push) Failing after -24m45s
CI / Build (push) Successful in -27m0s
CI / Lint (push) Successful in -26m50s

* Add registration process for new phone numbers
* Clarify importance of registration for sending messages and 2FA
* Improve formatting and clarity throughout the document
This commit is contained in:
Hein
2026-01-30 17:06:04 +02:00
parent c5e121de4a
commit 98fc28fc5f

View File

@@ -5,6 +5,7 @@ This guide will help you set up WhatsApp Business API credentials for use with W
## Common Error: "Object does not exist or missing permissions" ## Common Error: "Object does not exist or missing permissions"
If you see this error: If you see this error:
``` ```
Failed to connect client account_id=test error="API returned status 400: Failed to connect client account_id=test error="API returned status 400:
{\"error\":{\"message\":\"Unsupported get request. Object with ID 'XXXXXXXXX' does not exist, {\"error\":{\"message\":\"Unsupported get request. Object with ID 'XXXXXXXXX' does not exist,
@@ -74,6 +75,7 @@ curl -X GET 'https://graph.facebook.com/v21.0/debug_token?input_token=YOUR_TOKEN
``` ```
Look for `"scopes"` in the response - it should include: Look for `"scopes"` in the response - it should include:
```json ```json
{ {
"data": { "data": {
@@ -106,6 +108,7 @@ curl -X GET 'https://graph.facebook.com/v21.0/YOUR_BUSINESS_ACCOUNT_ID/phone_num
``` ```
Response: Response:
```json ```json
{ {
"data": [ "data": [
@@ -128,13 +131,85 @@ curl -X GET 'https://graph.facebook.com/v21.0/me/businesses' \
``` ```
Or find it in WhatsApp Manager: Or find it in WhatsApp Manager:
1. Go to WhatsApp Manager 1. Go to WhatsApp Manager
2. Click on **Settings** (gear icon) 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` 3. The Business Account ID is shown in the URL: `https://business.facebook.com/wa/manage/home/?waba_id=XXXXXXXXX`
## Step 7: Test Your Credentials ## Step 7: Register Your Phone Number (Required for New Numbers)
Before configuring WhatsHooked, test your credentials: 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 ```bash
# Replace PHONE_NUMBER_ID and YOUR_TOKEN # Replace PHONE_NUMBER_ID and YOUR_TOKEN
@@ -143,6 +218,7 @@ curl -X GET 'https://graph.facebook.com/v21.0/PHONE_NUMBER_ID' \
``` ```
If successful, you'll get a response like: If successful, you'll get a response like:
```json ```json
{ {
"verified_name": "Your Business Name", "verified_name": "Your Business Name",
@@ -154,7 +230,7 @@ If successful, you'll get a response like:
If you get an error like `"error_subcode":33`, your token lacks permissions - go back to Step 4. If you get an error like `"error_subcode":33`, your token lacks permissions - go back to Step 4.
## Step 8: Configure WhatsHooked ## Step 9: Configure WhatsHooked
Update your `config.json` with the Business API configuration: Update your `config.json` with the Business API configuration:
@@ -180,7 +256,7 @@ Update your `config.json` with the Business API configuration:
### Configuration Fields ### Configuration Fields
| Field | Required | Description | | Field | Required | Description |
|-------|----------|-------------| | --------------------- | -------- | ------------------------------------------------------ |
| `id` | Yes | Unique identifier for this account in WhatsHooked | | `id` | Yes | Unique identifier for this account in WhatsHooked |
| `type` | Yes | Must be `"business-api"` | | `type` | Yes | Must be `"business-api"` |
| `phone_number` | Yes | Your WhatsApp Business phone number (E.164 format) | | `phone_number` | Yes | Your WhatsApp Business phone number (E.164 format) |
@@ -188,9 +264,9 @@ Update your `config.json` with the Business API configuration:
| `access_token` | Yes | Permanent access token (from Step 4) | | `access_token` | Yes | Permanent access token (from Step 4) |
| `business_account_id` | No | WhatsApp Business Account ID (optional, for reference) | | `business_account_id` | No | WhatsApp Business Account ID (optional, for reference) |
| `api_version` | No | Graph API version (defaults to `"v21.0"`) | | `api_version` | No | Graph API version (defaults to `"v21.0"`) |
| `verify_token` | Yes | Random string for webhook verification (see Step 8a) | | `verify_token` | Yes | Random string for webhook verification (see Step 9a) |
### Step 8a: Generate Verify Token ### Step 9a: Generate Verify Token
The verify token is used by Meta to verify your webhook endpoint. Generate a secure random string: The verify token is used by Meta to verify your webhook endpoint. Generate a secure random string:
@@ -202,33 +278,36 @@ openssl rand -hex 32
# "my_secure_verify_token_abc123xyz789" # "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 10. Add this token to your `config.json` (see above) and save it - you'll need it for webhook configuration in Step 11.
## Step 9: Start WhatsHooked ## Step 10: Start WhatsHooked
```bash ```bash
./bin/whatshook-server -config config.json ./bin/whatshook-server -config config.json
``` ```
You should see: You should see:
``` ```
INFO Business API client connected account_id=business phone=+1234567890 INFO Business API client connected account_id=business phone=+1234567890
INFO Hook manager started and subscribed to events event_types=13 INFO Hook manager started and subscribed to events event_types=13
``` ```
If you see `Failed to connect client`, check the error message and verify: If you see `Failed to connect client`, check the error message and verify:
1. Phone Number ID is correct 1. Phone Number ID is correct
2. Access token has required permissions 2. Access token has required permissions
3. Access token hasn't expired 3. Access token hasn't expired
4. Business Account has WhatsApp API access enabled 4. Business Account has WhatsApp API access enabled
## Step 10: Configure Webhook in Meta Developer Console ## Step 11: Configure Webhook in Meta Developer Console
WhatsHooked provides a webhook endpoint to receive incoming messages and status updates from WhatsApp. WhatsHooked provides a webhook endpoint to receive incoming messages and status updates from WhatsApp.
### 10.1: Webhook URL Format ### 11.1: Webhook URL Format
Your webhook URL should be: Your webhook URL should be:
``` ```
https://your-domain.com/webhooks/whatsapp/{account_id} https://your-domain.com/webhooks/whatsapp/{account_id}
``` ```
@@ -236,11 +315,12 @@ https://your-domain.com/webhooks/whatsapp/{account_id}
Where `{account_id}` matches the `id` field in your config (e.g., "business"). 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`: **Example**: If your domain is `api.example.com` and account ID is `business`:
``` ```
https://api.example.com/webhooks/whatsapp/business https://api.example.com/webhooks/whatsapp/business
``` ```
### 10.2: Configure in Meta Developer Console ### 11.2: Configure in Meta Developer Console
1. Go to [Meta Developers](https://developers.facebook.com/) 1. Go to [Meta Developers](https://developers.facebook.com/)
2. Select your app 2. Select your app
@@ -253,9 +333,10 @@ https://api.example.com/webhooks/whatsapp/business
Meta will send a GET request to verify your endpoint. If verification succeeds, you'll see a green checkmark. Meta will send a GET request to verify your endpoint. If verification succeeds, you'll see a green checkmark.
### 10.3: Subscribe to Webhook Events ### 11.3: Subscribe to Webhook Events
After verification, subscribe to these webhook fields: After verification, subscribe to these webhook fields:
-**messages** - Incoming messages and message status updates -**messages** - Incoming messages and message status updates
-**message_template_status_update** - Template approval/rejection (optional) -**message_template_status_update** - Template approval/rejection (optional)
-**account_update** - Account changes (optional) -**account_update** - Account changes (optional)
@@ -270,7 +351,7 @@ WhatsHooked supports all WhatsApp Business API webhook events and message types:
### Message Types ### Message Types
| Type | Supported | Downloads Media | Description | | Type | Supported | Downloads Media | Description |
|------|-----------|-----------------|-------------| | ------------- | --------- | --------------- | --------------------------------- |
| `text` | ✅ | N/A | Text messages | | `text` | ✅ | N/A | Text messages |
| `image` | ✅ | ✅ | Images with optional caption | | `image` | ✅ | ✅ | Images with optional caption |
| `video` | ✅ | ✅ | Videos with optional caption | | `video` | ✅ | ✅ | Videos with optional caption |
@@ -288,7 +369,7 @@ WhatsHooked supports all WhatsApp Business API webhook events and message types:
### Status Updates ### Status Updates
| Status | Event | Description | | Status | Event | Description |
|--------|-------|-------------| | ----------- | ------------------- | ------------------------------ |
| `sent` | `message.sent` | Message sent from your number | | `sent` | `message.sent` | Message sent from your number |
| `delivered` | `message.delivered` | Message delivered to recipient | | `delivered` | `message.delivered` | Message delivered to recipient |
| `read` | `message.read` | Message read by recipient | | `read` | `message.read` | Message read by recipient |
@@ -297,7 +378,7 @@ WhatsHooked supports all WhatsApp Business API webhook events and message types:
### Webhook Notification Types ### Webhook Notification Types
| Field | Description | Events Published | | Field | Description | Events Published |
|-------|-------------|------------------| | -------------------------------- | ---------------------- | ------------------------------------------ |
| `messages` | Message events | `message.received`, message status updates | | `messages` | Message events | `message.received`, message status updates |
| `message_template_status_update` | Template changes | Logged to console | | `message_template_status_update` | Template changes | Logged to console |
| `account_update` | Account config changes | Logged to console | | `account_update` | Account config changes | Logged to console |
@@ -382,9 +463,7 @@ DEBUG Sending to hook hook_id=message_hook url=https://your-webhook.com/messages
} }
``` ```
## Step 11: Configure Your Webhooks ## Step 12: Configure Your Webhooks
## Step 11: Configure Your Webhooks
WhatsHooked forwards events to your own webhook URLs. Configure them in `config.json`: WhatsHooked forwards events to your own webhook URLs. Configure them in `config.json`:
@@ -415,7 +494,7 @@ WhatsHooked forwards events to your own webhook URLs. Configure them in `config.
### Hook Configuration Fields ### Hook Configuration Fields
| Field | Required | Description | | Field | Required | Description |
|-------|----------|-------------| | ------------- | -------- | ------------------------------------------- |
| `id` | Yes | Unique identifier for this hook | | `id` | Yes | Unique identifier for this hook |
| `name` | Yes | Human-readable name | | `name` | Yes | Human-readable name |
| `url` | Yes | Your webhook URL to receive events | | `url` | Yes | Your webhook URL to receive events |
@@ -428,6 +507,7 @@ WhatsHooked forwards events to your own webhook URLs. Configure them in `config.
### Available Event Types ### Available Event Types
**Message Events:** **Message Events:**
- `message.received` - Incoming messages - `message.received` - Incoming messages
- `message.sent` - Outgoing messages - `message.sent` - Outgoing messages
- `message.delivered` - Delivery confirmations - `message.delivered` - Delivery confirmations
@@ -435,15 +515,18 @@ WhatsHooked forwards events to your own webhook URLs. Configure them in `config.
- `message.failed` - Delivery failures - `message.failed` - Delivery failures
**Connection Events:** **Connection Events:**
- `whatsapp.connected` - Account connected - `whatsapp.connected` - Account connected
- `whatsapp.disconnected` - Account disconnected - `whatsapp.disconnected` - Account disconnected
**QR Code Events** (whatsmeow only): **QR Code Events** (whatsmeow only):
- `whatsapp.qr.code` - QR code for pairing - `whatsapp.qr.code` - QR code for pairing
- `whatsapp.qr.timeout` - QR code expired - `whatsapp.qr.timeout` - QR code expired
- `whatsapp.qr.error` - QR code error - `whatsapp.qr.error` - QR code error
**Hook Events:** **Hook Events:**
- `hook.triggered` - Hook was called - `hook.triggered` - Hook was called
- `hook.success` - Hook responded successfully - `hook.success` - Hook responded successfully
- `hook.failed` - Hook call failed - `hook.failed` - Hook call failed
@@ -481,6 +564,7 @@ Add to your `config.json`:
### When Events Are Cached ### When Events Are Cached
Events are automatically cached when: Events are automatically cached when:
- No webhooks are configured for the event type - No webhooks are configured for the event type
- All webhooks are inactive (`"active": false`) - All webhooks are inactive (`"active": false`)
- No webhooks match the event in their `events` array - No webhooks match the event in their `events` array
@@ -488,33 +572,39 @@ Events are automatically cached when:
### Cache Management API ### Cache Management API
**List cached events:** **List cached events:**
```bash ```bash
curl -u username:password http://localhost:8080/api/cache curl -u username:password http://localhost:8080/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:8080/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:8080/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:8080/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:8080/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:8080/api/cache/clear?confirm=true"
@@ -553,12 +643,14 @@ curl -X DELETE -u username:password \
**Error**: "The callback URL or verify token couldn't be validated" **Error**: "The callback URL or verify token couldn't be validated"
**Causes**: **Causes**:
- `verify_token` mismatch between config.json and Meta console - `verify_token` mismatch between config.json and Meta console
- WhatsHooked server not running - WhatsHooked server not running
- Firewall blocking Meta's IP ranges - Firewall blocking Meta's IP ranges
- Wrong webhook URL format - Wrong webhook URL format
**Fix**: **Fix**:
1. Ensure server is running: `./bin/whatshook-server -config config.json` 1. Ensure server is running: `./bin/whatshook-server -config config.json`
2. Check logs for verification attempt 2. Check logs for verification attempt
3. Verify token matches exactly (case-sensitive) 3. Verify token matches exactly (case-sensitive)
@@ -567,6 +659,7 @@ curl -X DELETE -u username:password \
### Messages Not Cached ### Messages Not Cached
**Check**: **Check**:
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:8080/api/cache/stats`
@@ -574,11 +667,13 @@ curl -X DELETE -u username:password \
### No Hooks Configured Error ### No Hooks Configured Error
If events are being cached but you have hooks configured, check: If events are being cached but you have hooks configured, check:
- Hook `"active"` is `true` - Hook `"active"` is `true`
- Hook `"events"` array includes the event type (or is empty for all events) - Hook `"events"` array includes the event type (or is empty for all events)
- Hook URL is reachable and responding with 2xx status - Hook URL is reachable and responding with 2xx status
Enable debug logging to trace the issue: Enable debug logging to trace the issue:
```json ```json
{ {
"log_level": "debug" "log_level": "debug"
@@ -726,10 +821,7 @@ Here's a complete `config.json` with all Business API features:
"url": "https://your-app.com/api/whatsapp/status", "url": "https://your-app.com/api/whatsapp/status",
"method": "POST", "method": "POST",
"active": true, "active": true,
"events": [ "events": ["whatsapp.connected", "whatsapp.disconnected"],
"whatsapp.connected",
"whatsapp.disconnected"
],
"description": "Monitors connection status" "description": "Monitors connection status"
} }
], ],
@@ -761,6 +853,7 @@ Here's a complete `config.json` with all Business API features:
WhatsHooked supports three media delivery modes: WhatsHooked supports three media delivery modes:
**1. Link Mode** (default, recommended) **1. Link Mode** (default, recommended)
```json ```json
{ {
"media": { "media": {
@@ -769,11 +862,13 @@ WhatsHooked supports three media delivery modes:
} }
} }
``` ```
- Downloads media and stores locally - Downloads media and stores locally
- Webhooks receive URL: `https://your-domain.com/api/media/business/filename.jpg` - Webhooks receive URL: `https://your-domain.com/api/media/business/filename.jpg`
- Efficient for large media files - Efficient for large media files
**2. Base64 Mode** **2. Base64 Mode**
```json ```json
{ {
"media": { "media": {
@@ -781,11 +876,13 @@ WhatsHooked supports three media delivery modes:
} }
} }
``` ```
- Encodes media as base64 in webhook payload - Encodes media as base64 in webhook payload
- No separate download needed - No separate download needed
- Good for small files, increases payload size - Good for small files, increases payload size
**3. Both Mode** **3. Both Mode**
```json ```json
{ {
"media": { "media": {
@@ -793,6 +890,7 @@ WhatsHooked supports three media delivery modes:
} }
} }
``` ```
- Provides both URL and base64 - Provides both URL and base64
- Maximum flexibility, largest payloads - Maximum flexibility, largest payloads
@@ -820,6 +918,7 @@ Track all events to file and/or database:
``` ```
Logged events include: Logged events include:
- All message events - All message events
- Connection status changes - Connection status changes
- Hook success/failure - Hook success/failure
@@ -830,6 +929,7 @@ Logged events include:
Your webhooks can respond to trigger outgoing messages: Your webhooks can respond to trigger outgoing messages:
**Webhook Response Format:** **Webhook Response Format:**
```json ```json
{ {
"send_message": true, "send_message": true,
@@ -866,11 +966,13 @@ Before going live:
### Error: "Object with ID does not exist" (error_subcode: 33) ### Error: "Object with ID does not exist" (error_subcode: 33)
**Cause**: One of the following: **Cause**: One of the following:
- Incorrect Phone Number ID - Incorrect Phone Number ID
- Access token lacks permissions - Access token lacks permissions
- Access token expired - Access token expired
**Fix**: **Fix**:
1. Verify token permissions (see Step 4) 1. Verify token permissions (see Step 4)
2. Double-check Phone Number ID (see Step 5) 2. Double-check Phone Number ID (see Step 5)
3. Generate a new token if needed 3. Generate a new token if needed
@@ -892,6 +994,7 @@ Before going live:
**Issue**: Using a User Access Token instead of System User token **Issue**: Using a User Access Token instead of System User token
**Fix**: **Fix**:
- Use a System User (Step 2) for permanent tokens - Use a System User (Step 2) for permanent tokens
- User Access Tokens expire in 60 days - User Access Tokens expire in 60 days
- System User tokens can be set to "Never expire" - System User tokens can be set to "Never expire"