Files

130 lines
9.6 KiB
Markdown
Raw Permalink Normal View History

# Message webhooks
Use this guide to connect a message listener to your HTTP consumer. Start with direct HTTPS if you already have a webhook endpoint; the local receiver is optional. The listener observes messages surfaced in the Desktop app, rather than subscribing to WhatsApp's server history.
## Choose a delivery mode
| Mode | What runs locally | Use it for |
| --- | --- | --- |
| Direct HTTPS | Listener/relay in WhatsApp; optional brief scheduled Python checks | Your existing webhook service or Node-RED |
| Loopback HTTP | Listener/relay plus a running Python receiver | Local testing and durable SQLite capture |
## Execution and restart behavior
`webhook install` is a one-shot command. JavaScript subscribes to message collection events inside WhatsApp and queues decoded records. A resident native helper posts them directly to an HTTPS endpoint or to a loopback HTTP receiver. Direct HTTPS needs no local server and no continuously running Python process. No CDP or UI automation is used. WhatsApp's CSP blocks direct JavaScript HTTP requests to localhost, so delivery uses native WinHTTP without weakening CSP.
A WhatsApp process restart destroys injected code. For direct HTTPS, optional `--auto-restore` registers a per-user Windows scheduled task that runs a short restoration check every minute while the user is logged in. No administrator rights are requested. Keep Python, the bundle and configuration at their registered paths. The task uses current-user DPAPI to recover the token without an environment variable. The protected configuration cannot be moved to another Windows user/machine. The listener is automatically reinstalled; process memory does not survive restart. Windows reboot behavior follows the scheduled task's normal logged-in scheduling and was not live tested. WhatsApp's package and startup files are not patched.
## Start and stop
For direct HTTPS, supply a 32–128 character printable ASCII token through the named environment variable using your secret manager, then run:
If you are setting it manually, this PowerShell prompt hides the input and avoids placing the token in the command text:
```powershell
$env:WHATSAPP_INJECTOR_WEBHOOK_TOKEN = [System.Net.NetworkCredential]::new('', (Read-Host 'Webhook token' -AsSecureString)).Password
```
Install the listener:
```powershell
python whatsapp.py webhook install --endpoint https://your-endpoint.example/events --token-env WHATSAPP_INJECTOR_WEBHOOK_TOKEN --self-only --auto-restore --config listener.json
Remove-Item Env:\WHATSAPP_INJECTOR_WEBHOOK_TOKEN
```
The endpoint must authenticate `X-Webhook-Token` and accept the batch schema below. Certificate validation is enabled; credentials in URLs, query strings, fragments and redirects are rejected. Remove `--self-only` only when you intend to forward events from other chats. `webhook auto-restore --config listener.json` registers/enables restoration separately; `webhook ensure --config listener.json` performs one check. `webhook watch --config listener.json` is an optional continuously running alternative.
For a local durable test receiver:
```powershell
python whatsapp.py webhook install --port 18763 --config listener.json
python whatsapp.py webhook serve --restore-config listener.json --store events.sqlite3
```
Keep the receiver running; the installer exits. Use `--self-only` on installation when testing just your own self-chat. Otherwise it subscribes to all qualifying local message events. Installation refuses an existing configuration unless you pass `--restore` or choose a new path. The receiver restores the configured listener when WhatsApp starts and does not launch WhatsApp itself.
```powershell
python whatsapp.py webhook status
python whatsapp.py send-self --output self-send-receipt.json
```
`send-self` sends a real fixed test message and must be invoked explicitly. It does not retry uncertain sends. The receiver health endpoint is `http://127.0.0.1:18763/health`; it reports counts and restoration state without message content.
Stop and disable restoration:
```powershell
python whatsapp.py webhook stop --config listener.json
```
Then stop the receiver with Ctrl+C. Re-enable with `webhook install --restore --config listener.json`. Stopping only the injected listener without disabling a restoring configuration causes the receiver to reinstall it.
### Completely remove automatic restoration
`stop --config` disables restoration in the configuration, but keeps the scheduled task registered. To remove it entirely, first disable the exact task named in your configuration, then stop the listener and unregister that task:
```powershell
$listenerConfig = Get-Content -LiteralPath listener.json -Raw | ConvertFrom-Json
Disable-ScheduledTask -TaskName $listenerConfig.restore_task | Out-Null
python whatsapp.py webhook stop --config listener.json
Unregister-ScheduledTask -TaskName $listenerConfig.restore_task -Confirm:$false
Remove-Item -LiteralPath listener.json
```
These task commands apply only when `--auto-restore` was used. Remove the adjacent `listener.status.json` diagnostic file if present. Restart WhatsApp normally to unload the stopped helper DLL; the listener stays absent because the task is removed. No WhatsApp package files need restoring. The development workstation's test task and protected configuration were removed after validation, and WhatsApp was restarted to clear the injected listener/helper.
## Payload and integration
The loopback endpoint is `POST /whatsapp-webhook` on `127.0.0.1`; direct HTTPS uses the explicitly configured URL. Batches include `listener_id`, `seqs` and `events`. Each message event includes a sequence number, message ID, chat ID, timestamp, direction, message type, body/caption and text-length/truncation metadata. The built-in receiver persists events in SQLite; an external receiver can feed them to a summarizer. No AI provider or automatic replies are configured.
HTTP 2xx means the batch was accepted. The built-in receiver commits before acknowledgement and deduplicates message IDs. Failed HTTP delivery leaves queued records available for retry. Consumer side effects such as AI jobs should also deduplicate IDs. There is no exactly-once guarantee.
### Example batch
This is synthetic data. Message IDs are opaque strings; use `event_id` for deduplication rather than parsing its format.
```json
{
"listener_id": "91b17841-2106-4e73-97db-c38be6e9b269",
"seqs": [1],
"events": [{
"seq": 1,
"event_id": "synthetic-message-1",
"type": "message",
"message": {
"id": "synthetic-message-1",
"chat_id": "synthetic-chat",
"timestamp": 1700000000,
"from_me": true,
"message_type": "chat",
"body": "Hello",
"caption": null,
"text_truncated": false,
"body_length": 5,
"caption_length": 0
}
}]
}
```
`timestamp` is Unix seconds; sequence numbers identify queue entries within the current listener installation. Body/caption may be null. Text lengths count JavaScript UTF-16 code units. Batches contain up to 16 events and are additionally bounded by serialized size.
Your endpoint should authenticate `X-Webhook-Token`, validate the batch, deduplicate IDs, persist or enqueue accepted work, and only then return HTTP 2xx. No response-body schema is required by the relay. Use a non-2xx status when a retry is needed. TLS certificates must validate, and redirects are not followed.
For a summarizer, pass newly accepted message events to your own processing queue. This repository supplies delivery, not an AI provider, prompt, response policy or automatic message sender.
## Bounds and limitations
- This listens to the app's loaded message collection, not a server-side subscription. Messages not surfaced there can be missed.
- Reinstallation reconciles qualifying loaded models since the saved install timestamp. It is not a complete offline database catch-up. Receiver IDs deduplicate replays.
- Queues are in memory and lost when WhatsApp exits. A full queue of 1,000 events drops new records and exposes a status counter.
- Each event includes up to 12,000 body and 4,000 caption UTF-16 code units. Longer text is marked `text_truncated`; full-message ZIP export is unaffected.
- Batches contain at most 16 events within a native JSON-size bound. Unusually large escaped records may exceed that bound and stall delivery; oversized records are not silently acknowledged.
- Text rows are retried briefly while stored/decoded. Persistent decode failures appear in status counters.
- Edits, deletions and media downloads are not separate webhook features; message IDs deduplicate repeated notifications.
- Stop cancels the native timer; an idle DLL remains loaded until WhatsApp exits to keep pending callbacks safe.
- Auto-restore has a polling/startup gap. Messages during that gap are not guaranteed to be delivered.
- Only the recorded Desktop/WebView build was live tested. Address discovery accepts matching fingerprints, not every future compiler or ABI layout.
## Observed validation
On 2026-10-11, two self-messages reached the local receiver, including one after receiver-owned restoration following a WhatsApp restart, with exact plaintext equality. Two further self-messages reached the direct HTTPS Node-RED endpoint, including one after the scheduled task restored the listener in a new WhatsApp process. Node-RED message IDs and SHA-256 hashes matched the sent plaintext. The task exited with result 0 and used the protected configuration without an injected environment token. Stop, disabled restoration and reactivation were also checked. These were self-chat tests, not live incoming-message tests from another account. Incoming-event filtering is covered by synthetic fixtures. The Node-RED test flow deduplicates in memory; it is not a durable message archive or an AI summarizer.