用 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 跑通傳送,再用標準事件把所有入站訊息接回業務系統。