Choosing the right webhook fields, and no more
Meta sends nothing until three things are true: the field is switched on, the Page is connected to your app, and the verification handshake completed. Miss any one and the symptom is identical - an endpoint that is never called.
The handshake
When you save a callback URL, Meta makes one GET with three query parameters. Echo the challenge only when the token matches:
@app.get("/hooks/meta")
def verify(request: Request):
args = request.query_params
if args.get("hub.mode") == "subscribe" and \
args.get("hub.verify_token") == VERIFY_TOKEN:
return PlainTextResponse(args.get("hub.challenge"))
raise HTTPException(403)Return the challenge as plain text, not JSON. A quoted string is not the challenge and the callback silently fails to save.
Fields worth switching on
| Field | Carries | Switch on? |
|---|---|---|
| messages | Inbound messages and their status | Yes, always |
| messaging_postbacks | Button taps and menu selections | If you use buttons |
| message_reactions | Reactions on your messages | Rarely useful |
| feed | Comments and posts on the Page | If you answer comments |
| messaging_seen | Read receipts from the customer | Noisy; only if you use it |
Switch on what you handle and nothing else. Every extra field is traffic your endpoint has to acknowledge, and an endpoint that 500s on an event type it did not expect gets its deliveries retried and then throttled - which takes the fields you do want down with it.
The Page connection people forget
Subscribing the app to a field is not the same as subscribing the Page to the app. Both are required. The second is a separate call per Page, and it is the step that gets missed when a second Page is added six months later - at which point one Page works and one does not, which is at least a more informative symptom.
Handling what arrives
Everything in webhooks done properly applies: verify the signature on raw bytes, assume duplicates, do not trust arrival order, acknowledge before working. Meta batches events, so one POST can carry several - iterate the entries rather than reading the first.
Questions people actually ask
Why is my Meta webhook not receiving anything?
Three usual causes: the field is not switched on, the Page is not connected to the app, or the verification handshake never completed. All three look identical - silence.
What is the hub.challenge request?
A one-off GET Meta makes when you save a webhook URL. Your endpoint must echo hub.challenge back when hub.verify_token matches yours, or the callback is never registered.
Njiwa
One inbox for WhatsApp, Facebook and Instagram, and an API that sends over either WhatsApp rail. 7 days free, no card.