From 98fc28fc5ff46e73c9319b7dc2fecd955c2a19ab Mon Sep 17 00:00:00 2001 From: Hein Date: Fri, 30 Jan 2026 17:06:04 +0200 Subject: [PATCH] =?UTF-8?q?docs(whatsapp):=20=E2=9C=A8=20Update=20WhatsApp?= =?UTF-8?q?=20Business=20API=20setup=20guide?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add registration process for new phone numbers * Clarify importance of registration for sending messages and 2FA * Improve formatting and clarity throughout the document --- WHATSAPP_BUSINESS.md | 235 +++++++++++++++++++++++++++++++------------ 1 file changed, 169 insertions(+), 66 deletions(-) diff --git a/WHATSAPP_BUSINESS.md b/WHATSAPP_BUSINESS.md index 0c4a10f..0f35b7e 100644 --- a/WHATSAPP_BUSINESS.md +++ b/WHATSAPP_BUSINESS.md @@ -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,13 +108,14 @@ curl -X GET 'https://graph.facebook.com/v21.0/YOUR_BUSINESS_ACCOUNT_ID/phone_num ``` Response: + ```json { "data": [ { "verified_name": "Your Business Name", "display_phone_number": "+1 234-567-8900", - "id": "123456789012345", // <- This is your Phone Number ID + "id": "123456789012345", // <- This is your Phone Number ID "quality_rating": "GREEN" } ] @@ -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: @@ -179,18 +255,18 @@ 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) | -| `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 8a) | +| 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 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) @@ -269,41 +350,41 @@ 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 | +| 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 | +| 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 | +| `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 | +| 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 @@ -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`: @@ -414,20 +493,21 @@ 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 | -| `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 | +| 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 @@ -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"