← 所有文章
教學

WhatsApp 引用回覆:分清 reply_token 與父訊息 ID

透過 UnifyPort 引用回覆 WhatsApp 訊息時,將所選訊息的 data.message.reply_token 原樣放入獨立發送請求的 reply_to.reply_token。不要以 data.message.reply_to_message_id 代替:它指向收到的引用回覆所關聯的父訊息,不是剛收到的這則訊息。沒有 token 時,不要用 ID 自行拼造,也不要在使用者不知情下改發普通訊息。

重點

  • 當前訊息 ID、父訊息 ID 及不透明的回覆 token 是不同資料。
  • 發送帳戶與目標對話必須來自所選訊息,而非聊天室的最新訊息。
  • 目前文件列明,引用發送操作只支援 WhatsApp。
  • 歷史訊息不含回覆 token;是否改發普通訊息,應有明確決定。

回覆會引用哪則訊息?

以下是假設情境:訊息 A 提問,訊息 B 引用 A 並補充更正,客服想在回覆時引用 B。

A ← B ← 你的新回覆

標準 webhook 文件將欄位區分如下:

B 的欄位含義應用用途
data.message.idB 的識別碼儲存並在收件箱選取 B
data.message.reply_to_message_idA 的識別碼顯示 B 的父訊息關係
data.message.reply_token用來引用 B 的不透明句柄原樣傳入發送請求
data.conversation.id 及 type原本的對話填入發送目標
account_id已連接的訊息帳戶保留正確的發送帳戶

若介面選取 A,就需要 A 自己儲存下來的 token,不能用 B 的父訊息 ID 代替。若本地沒有父訊息,只顯示引用內容未能取得,不要猜測其文字。

這與「能否在 HTTP webhook 回應內發送訊息」並非同一問題。Webhook 回應與獨立發送請求比較說明傳輸方式;本文處理的是發出的引用指向哪則訊息。

從所選事件建立請求

先驗證傳入事件,再持久化儲存。設定 signing_secret,按 webhook 投遞規範對時間戳、一個點號及原始請求本文計算 HMAC-SHA256,驗證後才能信任資料。時間戳新鮮度與去重仍要分開檢查,詳見 HMAC 重放防護教學。

以下 JavaScript 只是請求建構函式,不是完整接收器或自動發送循環。輸入應是經驗證、已儲存,並由獲授權客服選取的即時事件。函式名稱及錯誤文字屬於應用程式,不是 API 欄位或服務錯誤碼。

function buildQuotedReply(event, text) {
  const conversation = event.data?.conversation;
  const message = event.data?.message;

  if (event.type !== 'message.received' ||
      event.provider !== 'whatsapp' ||
      message?.direction !== 'inbound') {
    throw new Error('Select an inbound WhatsApp message');
  }
  if (!event.account_id || !conversation?.id || !conversation.type) {
    throw new Error('Missing destination context');
  }
  if (typeof message.reply_token !== 'string' || !message.reply_token) {
    throw new Error('Quoted reply unavailable');
  }
  if (typeof text !== 'string' || !text.trim()) {
    throw new Error('Reply text is required');
  }

  return {
    account_id: event.account_id,
    to: { id: conversation.id, type: conversation.type },
    message: { type: 'text', text },
    reply_to: { reply_token: message.reply_token }
  };
}

按照引用回覆 API 文件,使用 POST /v1/messages 發送產生的本文,以 X-Api-Key 驗證,金鑰只保存在後端。群組中的 conversation 代表群組;改用 data.sender.id 會改變發送目的地,而不是選擇引用。

發送前,確認操作人員有權存取該訊息帳戶及對話。在本地發送工作中保留所選訊息的識別碼,避免新訊息到達後改變引用目標。限制已儲存 token 的存取權限,不要放進一般日誌或 AI 提示詞。

token 缺失、無效,還是渠道不支援?

情況文件界線建議處理
即時訊息沒有 tokenWhatsApp 在設定回覆 token 簽署時提供它核對事件來源與設定,明確提供普通訊息選項
訊息來自 conversation.history歷史訊息沒有 reply_token不自行拼造 token,也不承諾從歷史資料還原
400 invalid_reply_tokentoken 被修改、使用不同金鑰加密,或無法讀取檢查儲存值及序列化流程,保留錯誤作調查
501 unsupported_by_provider所選渠道未實作引用發送停用此引用發送流程,不要無限重試
省略 reply_to會發送普通訊息必須明確選擇此替代行為

Webhook 的 signing_secret 用來驗證投遞,不應假設更換它就能修復無法讀取的加密回覆句柄。錯誤參考定義錯誤含義,但沒有承諾 token 修復方法或有效期。

驗收案例與限制

測試 B 引用 A 時,選取 B 仍會引用 B。亦要測試撰寫草稿期間收到新訊息、群組、token 缺失、只有歷史訊息,以及重複投遞。重複接收不應建立另一項發送工作。以上是建議測試,不是已完成的測試結果。

記錄實際發送結果。data.status: accepted 不是已讀回條,網絡逾時也不代表訊息沒有發出。不要盲目重發,或在報錯後自動移除 reply_to。

UnifyPort 提供非官方介面。統一事件格式不等於所有渠道都支援引用發送。例如 Telegram 官方 Bot API 文件定義自己的 reply_parameters 及 ReplyParameters,不能直接放入這裏的請求。需要原生功能時應使用對應的原生 API。UnifyPort 沒有 REST 訊息歷史讀取 API,也不保證重放遺漏的資料。

常見問題

可以把 reply_to_message_id 放入 reply_to.reply_token 嗎?

不可以。前者指向傳入訊息的父訊息;後者必須是所選訊息原樣保存的不透明 token。

有歷史訊息 ID 就能引用它嗎?

沒有對應 token,就不能使用此文件記載的 token 操作。歷史資料不提供 token。普通訊息只能作為明確選擇的替代方案。

UnifyPort 的 Telegram、LINE、Zalo 也支援嗎?

目前引用發送文件限定為 WhatsApp。不能因為傳入訊息有引用關係,就推斷渠道支援引用發送。

下一步與參考資料

先按引用回覆文件實作訊息選取檢查,再啟用收件箱的「引用」按鈕。

核對日期:2026-09-26。

UnifyPort API

令訊息接入變成一條穩定嘅產品管線。

先用統一嘅 API 跑通發送,再用標準事件將所有入站訊息接返去業務系統。