用 group.updated 同步 WhatsApp 群組成員名單
要讓應用程式內的 WhatsApp 群組成員名單保持更新,可將 UnifyPort 的 group.updated webhook 視為重新查詢的訊號,再透過 List conversation members 取得名單。處理 data.changes[] 的所有項目,但不要把當中的參與者 ID 當成完整名單。只有全部分頁都成功後,才發布更新結果;如果查詢期間再收到變更,便安排下一輪查詢。
重點
data.actor是作出變更的人,changes[].members[]才是受影響的參與者。- 是否屬於群組與是否擔任管理員,是兩個不同維度。
- 查詢失敗或結果不完整,不應清除之前觀察到的成員。
- 這是讀取端同步流程,不會自動管理群組成員。
理解通知,不要將它當作操作指令
WhatsApp 的管理員說明區分委任及撤銷管理員。應用程式亦應保留這個分別:角色改變不等於退出群組。
UnifyPort 的 group.updated 文件定義了 data.conversation、data.actor 及 data.changes[]。單一事件可以包含多項變更。請使用接收端的工作空間脈絡、provider、account_id 及 data.conversation.id 識別群組,不要以群組名稱配對。
| 變更種類 | 對名單的影響 | 建議處理 |
|---|---|---|
member_added / member_removed | 成員關係可能改變 | 排程重新查詢名單 |
promoted / demoted | 角色可能改變 | 同時更新成員識別碼及角色 |
renamed / description_changed / avatar_changed | 群組資料改變 | 交由獨立的群組資料更新流程處理 |
dissolved | 群組生命週期改變 | 標記待核實,不自動刪除已儲存的歷史 |
應遍歷整個陣列,而非只讀取 changes[0]。同一事件若包含改名及新增成員,兩種更新都要處理。未知或格式異常的項目應保留作調查,不要猜測效果。
如果操作員確實要調整角色,請使用獨立的管理員升降級流程。收到移除通知,不應再發出一次移除請求;主動寫入應使用移除群組成員流程。
以完整查詢建立名單
列出對話成員文件回傳 peer_id、display_name、avatar_url 及 role。角色有 member、admin、superadmin,最後一項代表擁有者或建立者。
以下是後端請求示例,環境變數來自實際選定的訊息帳戶及群組;本文沒有執行此請求:
curl --get \
"https://api.unifyport.ai/v1/accounts/${UNIFYPORT_ACCOUNT_ID}/conversations/members" \
-H "X-Api-Key: ${UNIFYPORT_API_KEY}" \
--data-urlencode "conversation_id=${WHATSAPP_GROUP_ID}" \
--data-urlencode "type=group" \
--data-urlencode "limit=50"
當 data.has_more 為 true,將 data.next_cursor 放入下一次請求的 cursor 查詢參數。先把所有分頁累積到暫存集合,以回傳的 peer_id 為鍵。API 金鑰必須留在後端。
成員沒有出現在第一頁,不代表可從畫面移除。任何一頁失敗,都應保留上一次完整名單,並顯示更新仍未完成。查詢成功完成但沒有成員,與請求失敗是兩種不同結果。
請原樣保留識別碼。事件中的參與者 ID 不一定可與名單的 peer_id 互換。尤其 WhatsApp 成員管理端點要求使用回傳的成員 LID;不要從電話號碼自行建立,也不要靠字串改寫將不同格式的 ID 強行視為相同。
避免更新工作遺失下一個觸發訊號
以下是建議的應用程式演算法,不是新增的 UnifyPort 欄位,亦不是伺服器端交易保證:
- 持久儲存接收到的事件。 訂閱
group.updated,並保留其他必要訂閱。依照 webhook 傳送契約先驗證簽署及時間戳記,再信任內容。簽署以signing_secret對X-Device-Timestamp、一個句點及原始內容計算十六進位 HMAC-SHA256。 - 以原子方式記錄更新需求。 在同一交易內,按事件 ID 去重並儲存已驗證的一般事件,同時遞增該群組的本地更新代次。完成後才回覆 2xx。重複傳送不應產生新的業務操作。
- 每個範圍內的群組由一個 worker 讀取。 記下目前的本地代次,再取得全部成員分頁。可將多個待處理事件合併成一次查詢,毋須每個參與者都查一次。
- 發布前再次檢查。 在與接收流程協調的交易內,比較開始查詢時及目前的代次。若分頁期間代次已改變,將暫存結果保留為臨時觀察並安排下一輪,不要標記名單已更新完成。
- 發布完成的觀察結果。 全部分頁成功,而且沒有新的本地觸發待處理時,才替換顯示名單並標記該代次已處理。其後提交的新事件會建立新的更新工作。
worker 停止後應能恢復未完成的代次。只存在記憶體的旗標可能遺失更新需求。透過順序執行或寫入保護,避免較慢的舊查詢覆蓋較新的完成結果。
這個機制只會發現應用程式在查詢期間收到的事件,不能證明上游成員一直沒有變動:公開介面沒有跨分頁及 webhook 共用的快照版本。介面應顯示最後觀察時間,而非承諾絕對即時。遲到的事件可再觸發查詢,毋須將名單回復至舊增量對應的狀態。
處理沒有通知及查詢失敗
UnifyPort 是非官方介面。事件支援矩陣描述解析器的對應能力,不保證每個上游帳戶都會發出所有通知,亦不保證遺漏事件可重播。
首次開啟群組畫面時初始化名單,提供明確的重新整理按鈕,並按需要為活躍群組安排受控的定期核對。本文不聲稱任何輪詢配額或資料新鮮度保證。
成員查詢失敗,不能單獨證明群組已解散或所有人已離開。請把無法取得、資料過期與空名單分開。待審批申請亦屬另一流程:group.join_request 不代表已確認加入。
常見問題
可以用 changes[].members[] 重建完整名單嗎?
不可以。陣列只描述特定變更影響的參與者,不是所有現有成員。應查詢並處理全部成員分頁。
data.actor 是加入或退出的人嗎?
它代表作出變更的人。受影響的參與者應查看對應的 members[],目前名單則透過成員查詢取得。
角色更新可以直接授予應用程式權限嗎?
不要自動將通訊平台角色等同於應用程式權限。操作員授權政策應獨立管理,敏感操作前亦應重新核實。
下一步及參考資料
按列出對話成員文件實作更新 worker。建議測試:成員出現在後續頁、中途分頁失敗、重複事件、同一事件多項變更、分頁期間收到新變更,以及發布前 worker 停止。這些是待執行測試,不是已驗證結果。
資料核對日期:2026-11-09。
令訊息接入變成一條穩定嘅產品管線。
先用統一嘅 API 跑通發送,再用標準事件將所有入站訊息接返去業務系統。