Skip to content

fix(reply): resolve quoted context for replies to business-sent messages - #507

Open
bambinounos wants to merge 1 commit into
shridarpatil:mainfrom
bambinounos:fix/reply-wamid-cross-perspective
Open

fix(reply): resolve quoted context for replies to business-sent messages#507
bambinounos wants to merge 1 commit into
shridarpatil:mainfrom
bambinounos:fix/reply-wamid-cross-perspective

Conversation

@bambinounos

Copy link
Copy Markdown
Contributor

Problem

When a customer replies to a message the business sent (WhatsApp reply/quote), the quoted context never renders — the reply shows up as a plain message with no quoted preview. Replies to the customer's own earlier inbound message do render correctly.

Root cause

WhatsApp encodes the peer's phone number into the WAMID prefix, so the same message has a different WAMID from the sender's vs the recipient's perspective.

  • An outbound message stores the sender-perspective WAMID (the id Meta returns from the send call).
  • When the customer replies to it, the inbound webhook's context.id is the recipient-perspective WAMID.

saveIncomingMessage resolves the quoted message with an exact match only:

a.DB.Where("whats_app_message_id = ?", replyToWAMID).First(&replyToMsg)

The two WAMIDs never match, so it logs "Reply-to message not found", IsReply stays false, and the frontend has nothing to render.

This is the same asymmetry that handleIncomingReaction already handles — it falls back to matching on the unique suffix after "FQIA" + a 4-char type indicator, which is stable across perspectives. The reaction path had the fallback; the reply path never got it.

Fix

  • Extract the exact-then-FQIA-suffix lookup into a shared helper resolveMessageByWAMID(wamid) (*models.Message, bool).
  • Use it on the reply path in saveIncomingMessage.
  • Refactor handleIncomingReaction to use the same helper, removing the duplicated FQIA magic-constant logic.

No schema change — IsReply / ReplyToMessageID / the preloaded ReplyToMessage relation and the API/DTO already exist; this only fixes resolution.

Tests

Added TestSaveIncomingMessage_ReplyToBusinessSentMessage: seeds an outbound message with a sender-perspective WAMID, processes an inbound reply whose context.id is the recipient-perspective WAMID (different prefix + type indicator, same suffix), and asserts the reply resolves (IsReply == true, ReplyToMessageID points at the outbound message). The existing exact-match reply test and the reaction tests continue to cover their paths.

go build ./..., go vet ./... clean.

WhatsApp encodes the peer phone number into the WAMID prefix, so the same
message has a different WAMID from the sender's vs the recipient's
perspective. When a customer replies to a message the business SENT, the
inbound context.id is the recipient-perspective WAMID, which never matches
the sender-perspective WAMID stored on the outbound row via an exact lookup.
IsReply stayed false and the quoted preview never rendered (replies to the
customer's own earlier inbound message matched exactly and did render).

Extract the exact-then-FQIA-suffix fallback already used by the reaction
handler into a shared resolveMessageByWAMID helper, and use it on the reply
path in saveIncomingMessage. The reaction handler now shares the same
resolver, removing the duplicated FQIA magic-constant logic.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant