Skip to main content
WhatsApp Alternative delivers group messages through the same message.inbound webhook as one-to-one messages. There is no separate event type to subscribe to — a group message simply carries extra group fields on data, so your existing handler keeps working and you branch on isGroup.

How a group message arrives

The conversation is keyed on the group, while from is the participant who actually sent the message.
message.inbound (group)
{
  "id": "evt_1736850000000_abc123",
  "type": "message.inbound",
  "timestamp": 1736850000000,
  "senderId": "sender_12345",
  "projectId": "proj_abc",
  "data": {
    "messageId": "jx77...",
    "channel": "whatsapp_alt",
    "from": "+14155551234",
    "to": "+13125551212",
    "messageType": "text",
    "text": "Anyone free at 3pm?",
    "status": "delivered",
    "isGroup": true,
    "groupId": "120363000000000000@g.us",
    "groupAuthor": "+14155551234",
    "groupName": "Weekend Trip",
    "providerTimestamp": 1736849999000
  }
}

Group fields on data

FieldPresentDescription
isGroupgroups onlytrue for a group message. Absent/falsy for a one-to-one message.
groupIdgroups onlyThe group’s JID (<id>@g.us). This is the conversation key.
groupAuthorgroups onlyThe participant who sent the message, in E.164. Same value as from.
groupNamewhen knownThe group’s display name (subject).
fromalwaysThe message sender — the participant in a group, the contact in a 1:1.
toalwaysYour linked number.
providerTimestampwhen knownWhen WhatsApp originally received the message (Unix ms).

Telling a group message from a one-to-one

Branch on isGroup:
app.post("/webhooks/zavu", (req, res) => {
  const { type, data } = req.body;
  if (type === "message.inbound" && data.channel === "whatsapp_alt") {
    if (data.isGroup) {
      // Group message: attribute to the participant, thread on the group.
      console.log(`[${data.groupName ?? data.groupId}] ${data.groupAuthor}: ${data.text}`);
    } else {
      // One-to-one message.
      console.log(`${data.from}: ${data.text}`);
    }
  }
  res.sendStatus(200);
});
@app.post("/webhooks/zavu")
async def zavu_webhook(payload: dict):
    if payload["type"] == "message.inbound" and payload["data"].get("channel") == "whatsapp_alt":
        data = payload["data"]
        if data.get("isGroup"):
            label = data.get("groupName") or data["groupId"]
            print(f"[{label}] {data['groupAuthor']}: {data.get('text')}")
        else:
            print(f"{data['from']}: {data.get('text')}")
    return {"ok": True}
Group messages count toward inbound only — like every channel, inbound messages are not billed against your plan quota. The group thread lives alongside your 1:1 conversations, keyed on groupId.

What Zavu ignores

To keep the inbox clean, some non-conversational threads are never delivered as inbound (message.inbound) events:
  • Status updates / stories (status@broadcast) — not an inbound message. They are delivered separately as opt-in message.status events, never in the inbox.
  • Newsletters / channels — not a two-way conversation.
  • Self-chat (messages to your own number).
Group membership-change events (joins, removals, subject changes) are not emitted today. Contact Zavu if you need them.

Next steps

Sending & Receiving

The base send/receive flow on the whatsapp_alt channel.

Receiving Messages

Configure and verify your sender webhook.