You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/content/events.mdx
+27-1Lines changed: 27 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -86,7 +86,26 @@ These deliver a rich [message context](#the-message-context) object — the same
86
86
|`edit`|`EditPayload`| A previously sent message was edited. `{ key, newContent, editedAt, sender }`. |
87
87
|`delete`|`DeletePayload`| A message was deleted. `{ key, deletedFor: 'everyone' \| 'me', sender, timestamp }`. |
88
88
|`reaction`|`ReactionPayload`| Someone reacted to (or un-reacted from) a message. `{ key, emoji, sender, timestamp }`. `emoji` is `null` when the reaction is removed. |
89
-
|`poll-vote`|`PollVotePayload`| A poll vote was cast/changed. `{ pollKey, selectedOptions, voter, timestamp }`. |
89
+
|`poll-vote`|`PollVotePayload`| A poll vote was cast/changed. `{ pollKey, selectedOptions, options(), voter, timestamp }`. |
90
+
91
+
#### Reading a poll vote
92
+
93
+
WhatsApp does not send the option text — it sends the **SHA-256 hash** of each option the voter
94
+
picked. `selectedOptions` holds those raw hashes; `options()` looks up the original poll and turns
|`senderLid`|`string \| null`| The sender's LID (linked-device identifier), if known. Keeps the raw LID even after `senderId` is resolved to PN. |
280
299
|`senderName`|`string \| null`| The sender's WhatsApp push name. |
281
300
|`senderUsername`|`string \| null`| The sender's WhatsApp username (`@handle`), without the `@`. `null` unless WhatsApp sends one — mostly group messages from LID-only senders. |
301
+
|`isOffline`|`boolean`|`true` for a backlog message replayed after a reconnect. Guard on this so the bot does not answer old messages twice. |
302
+
|`forwardCount`|`number`| Forward hops. `>= 5` is WhatsApp's "forwarded many times". |
303
+
|`ephemeralDuration`|`number \| null`| The chat's disappearing timer in seconds. |
304
+
|`addressingMode`|`'pn' \| 'lid'`| How WhatsApp addressed the message. |
305
+
|`mentionedGroups`|`string[]`| Groups tagged via a community `@group` mention. |
306
+
|`ad`|`AdAttribution?`| Meta ad attribution, on the first message of a Click-to-WhatsApp chat only. |
307
+
|`business`|`BusinessInfo?`| Verified business name, for verified business senders only. |
282
308
|`senderDevice`|`SenderDevice`|`'android' \| 'ios' \| 'web' \| 'desktop' \| 'unknown'` — detected from the JID's device suffix. |
283
309
|`timestamp`|`number`| Message time in epoch **milliseconds**. |
description: Every field of the inbound message object zaileys passes to your handlers — where each value comes from, what it means, and how to use it.
4
4
---
5
5
6
+
import { Callout } from'nextra/components'
7
+
6
8
# Message Payload (`MessageContext`)
7
9
8
10
Every inbound message handler receives a single **`MessageContext`** object. It is decoded by zaileys from the raw Baileys `WAMessage` into a flat, predictable shape: IDs are normalized, LIDs are resolved to phone numbers where possible, and the heavy parts (group name, replied message, media bytes) are exposed as **lazy functions** so nothing is fetched until you ask for it.
@@ -56,6 +58,13 @@ So plain fields are cheap to read; the function fields do real work (network/asy
56
58
|`senderLid`|`string \| null`|`key.participantAlt` / `remoteJidAlt` ending in `@lid`| The sender's LID, when WhatsApp exposes one. `null` if not available. |
57
59
|`senderName`|`string \| null`|`message.pushName`| Display/push name. Can be `null` or spoofed — don't use for authz. |
58
60
|`senderUsername`|`string \| null`|`key.participantUsername` / `remoteJidUsername`| The sender's WhatsApp username (the `@handle`), without the `@`. `null` unless WhatsApp sends one — see the note below. |
61
+
|`isOffline`|`boolean`|`messages.upsert` type `append`|**`true` for a backlog message replayed after a reconnect.** Skip these so your bot doesn't answer hours-old messages twice. |
62
+
|`forwardCount`|`number`|`contextInfo.forwardingScore`| How many hops the message has been forwarded. `0` = not forwarded, `>= 5` = WhatsApp's "forwarded many times". |
63
+
|`ephemeralDuration`|`number \| null`|`contextInfo.expiration`| The chat's disappearing timer **in seconds**, or `null` when messages are kept. |
64
+
|`addressingMode`|`'pn' \| 'lid'`|`key.addressingMode`| Whether WhatsApp addressed this message by phone number or by LID. Useful when debugging identity resolution. |
65
+
|`mentionedGroups`|`string[]`|`contextInfo.groupMentions`| JIDs of groups tagged in the message (community `@group` mentions). |
66
+
|`ad`|`AdAttribution \| undefined`|`contextInfo.externalAdReply`| Present **only** on the first message of a chat opened from a Meta ad. |
67
+
|`business`|`BusinessInfo \| undefined`|`verifiedBizName`| Present **only** when the sender is a verified WhatsApp Business account. |
59
68
|`senderDevice`|`SenderDevice`| Parsed from the sender's device jid | Which client app sent it: `android` · `ios` · `web` · `desktop` · `unknown`. |
60
69
|`isFromMe`|`boolean`|`key.fromMe === true`|`true` if your own account sent it (echo of your sends, other-device activity). |
61
70
|`isGroup`|`boolean`|`remoteJid` is a group jid | Branch group vs DM logic. |
@@ -156,6 +165,11 @@ Present only for messages that carry media or structured content. The shape depe
156
165
|`fileName`|`string \| null`| Original name (documents). |
157
166
|`fileSize`|`number \| null`| Bytes, when WhatsApp provides it. |
158
167
|`ptt`|`boolean`|`true` for a voice note (push-to-talk audio). |
168
+
|`duration`|`number \| null`| Playback length in **seconds** (audio and video). |
awaitctx.reply(`Halo! Kamu datang dari iklan "${ctx.ad.title}". Ada yang bisa dibantu?`)
231
+
})
232
+
```
233
+
234
+
<Callouttype="warn">
235
+
This is built from WhatsApp's protocol definition but has **not been verified against a live ad click**
236
+
— we have no Click-to-WhatsApp campaign to test with. The field names are correct; report an issue if a
237
+
real ad message shapes differently.
238
+
</Callout>
239
+
240
+
## `business` — verified business senders
241
+
242
+
| Field | Type | Notes |
243
+
|---|---|---|
244
+
|`verifiedName`|`string`| The WhatsApp-verified business name. |
245
+
246
+
Present only when WhatsApp itself verified the sender. Unlike `senderName` (a push name anyone can
247
+
set to anything) this cannot be spoofed, so prefer it when you display or log who you are talking to.
248
+
249
+
---
250
+
181
251
## `chatType` values
182
252
183
253
```
@@ -227,7 +297,11 @@ A few values come from your `Client` config rather than the raw message:
227
297
-**`senderId` is a phone-number jid** (`@s.whatsapp.net`), resolved from LID when possible; `senderLid` holds the `@lid` form when present.
228
298
-**Methods are lazy & mostly async.**`roomName()`, `replied()`, `media.buffer()`, `citation.*` do real work — `await` them; they show as `[Function]` when you log the object.
229
299
-**`roomId` follows the conversation, not the direction** — safe as a reply target for both inbound and your own (`isFromMe`) messages.
230
-
-**`isSpam` is reserved** and always `false` today.
300
+
-**`isSpam` is reserved** and always `false` today. Use `forwardCount >= 5` for chain-message detection.
301
+
-**Answer only live messages.** After a reconnect WhatsApp replays everything you missed. Guard with
302
+
`if (ctx.isOffline) return` unless you deliberately want to process the backlog.
303
+
-**Mirror the disappearing timer on replies.**`ctx.reply()` does not inherit it — pass
304
+
`ctx.ephemeralDuration` to `.disappearing()` yourself, or your answer outlives the thread it belongs to.
231
305
-**`senderUsername` is usually `null` — WhatsApp sends the phone number _or_ the username, never
232
306
both.** A username is the fallback handle for a sender whose number you cannot see, so it stays
233
307
`null` for anyone whose phone number your account already knows (which is most people). It arrives
0 commit comments