Repository navigation
Expose SubscribePresence (contact online) + decrypt edited messages (new text arrives encrypted) #146
Description
Summary
Two whatsmeow capabilities are effectively present in the codebase but not surfaced to API consumers, so CRMs built on top of Evolution Go can't reach feature parity with the Baileys-based Evolution API for them:
- Contact presence ("online" / last-seen) — there is no way to
SubscribePresence, soevents.Presencenever fires. - Edited messages arrive encrypted and undecrypted — the new text is delivered as a raw
secretEncryptedMessageenvelope, so consumers can't read what the message was edited to.
Both are small, additive changes. Happy to open a PR for either/both if the approach looks right to you.
1. Expose SubscribePresence → enables contact "online"/last-seen
whatsmeow only emits events.Presence for JIDs you've explicitly subscribed to via Client.SubscribePresence(ctx, jid). A grep of the repo shows SubscribePresence is never called, and there's no route to trigger it. The rest of the plumbing already exists:
- the
Presenceevent dispatcher → webhook ({event:"Presence", state, data:{From, Unavailable, LastSeen}}) is already implemented inpkg/whatsmeow/service/whatsmeow.go; - the
PRESENCEsubscription filter already exists.
Request: a new instance-scoped route, e.g. POST /user/presence/subscribe with body { "number": "5521..." } (nice-to-have: also accept { "numbers": [...] } for batching the top N conversations of an inbox):
- normalize to a canonical JID (same helper used by
/message/presence); - send our own presence first —
client.SendPresence(types.PresenceAvailable)— since whatsmeow only receives presence updates after you've broadcast your own (same rationale already noted inpkg/message/service/message_service.goaround theChatPresencehandler); - call
client.SubscribePresence(ctx, jid)and return{data:{subscribed:true}}.
With the subscribe in place, the existing Presence → webhook path just starts flowing. No other change needed.
2. Decrypt edited messages (currently the new text is unreadable)
When a contact edits a text message, the event arrives with Info.Edit == "1" and the new text encrypted inside Message.secretEncryptedMessage (secretEncType: 2), with the original message key under secretEncryptedMessage.targetMessageKey. Because this is never decrypted, downstream consumers receive an opaque envelope instead of the edited text.
Real captured payload (redacted):
{
"event": "Message",
"data": {
"Info": { "Edit": "1", "ID": "3A3EFD...", "IsFromMe": false, "Type": "text", "Timestamp": "..." },
"IsEdit": false,
"Message": {
"secretEncryptedMessage": {
"encIV": "…", "encPayload": "…", "secretEncType": 2,
"targetMessageKey": { "ID": "3A35AE...", "fromMe": true, "remoteJID": "…" }
}
}
}
}Two observations:
data.IsEditisfalseeven for an edit — the only reliable signal isInfo.Edit == "1". If that's intended, it would help to document it; if not, it may be a small bug worth fixing.- The message handler already decrypts poll votes with
DecryptPollVote(inpkg/whatsmeow/service/whatsmeow.go, in the same event-processing block that handlesPollUpdateMessage). The edit path could mirror that: whenevt.Info.Editindicates an edit (orsecretEncryptedMessageis present), decrypt the secret message and emit the resultingeditedMessage/ plaintext in the webhook (e.g. asprotocolMessage.editedMessageor a decodedMessage), so consumers can update the original bubble.
Request: decrypt the secretEncryptedMessage for edits (as already done for poll votes) and surface the plaintext new text in the webhook payload.
Environment
- Evolution Go build "Evolution GO 1.0" (self-hosted), consumed by an external CRM via webhooks + REST.
- Baileys-based Evolution API already surfaces both of these (contact online + decoded edits), so this is purely about reaching parity on the Go engine.
Thanks for the project! Glad to send PRs for these if you'd point me at the preferred approach.
Activity
feat(message): POST /message/subscribe for contact presence