Why does Chatwoot return 401 Unauthorized to WhatsApp webhooks?

In short: since version 4.14, Chatwoot checks the X-Hub-Signature-256 of WhatsApp Cloud deliveries against the app_secret of the inbox they match. A 401 means one of two things: no inbox matches the number, or the inbox's app_secret is not the secret that signed the delivery. You fix both on the inbox, through Chatwoot's API.

ZapClaw connects your number to the official WhatsApp API, signs every delivery to Chatwoot and shows the inbox command for each number with the number's details filled in.

Start for free

The two causes

WHATSAPP_APP_SECRET in the environment does not help. Chatwoot reads that value from its installation config, which db:chatwoot_prepare creates empty on a standard install, so the environment value is never used. You can remove the variable.

How to fix it

  1. Open the failed delivery in ZapClaw's Logs: it shows the status and the raw response Chatwoot returned. A 401 with Empty response body comes from this signature check.
  2. Fix the inbox through Chatwoot's API. A number with no inbox yet gets one from the command the ZapClaw dashboard shows for it. For an existing inbox, send the whole provider_config, app_secret and source: manual_setup_v2 included: Chatwoot replaces the object instead of merging it, and a partial one is refused with Provider config Invalid Credentials. If the phone number is wrong too, add phone_number to channel in the same call.

    curl -X PATCH "https://chatwoot.your-domain.com/api/v1/accounts/<ACCOUNT_ID>/inboxes/<INBOX_ID>" \
      -H "api_access_token: <CHATWOOT_ACCESS_TOKEN>" \
      -H "Content-Type: application/json" \
      -d '{
        "channel": {
          "provider_config": {
            "api_key": "zc_live_xxx",
            "phone_number_id": "<PHONE_NUMBER_ID>",
            "business_account_id": "<WABA_ID>",
            "source": "manual_setup_v2",
            "app_secret": "<CHATWOOT_SIGNING_SECRET>"
          }
        }
      }'

    app_secret is the Signing secret of the Chatwoot section in ZapClaw. The inbox ID is the number after /settings/inboxes/ when you open the inbox's settings. The Rails console works too: see the guide.

  3. Press Send test event in ZapClaw's Chatwoot section. A success means Chatwoot found the inbox and accepted the signature. The test goes to your first connected number, so that number needs an inbox too. Then resend the failed deliveries from Logs.

Straight from Meta, without ZapClaw

A 404, Invalid OAuth access token and replies that never leave Chatwoot have their own fixes in the Chatwoot troubleshooting.

Self-hosted Chatwoot on the official WhatsApp API

ZapClaw connects your number through Coexistence, so it keeps working in the WhatsApp Business app, and Chatwoot's own WhatsApp Cloud channel talks to ZapClaw instead of Meta. You need no Meta app of your own and no App Review.

The dashboard shows each number's inbox command with the number's details filled in, and Logs keeps every delivery with Chatwoot's answer, ready to resend.

Start for free Why run Chatwoot on ZapClaw