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[] が定義されています。1つのイベントに複数の変更が入る場合があります。グループ名ではなく、受信側のワークスペース情報、provider、account_id、data.conversation.id で対象を識別します。
| 変更の種類 | 一覧への影響 | 推奨する処理 |
|---|---|---|
member_added / member_removed | 所属メンバーが変わった可能性 | メンバー一覧の再取得を予約 |
promoted / demoted | 役割が変わった可能性 | ID と役割を再取得 |
renamed / description_changed / avatar_changed | グループ情報の変更 | 別のグループ情報更新処理へ渡す |
dissolved | グループのライフサイクルの変更 | 確認対象にし、保存済み履歴は自動削除しない |
changes[0] だけではなく、配列全体を確認します。同じイベントに名前変更とメンバー追加があれば、両方に対応する更新が必要です。不明な種類や形式が不正な項目は、意味を推測せず調査用に保持してください。
担当者が役割を変更したい場合は、別の管理者の昇格・降格フローを使います。削除通知を受けたからといって、もう一度削除要求を送る必要はありません。意図的な書き込みはメンバー削除フローで扱います。
全ページを取得してから一覧を作る
会話メンバー一覧のリファレンスは peer_id、display_name、avatar_url、role を返します。役割は member、admin、superadmin で、最後の値は所有者または作成者を表します。
次はバックエンド用の例です。環境変数には実際に選択したメッセージングアカウントとグループの ID を設定します。この例は本記事では実行していません。
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 のメンバー管理 API は、返されたメンバーの LID を要求します。電話番号から作ったり、異なる形式の ID を文字列変換で同一視したりしないでください。
読み取り中の次の更新要求を失わない
以下はアプリケーション側の推奨アルゴリズムです。UnifyPort の追加フィールドや、サーバー側のトランザクション保証ではありません。
- イベントを永続化する。 必要な既存の購読を残しつつ、
group.updatedを購読します。webhook 配信仕様に従って署名とタイムスタンプを検証してから本文を信頼します。署名はsigning_secretを鍵として、X-Device-Timestamp、ピリオド、未加工の本文に対する HMAC-SHA256 を16進数で表したものです。 - 更新要求を原子的に記録する。 認証済みの通常イベントをイベント ID で重複排除して保存し、対象グループのローカルな更新世代を増やします。この2つを同じトランザクションで確定してから 2xx を返します。再配信で新たな業務操作を作らないでください。
- 対象グループごとに1つの worker が読む。 現在のローカル世代を記録し、全メンバーページを取得します。保留中の複数イベントを1回の取得にまとめ、参加者ごとに要求しないようにします。
- 公開前に再確認する。 受信処理と連携したトランザクション内で、開始時と現在の世代を比較します。ページ取得中に変わっていたら、その結果は暫定情報として扱い、次の取得を予約します。更新完了にはしません。
- 完了した観測結果を表示する。 全ページに成功し、新しいローカル更新要求がなければ、表示用の一覧を置き換えて当該世代を処理済みにします。その後に確定したイベントは、新しい更新作業を作ります。
worker が停止しても未完了の世代を復旧できるようにします。メモリ内だけのフラグでは更新要求を失うことがあります。処理の直列化や書き込みガードを使い、遅い古い取得が新しい完了結果を上書きしないようにしてください。
この方法で検出できるのは、読み取り中にアプリケーションが受信したイベントです。上流の状態が変わらなかったことまでは証明できません。API はページと webhook をまたぐ共通のスナップショット版を定義していません。完全なリアルタイム性を約束する代わりに、最終観測時刻を表示します。遅れて届いたイベントは再取得のきっかけにすればよく、古い差分を使って一覧を戻す必要はありません。
通知がない場合と読み取り失敗
UnifyPort は非公式インターフェースです。イベント対応表はパーサーの対応状況であり、すべての上流アカウントで通知される保証ではありません。取り逃したイベントの再配信も保証されません。LINE などを同じ受信基盤で扱う場合も、共通形式だけを理由に同じグループイベントを期待しないでください。
グループ画面の初回利用時に一覧を取得し、明示的な更新ボタンを用意します。実際に利用するグループには、必要に応じて頻度を抑えた定期照合も検討できます。本記事はポーリング枠や鮮度保証を示すものではありません。
メンバー取得に失敗しただけでは、グループ解散や全員退出とは判断できません。取得不能、古い情報、空の一覧を分けてください。参加申請も別の処理です。group.join_request は加入完了を意味しません。
よくある質問
changes[].members[] から完全な一覧を再構築できますか?
できません。配列は特定の変更を受けた参加者だけを示します。現在の一覧は全ページを取得してください。
data.actor は加入・退出した人ですか?
変更を行った人です。影響を受けた参加者は対応する members[] で確認し、現在の名簿は一覧 API で取得します。
役割通知でアプリケーション内の権限を付与してよいですか?
メッセージングプラットフォームの役割を、そのままアプリケーション権限と同一視しないでください。担当者の認可方針は独立させ、機密性の高い操作前に再確認します。
次のステップと参考資料
会話メンバー一覧に沿って更新 worker を実装してください。後続ページにしかない参加者、途中ページの失敗、重複イベント、複数変更を含むイベント、取得中の新しい変更、公開直前の worker 停止をテストします。これらは推奨テストであり、実施済みの結果ではありません。
資料確認日:2026-11-09。
メッセージ連携を安定したプロダクトパイプラインへ。
まずは 1 つの API で送信を始め、標準イベントですべての inbound メッセージを業務システムへ戻しましょう。