Channels · WhatsApp · ~10 min

Connect a WhatsApp Business number

Use Meta's WhatsApp Cloud API to send and receive on a Business phone number. Every inbound message is verified by an HMAC-SHA256 signature over the raw body, parsed into an interaction withchannel = "whatsapp", and dispatched through the same Brain pipeline as your /process calls.

1. Set up a Meta Business app

In Meta for Developers:

  1. Create a Business app (or use an existing one) and add the WhatsApp product.
  2. In WhatsApp → API Setup, copy thePhone number ID for the number you want Humane to listen on.
  3. Generate a System User access token withwhatsapp_business_messaging andwhatsapp_business_management scopes (strongly preferred — the temporary 60-day token in the dashboard will silently die on you).
  4. In App Dashboard → Settings → Basic, clickShow next to App Secret and copy it. Humane uses it to verify theX-Hub-Signature-256 header on every inbound delivery.

2. Create the channel in Humane

From the dashboard: Channels → Connect WhatsApp, paste the three credentials, give it a label, click Create. Or via SDK:

python
from humane_ai import HumaneClient

client = HumaneClient(api_key="hx_...")

channel = client.channels.create_whatsapp(
    phone_number_id="108XXXXXXXXX",        # Meta App Dashboard → WhatsApp → API Setup
    access_token="EAAG...",                # System User token (recommended)
    app_secret="abc123...",                # App Dashboard → Settings → Basic
    label="Care line",
    auto_reply=True,
)

print(channel.id)                          # mc_3pQ7...
print(channel.webhook_url_hint)            # /api/ingress/whatsapp/mc_3pQ7...
print(channel.verify_token)                # shown ONCE — paste into Meta Configuration
Save the verify_token now
The response includes verify_token — shown once. You'll paste it into Meta's Configuration page in the next step. We only store a hashed copy. Lost it? Rotate viaclient.channels.update(id, ...) and re-register the webhook.

3. Point Meta at the ingress endpoint

In App Dashboard → WhatsApp → Configuration:

  1. Callback URL: https://your-host.com/api/ingress/whatsapp/{integration_id} — use the id from the channel you just created.
  2. Verify Token: paste the verify_tokenfrom step 2.
  3. Click Verify and Save. Meta will fire aGET with a hub.challengeand the token; Humane checks the token and echoes the challenge. If you see "✓ Webhook verified" — you're good.
  4. Under Webhook fields, subscribe to messages. (Other fields are fine but not required for ingress.)
The GET handshake is the same endpoint
GET /api/ingress/whatsapp/{integration_id}handles only Meta's verification handshake — it returns thehub.challenge string on token match, 403 otherwise. Real messages arrive as POST requests on the same path.

4. How requests are authenticated

Every POST to /api/ingress/whatsapp/{integration_id}carries an X-Hub-Signature-256: sha256=<hex>header. Humane recomputesHMAC-SHA256(app_secret, raw_body) and compares it constant-time. Match → handled. No match, missing header, or tampered body → 401. Because the signature covers the raw body, a stripped or modified payload cannot pass.

Typing, status callbacks, edits — all 200 ignored
Meta sends webhook fields for delivery receipts, read receipts, message status, and template events. Anything that isn't a user-authored message returns 200 {status: "ignored"}so Meta doesn't retry — but the Brain pipeline only fires on the real ones.

5. (Optional) See the raw handshake

Meta's verification GET looks like this — useful when debugging a stuck "Verify and Save":

bash
# What Meta sends:
GET /api/ingress/whatsapp/<integration_id>
  ?hub.mode=subscribe
  &hub.verify_token=<your_verify_token>
  &hub.challenge=<random_string>

# What Humane returns (token match):
200 OK
<random_string>

# What Humane returns (token mismatch):
403 Forbidden

6. Verification

Confirm end-to-end:

  1. From a personal phone, send a WhatsApp message to your Business number.
  2. If auto_reply is enabled, Humane replies within a few seconds with a Brain-shaped LLM response.
  3. In the dashboard, Users shows a new end-user withchannel = "whatsapp"; the interaction has mood, energy, safety state, and any memory hits.
Verify and Save fails?
Almost always one of: (a) the callback URL is wrong or unreachable from the public internet, (b) the verify token doesn't match (whitespace, a stray newline), (c) the integration_id in the path doesn't match the channel you created. Tail your server logs while you click "Verify and Save" — the GET will appear in real time.