docs(whatsapp): ✨ Update WhatsApp Business API setup guide
* 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:
@@ -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"
|
||||
|
||||
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,
|
||||
@@ -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:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
@@ -106,6 +108,7 @@ curl -X GET 'https://graph.facebook.com/v21.0/YOUR_BUSINESS_ACCOUNT_ID/phone_num
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
@@ -128,13 +131,85 @@ curl -X GET 'https://graph.facebook.com/v21.0/me/businesses' \
|
||||
```
|
||||
|
||||
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: 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
|
||||
# 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:
|
||||
|
||||
```json
|
||||
{
|
||||
"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.
|
||||
|
||||
## Step 8: Configure WhatsHooked
|
||||
## Step 9: Configure WhatsHooked
|
||||
|
||||
Update your `config.json` with the Business API configuration:
|
||||
|
||||
@@ -180,7 +256,7 @@ Update your `config.json` with the Business API configuration:
|
||||
### 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) |
|
||||
@@ -188,9 +264,9 @@ Update your `config.json` with the Business API configuration:
|
||||
| `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 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:
|
||||
|
||||
@@ -202,33 +278,36 @@ openssl rand -hex 32
|
||||
# "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
|
||||
./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 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.
|
||||
|
||||
### 10.1: Webhook URL Format
|
||||
### 11.1: Webhook URL Format
|
||||
|
||||
Your webhook URL should be:
|
||||
|
||||
```
|
||||
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").
|
||||
|
||||
**Example**: If your domain is `api.example.com` and account ID is `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/)
|
||||
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.
|
||||
|
||||
### 10.3: Subscribe to Webhook Events
|
||||
### 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)
|
||||
@@ -270,7 +351,7 @@ 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 |
|
||||
@@ -288,7 +369,7 @@ WhatsHooked supports all WhatsApp Business API webhook events and message types:
|
||||
### 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 |
|
||||
@@ -297,7 +378,7 @@ WhatsHooked supports all WhatsApp Business API webhook events and message types:
|
||||
### 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 |
|
||||
@@ -382,9 +463,7 @@ DEBUG Sending to hook hook_id=message_hook url=https://your-webhook.com/messages
|
||||
}
|
||||
```
|
||||
|
||||
## Step 11: Configure Your Webhooks
|
||||
|
||||
## Step 11: Configure Your Webhooks
|
||||
## Step 12: Configure Your Webhooks
|
||||
|
||||
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
|
||||
|
||||
| Field | Required | Description |
|
||||
|-------|----------|-------------|
|
||||
| ------------- | -------- | ------------------------------------------- |
|
||||
| `id` | Yes | Unique identifier for this hook |
|
||||
| `name` | Yes | Human-readable name |
|
||||
| `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
|
||||
|
||||
**Message Events:**
|
||||
|
||||
- `message.received` - Incoming messages
|
||||
- `message.sent` - Outgoing messages
|
||||
- `message.delivered` - Delivery confirmations
|
||||
@@ -435,15 +515,18 @@ WhatsHooked forwards events to your own webhook URLs. Configure them in `config.
|
||||
- `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
|
||||
@@ -481,6 +564,7 @@ Add to your `config.json`:
|
||||
### 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
|
||||
@@ -488,33 +572,39 @@ Events are automatically cached when:
|
||||
### 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"
|
||||
@@ -553,12 +643,14 @@ curl -X DELETE -u username:password \
|
||||
**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)
|
||||
@@ -567,6 +659,7 @@ curl -X DELETE -u username:password \
|
||||
### 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`
|
||||
@@ -574,11 +667,13 @@ curl -X DELETE -u username:password \
|
||||
### 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"
|
||||
@@ -726,10 +821,7 @@ Here's a complete `config.json` with all Business API features:
|
||||
"url": "https://your-app.com/api/whatsapp/status",
|
||||
"method": "POST",
|
||||
"active": true,
|
||||
"events": [
|
||||
"whatsapp.connected",
|
||||
"whatsapp.disconnected"
|
||||
],
|
||||
"events": ["whatsapp.connected", "whatsapp.disconnected"],
|
||||
"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:
|
||||
|
||||
**1. Link Mode** (default, recommended)
|
||||
|
||||
```json
|
||||
{
|
||||
"media": {
|
||||
@@ -769,11 +862,13 @@ WhatsHooked supports three media delivery modes:
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- 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": {
|
||||
@@ -781,11 +876,13 @@ WhatsHooked supports three media delivery modes:
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- Encodes media as base64 in webhook payload
|
||||
- No separate download needed
|
||||
- Good for small files, increases payload size
|
||||
|
||||
**3. Both Mode**
|
||||
|
||||
```json
|
||||
{
|
||||
"media": {
|
||||
@@ -793,6 +890,7 @@ WhatsHooked supports three media delivery modes:
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- Provides both URL and base64
|
||||
- Maximum flexibility, largest payloads
|
||||
|
||||
@@ -820,6 +918,7 @@ Track all events to file and/or database:
|
||||
```
|
||||
|
||||
Logged events include:
|
||||
|
||||
- All message events
|
||||
- Connection status changes
|
||||
- Hook success/failure
|
||||
@@ -830,6 +929,7 @@ Logged events include:
|
||||
Your webhooks can respond to trigger outgoing messages:
|
||||
|
||||
**Webhook Response Format:**
|
||||
|
||||
```json
|
||||
{
|
||||
"send_message": true,
|
||||
@@ -866,11 +966,13 @@ Before going live:
|
||||
### 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
|
||||
@@ -892,6 +994,7 @@ Before going live:
|
||||
**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"
|
||||
|
||||
Reference in New Issue
Block a user