zapo surfaces both. Understanding the distinction matters as soon as you touch groups, because WhatsApp is migrating group identities to LID for privacy.
PN vs LID
A LID (“linked identity”) is a stable, opaque identifier that represents a user without exposing their phone number. WhatsApp increasingly uses LIDs in groups and communities so members can interact without sharing their number.
Addressing mode
When sending into a group, the message is addressed to participants either by PN or by LID — theaddressingMode: 'pn' | 'lid'. zapo resolves this automatically: it scans the group participants and uses lid if any participant is a LID, otherwise pn. The server can confirm or override the choice, which is reflected back in the publish result:
What you get on an incoming message
WaIncomingMessageEvent.key carries both identifiers when the server provides them. In groups the sender is key.participant; in 1:1 chats it is key.remoteJid. Each gets a parallel *Alt field with the alternate addressing.
key.participant as a @lid and key.participantAlt as the phone JID (if the server shares it).
Replying — which JID to use
client.message.send accepts either a PN or a LID JID and normalizes the target for you, so you rarely have to convert:
Mapping a phone number to its LID
To resolve LIDs for a set of phone numbers, use the profile coordinator:lidJid is null when the server has no LID mapping for that number.
LID changes
A user’s LID can change (server-side, for privacy). When it does, you receive amex_notification of kind lid_change:
zapo handles the underlying Signal-session bookkeeping; this event is for your own caches/bookkeeping.
Where PN ↔ LID linkage is stored
Several app-state schemas track the relationship and sync it across your devices (see chat mutations):Signal sessions
Signal sessions are keyed by the canonical JID (PN or LID) plus device id.zapo canonicalizes hosted server variants (hosted.lid → lid, hosted → s.whatsapp.net) before lookups, and maintains sessions for both addressing forms. If you ever need to force a fresh session sync for a peer, use:
