Skip to content

Webhook Fan-Out

Also called: Webhook relay · Event fan-out · Webhook broadcasting · Pub/sub for webhooks

Distributing one incoming WhatsApp webhook stream to several internal consumers — inbox, CRM, chatbot, analytics — through a broker or relay you control.

Reviewed

What is webhook fan-out?

Webhook fan-out is the layer that copies one incoming WhatsApp event stream to every internal system that needs it. Meta delivers your WhatsApp events to one callback URL per app, or to an alternate URL per WhatsApp Business Account or phone number if you use overrides. Most businesses, though, have several systems that need the same events: the shared team inbox shows conversations, the chatbot answers them, the CRM integration logs them against the customer, the analytics warehouse counts them and the campaign tool watches delivery statuses. Fan-out takes the single stream from Meta and gives each of those consumers its own copy.

The usual shape is a standard event-driven architecture: a thin webhook endpoint followed by a message broker. The endpoint verifies the signature, stores the payload and returns 200 — the webhook acknowledgement Meta needs. A relay then splits each POST into individual events and publishes them to topics by type — inbound messages, statuses, template updates, account updates. Each consumer has its own subscription and message queue, so it reads at its own pace, retries its own failures and can be added or removed without touching Meta's configuration. A topic with one queue per consumer, a log with consumer groups, or a fan-out exchange all implement the same idea.

Fan-out is not a work queue. In a work queue (competing consumers), each event goes to exactly one worker; in fan-out, every subscriber receives every event it subscribed to. It also differs from webhook override, which splits traffic at Meta by phone number or WABA — and only for fields such as messages, since template and account webhooks always go to the app's default URL. Override decides where Meta sends; fan-out decides who inside your stack receives.

Key takeaways

  • Webhook fan-out takes the single WhatsApp event stream Meta sends you and gives each internal system its own copy.
  • Meta calls one callback URL per app; overrides per WABA or phone number apply only to fields such as messages.
  • Ingest once, split each payload into events, publish them by type and give every consumer its own queue.
  • Fan-out is not a work queue: every subscriber receives every event it subscribed to, not one worker per event.
  • Prefer one app with internal fan-out over several apps on one WABA, because Meta sends retries to every subscribed app.

See InfiQ pricing

Interactive stop

One webhook in, a copy for every consumer

11 / 11

Only agents with the required skill are eligible; the least busy of them wins.

Incoming · 0 left

  1. All 11 conversations have been routed.

Conversation 11 of 11 · Skills-based

msg C3 · button reply(needs analytics)goes toAnalytics

Skills: needs analytics, and only Analytics has it.

  • Shared inbox

    3 of 3 open

    Full
    • inbox
    1. msg A1 · textneeds inbox
    2. status B7 · deliveredneeds inbox
    3. msg C3 · button replyneeds inbox
  • Chatbot

    2 of 3 open

    • bot
    1. msg A1 · textneeds bot
    2. msg C3 · button replyneeds bot
  • CRM sync

    2 of 2 open

    Full
    • crm
    1. msg A1 · textneeds crm
    2. status B7 · deliveredneeds crm
  • Analytics

    3 of 4 open

    • analytics
    1. msg A1 · textneeds analytics
    2. status B7 · deliveredneeds analytics
    3. msg C3 · button replyneeds analytics

Waiting · 1

  1. msg C3 · button replyneeds crm
Same 11 conversations, each strategy
StrategyRoutedWaitingSkill mismatches
Skills-based1010
Round-robin1105
Each chip is one copy the relay made: a message goes to all four consumers, a status to the three that subscribe to statuses. Skills routing keeps each copy on its consumer; switch to round-robin to see why a work queue is not fan-out.

Conversation 11 of 11, msg C3 · button reply: Skills: needs analytics, and only Analytics has it.

Why does webhook fan-out matter?

Without fan-out, teams either chain consumers inside the webhook handler — so the slowest system sets the response time and one outage blocks everyone — or subscribe several apps to the same WABA, where Meta notes that retries go to every subscribed app, so one app's failures create duplicates for the others. A broker in the middle isolates consumers from each other and from Meta: the CRM can be down for an hour while the inbox and chatbot carry on, and the CRM simply drains its own backlog when it returns.

How does webhook fan-out work?

  1. Ingest once

    One endpoint receives every POST, verifies X-Hub-Signature-256, writes the raw payload durably and returns 200. Nothing downstream runs inside the request.

  2. Split into events

    The relay breaks each payload into one event per message, status or change, adding an event key (such as wamid plus status), the field, the phone_number_id and a received-at time.

  3. Publish by event type

    Send each event to a topic such as whatsapp.message.inbound, whatsapp.status, whatsapp.template or whatsapp.account. Use the customer's ID as the partition or ordering key so one person's events stay in sequence.

  4. Give each consumer its own subscription

    The inbox subscribes to inbound messages and statuses, the chatbot to inbound messages only, analytics to everything. Each subscription is an independent queue with its own retries and dead-letter queue.

  5. Make every consumer idempotent

    Brokers deliver at least once and Meta retries, so each consumer applies webhook deduplication on the event key before its side effects run.

  6. Watch lag per consumer

    Alert on each subscription's backlog and oldest-message age. A growing lag on one consumer is a local problem, not an outage — as long as you notice it.

Example: A Chennai retailer's CRM outage

A Chennai electronics retailer fans its WhatsApp events out to a shared inbox, a chatbot, a CRM sync and a data warehouse. One afternoon the CRM vendor has a three-hour outage. The CRM subscription's queue grows to about 90,000 events, but the inbox keeps showing new chats, the chatbot keeps answering order questions and Meta keeps receiving instant 200s. When the CRM returns, its consumer drains the backlog in around 20 minutes, deduplicating anything it had half-processed before the outage (figures illustrative).

— A Chennai retailer's CRM outage

Webhook fan-out in code

import crypto from "node:crypto";
const sha256 = (s) => crypto.createHash("sha256").update(s).digest("hex");
const TOPIC_BY_KIND = {
message: "whatsapp.message.inbound",
status: "whatsapp.status",
};
export async function relay(payload) {
for (const entry of payload.entry ?? []) {
for (const change of entry.changes ?? []) {
const v = change.value ?? {};
const events = change.field === "messages"
? [
...(v.messages ?? []).map((m) => ({ kind: "message", key: "msg:" + m.id, user: m.from_user_id ?? m.from, data: m })),
...(v.statuses ?? []).map((s) => ({ kind: "status", key: "st:" + s.id + ":" + s.status, user: s.recipient_user_id ?? s.recipient_id, data: s })),
]
: [{ kind: change.field, key: change.field + ":" + entry.id + ":" + sha256(JSON.stringify(v)), user: entry.id, data: v }];
for (const e of events) {
const topic = TOPIC_BY_KIND[e.kind] ?? "whatsapp." + e.kind;
await broker.publish(topic, {
orderingKey: e.user, // keeps one customer's events in sequence
eventKey: e.key, // consumers deduplicate on this
phoneNumberId: v.metadata?.phone_number_id,
data: e.data,
});
}
}
}
}

Split once, publish by type, and let every consumer subscribe to the topics it needs.

Common mistakes with webhook fan-out

  • Forwarding synchronously from the handler

    POSTing each webhook on to four internal URLs before answering Meta makes the slowest consumer decide your response time. Publish to a broker and answer immediately.

  • Using a work queue and calling it fan-out

    With competing consumers, each event reaches only one of them, so the CRM silently misses what the inbox processed. Give every consumer its own subscription.

  • Losing per-customer order

    Publishing with no ordering key spreads one customer's messages across partitions, and a reply can be processed before the question. Partition by customer.

  • Multiplying personal data

    Every copy of a message is another place customer data lives under the DPDP Act. Strip message bodies for consumers that only count, and set retention per subscription.

Webhook fan-out: key facts and limits

Meta delivers to
One app callback URL (overrides per WABA or number)
Never overridable
Template and account webhook fields
Payload size
Up to 3 MB, up to 1,000 updates
Meta retry window
Up to 7 days
Consumer delivery
At least once — deduplicate on event key
Ordering key
Customer ID (BSUID or wa_id)

Best practices for webhook fan-out

  • Keep the raw payload archive separate from the fan-out, so you can replay a consumer from scratch.
  • Version the event envelope you publish; consumers should not parse Meta's raw shape directly.
  • Prefer one app with internal fan-out over several apps subscribed to the same WABA.
  • Give the chatbot the tightest retry budget — a reply that arrives an hour late is worse than none.

Webhook Fan-Out FAQs

Can Meta send the same webhook to several URLs?+
Not from one app. Each app has one callback URL, with overrides per WABA or phone number for some fields. Several apps subscribed to one WABA each receive events, but retries then go to all of them, which is why internal fan-out is usually cleaner.
How is fan-out different from webhook override?+
Override chooses which endpoint Meta calls for a given number or WABA. Fan-out copies events inside your own systems after they arrive.
Should I subscribe several Meta apps to the same WABA instead of fanning out?+
Usually not. Each subscribed app does receive the events, but Meta sends retries to every subscribed app, so one app's failures create duplicates for the others, and you manage several apps, secrets and endpoints instead of one.
Do I need a broker for two consumers?+
Not necessarily — a durable table that two workers read independently works. The principle is the same: each consumer tracks its own progress, and none of them runs inside Meta's request.

Talk to InfiQ

From definition to your first message

InfiQ is an official Meta Business Partner. Start a 7-day free trial — no card needed — and see this running on your own number.