Integrations
Webhooks
Inbound webhook endpoints for Meta channels: Facebook Messenger, Instagram DM, and WhatsApp.
Quick facts#
| Base URL | https://helpstack.eu/api/webhooks |
| Auth (verify) | hub.verify_token must equal the configured verify token (GET handshake) |
| Auth (receive) | x-hub-signature-256: sha256=<HMAC-SHA256(rawBody, FACEBOOK_APP_SECRET)> |
| Content-Type | application/json |
| Visibility | Endpoints are public; security is the token + signature |
Webhooks are received at helpstack.eu; you register that callback URL in the Meta App dashboard. The verify token and app secret are configured by HelpStack (see the environment variables referenced below).
How the handshake works (all providers)#
Meta verifies a webhook by sending a GET with three query params. HelpStack echoes the challenge only if the verify token matches.
GET /api/webhooks/facebook
?hub.mode=subscribe
&hub.verify_token=TOKEN
&hub.challenge=CHALLENGE
- If
TOKENequals the configured verify token → respond200with the rawCHALLENGEvalue. - Otherwise → respond
403.
How signature verification works (all providers)#
Every POST carries an x-hub-signature-256 header. The signature is computed over the raw request body using HMAC-SHA256 keyed by FACEBOOK_APP_SECRET, prefixed with sha256=.
x-hub-signature-256: sha256=<hex HMAC-SHA256(rawBody, FACEBOOK_APP_SECRET)>
Node example (how to compute / verify):
import crypto from 'node:crypto';
function verifySignature(rawBody, headerValue, appSecret) {
const expected =
'sha256=' +
crypto.createHmac('sha256', appSecret).update(rawBody).digest('hex');
return headerValue === expected;
}
Gotcha — use the raw body. The signature is computed over the exact bytes Meta sent. HelpStack reads the body as raw text before parsing JSON. If you build your own verifier, do not re-serialize the parsed JSON object (key order/whitespace will differ and the signature will not match). Capture the raw body string and HMAC that.
Facebook / Messenger#
| Verify endpoint | GET /api/webhooks/facebook |
| Receive endpoint | POST /api/webhooks/facebook |
| Signature key | FACEBOOK_APP_SECRET |
| Verify token env | FACEBOOK_VERIFY_TOKEN |
Inbound payload shape. The body contains an entry[] array. Each entry has either:
entry[].messaging[]— legacy Messenger format, orentry[].changes[]— newer format.
Channel matching & processing. The handler matches a channel by facebookPageId / credentials.pageId, then:
- Creates or updates a conversation keyed by the sender PSID.
- Stores the inbound message.
- Fetches the sender's profile and downloads attachments to storage.
- Emits a real-time event to the dashboard.
Instagram#
| Endpoint | GET/POST /api/webhooks/instagram |
| Signature key | FACEBOOK_APP_SECRET |
| Verify token env | INSTAGRAM_VERIFY_TOKEN (falls back to FACEBOOK_VERIFY_TOKEN) |
Matches OAuth-managed channels by Instagram account id. Handshake and signature verification work the same as Facebook.
WhatsApp#
| Endpoint | GET/POST /api/webhooks/whatsapp |
| Signature key | FACEBOOK_APP_SECRET |
| Verify token env | WHATSAPP_VERIFY_TOKEN (falls back to FACEBOOK_VERIFY_TOKEN) |
Inbound payload shape. The body contains entry[].changes[].value with messages[] and contacts[]. The handler matches a channel by credentials.phoneNumberId and keys the conversation by the sender's phone number.
Environment variables#
| Variable | Used by | Purpose |
|---|---|---|
FACEBOOK_APP_SECRET | FB, IG, WhatsApp | HMAC-SHA256 signature key for x-hub-signature-256 |
FACEBOOK_VERIFY_TOKEN | FB (IG/WhatsApp fallback) | GET handshake verify token |
INSTAGRAM_VERIFY_TOKEN | Verify token; falls back to FACEBOOK_VERIFY_TOKEN | |
WHATSAPP_VERIFY_TOKEN | Verify token; falls back to FACEBOOK_VERIFY_TOKEN |
Register in the Meta App dashboard#
For Messenger (the same pattern applies to Instagram and WhatsApp with their endpoints):
- In the Meta App dashboard, open the product (Messenger / Instagram / WhatsApp) → Webhooks.
- Callback URL:
https://helpstack.eu/api/webhooks/facebook(Instagram:.../api/webhooks/instagram, WhatsApp:.../api/webhooks/whatsapp.) - Verify token: the value you set in
FACEBOOK_VERIFY_TOKEN(or the provider-specific token). - Click Verify and Save — Meta sends the
GEThandshake; it succeeds when the token matches. - Subscribe to fields: subscribe to the
messages/messagingfields so message events are delivered. - Ensure your app's App Secret matches
FACEBOOK_APP_SECRETso signature verification passes onPOST.
After saving, send a test message to the page/account — it should appear as a new conversation in the dashboard.