Connecting your channels8 min read

Webhooks: why messages arrive, and why they sometimes don't

The failure where every light is green and nothing is delivered — once for WhatsApp, once for a Page — and how to prove which side it is on.

Sending and receiving are two different systems, and only one of them is proved by a token that verifies.

  • Sending is us calling Meta. A valid token with the messaging permission is enough.
  • Receiving is Meta calling us. It needs a webhook URL Meta has verified, the messages field subscribed, and the account the messages belong to subscribed to your app.

That last condition is the one this article exists for. It has two forms — one for WhatsApp, one for Instagram and Messenger — and Meta surfaces neither of them.

If you connected with a button (Connect with Meta, Connect with Facebook or Connect with Instagram), you have nothing to paste and nothing to set up in Meta's console: the webhook runs through FiguredOutAI's own Meta app, and subscribing your account is the last step of the connection. If that step fails, the card shows Setup isn't finished and a Finish setup button that tries it again. The rest of this article matters most when you connected with your own Meta app, where every piece is yours.

The WhatsApp form: an account subscribed to somebody else's app

Every signal can be green while nothing is delivered.

Your credentials verify. The Meta console shows the callback URL verified with a green tick. The messages field shows as subscribed. Your test message sends and arrives on a real phone. And every message a customer sends you vanishes — no error, no bounce, no entry in any log on either side.

The cause is that a WhatsApp Business Account is subscribed to an app, and it is not necessarily yours. An account created by Meta's "Try it out" flow is subscribed to Meta's own internal app. The callback URL and field subscription you configured belong to your app, which the account is not talking to — so they are correctly configured and never consulted.

Nothing in Meta's console shows this. It cost us a live debugging session to find, which is why our connect flow now makes the subscription call for you every time you save, and why the button connections do it as their last step.

What we do about it

When you save your own app's credentials we subscribe your app to your WhatsApp Business Account automatically. The call is additive — it does not displace another app's subscription, and repeating it on an account already subscribed succeeds rather than failing, so reconnecting is always safe.

If it does not work, the save still succeeds and the result tells you so, as a subscription error: the call was made and Meta refused it. That is almost always a token missing whatsapp_business_management. Regenerate it with all three permissions (Generate a permanent token).

Your number can still send. It is receiving that is not wired up, which is exactly the state that looks fine until a customer messages you.

So we do not leave it to the connect screen. Until the subscription succeeds or a message arrives, the channel's card in Admin → Channels shows "Messages are probably not reaching you", with the reason Meta gave. Your Today page shows a matching warning, "probably not receiving messages", in Channel health. A connection saved before we recorded subscriptions shows it too, until a message arrives or you replace its credentials. Pressing Replace credentials and filling in every value, including the WhatsApp Business Account ID, is the fix. For Instagram and Messenger, use a Page access token. A button connection is repaired with Finish setup or by connecting again.

The Page form: a Page that was never subscribed to your app

Instagram and Messenger have an exact twin of the problem above, and it is easier to hit.

A Facebook Page is subscribed to an app in its own right, separately from anything you set in the Messenger or Instagram webhook panels. You can have a verified Page access token, a callback URL the console shows as verified, and the messages field ticked — and receive nothing, because the Page itself was never subscribed to your app.

As with WhatsApp, nothing in Meta's console shows this, and as with WhatsApp we make the call for you: connecting Instagram or Messenger subscribes your Page to your app. If that call fails the connection still saves — it can send — and the result says that inbound messages may not arrive.

To check it yourself, ask Meta what the Page is subscribed to:

GET https://graph.facebook.com/v26.0/{PAGE_ID}/subscribed_apps
Authorization: Bearer {YOUR_PAGE_ACCESS_TOKEN}

An empty list, or a list without your app in it, is the whole problem. Reconnect from Admin → Channels, which re-runs the subscription.

One Page, two channels, two subscriptions to think about. Instagram DMs and Messenger messages both arrive against the same Page, but Meta addresses them differently — an Instagram webhook names the Instagram professional account, a Messenger webhook names the Page — so having one of them working tells you very little about the other. If Messenger arrives and Instagram does not, check that the Instagram professional account is still linked to the Page in Meta Business Suite → Linked accounts; that link is where we read the account id from, and it is what an Instagram webhook is addressed to.

Why there is no test-send button for Instagram or Messenger

Because there is nothing to send one to.

Instagram and Messenger only allow a message to someone who has written to you first. A test send would have no recipient and would be refused every time — a button whose only possible outcome is teaching you that a working connection is broken.

The proof those connections receive is the message you send your own Page or profile from a personal account. The proof they send is the bot's reply to it. Do both before you tell a customer about the channel — the same advice as for WhatsApp, and for the same reason.

Proving which side is broken

Do these in order; each one rules out a layer.

  1. WhatsApp only: press Send test message on the channel card in Admin → Channels. If this fails, the problem is your token or permissions, not webhooks at all. Instagram and Messenger have no such button, so start at step 2.

  2. Message your business number from a personal phone and watch the Inbox. If it appears and the bot's reply to it is not marked Not delivered, everything works. A reply marked Not delivered means receiving works and sending does not: the reason is written under it, with a link to what to do.

  3. If it does not appear, and you connected with your own Meta app, ask Meta which apps your account is subscribed to (with a button connection, reconnect from Admin → Channels instead, which repeats the subscription):

    GET https://graph.facebook.com/v26.0/{WHATSAPP_BUSINESS_ACCOUNT_ID}/subscribed_apps
    Authorization: Bearer {YOUR_PERMANENT_TOKEN}
    

    The reply lists the subscribed apps by id and name. If your app is not in that list, that is the whole problem — reconnect from Admin → Channels, which re-runs the subscription, and check again.

The rest of the webhook setup

You do not paste the callback URL or verify token from this article — the Webhook card on Admin → Channels shows the exact values (Callback URL and Verify token), and they are the ones to copy. You only need them with your own Meta app. The same two values work for all three channels; what differs is where in Meta's console you paste them (WhatsApp → Configuration, Messenger → Webhooks, Instagram → Webhooks) and that each one needs the messages field subscribed separately. Two things about them are worth understanding:

  • Meta verifies the URL by calling it once with a challenge value (opens in a new tab) it expects echoed back. That handshake either passes immediately or does not; a URL that will not verify is unreachable from the public internet, not misconfigured.
  • Only the messages field matters for lead intake. Subscribing to more fields does no harm and no good.

Every inbound message is signature-checked

Meta signs each webhook request with the secret of the app that sent it. We recompute the signature over the exact bytes that arrived and reject anything that does not match. For a button connection that app is ours, so there is nothing for you to get wrong. With your own Meta app it is your app secret — the entire reason it is one of the values you paste, and why a wrong one produces a number that sends perfectly and receives nothing.

Then we route the message to your workspace by the id inside it — the phone number ID for WhatsApp, the Page id for Messenger, the Instagram professional account id for Instagram — which is why those values have to be yours and correct. It is also why the Instagram card has no account field: we read the linked account off your Page during verification rather than ask you for the one value that is easiest to get wrong and impossible to notice being wrong.