← Все статьи
Руководство

Синхронизация участников группы WhatsApp через group.updated

Чтобы поддерживать список участников группы WhatsApp в актуальном состоянии, используйте webhook group.updated от UnifyPort как сигнал для повторного чтения через List conversation members. Обрабатывайте все элементы data.changes[], но не считайте перечисленные там ID полным составом группы. Публикуйте обновлённый список только после успешной загрузки всех страниц. Если во время чтения поступило новое изменение, запланируйте ещё один проход.

Главное

  • data.actor — тот, кто внёс изменение; changes[].members[] — участники, которых оно затронуло.
  • Членство в группе и роль администратора — разные характеристики.
  • Частичный результат или ошибка чтения не должны стирать ранее полученный список.
  • Это синхронизация данных на стороне чтения, а не автоматическое управление участниками.

Не превращайте уведомление в команду

В документации WhatsApp об администраторах назначение и снятие административной роли рассматриваются отдельно. Сохраните это различие в интерфейсе: изменение роли не означает выход из группы.

Справочник 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]. Переименование и добавление участника в одном событии требуют обоих соответствующих обновлений. Неизвестные или некорректные элементы сохраняйте для разбора, не угадывая их эффект.

Если оператор действительно хочет изменить роль, используйте отдельный процесс назначения и снятия администраторов. Уведомление об удалении участника не должно вызывать ещё один запрос удаления. Для намеренных изменений есть процесс удаления участника.

Формируйте список только после полного чтения

Метод List conversation members возвращает peer_id, display_name, avatar_url и role. Роли: member, admin, superadmin; последняя обозначает владельца или создателя.

Пример запроса с backend использует переменные окружения с реально выбранными идентификаторами аккаунта и группы. В рамках статьи этот запрос не выполнялся:

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 в query-параметре cursor следующего запроса. Соберите все страницы во временную коллекцию с ключом по возвращённому peer_id. API-ключ должен оставаться на сервере.

Не удаляйте человека из интерфейса только потому, что его нет на первой странице. При ошибке любой страницы сохраняйте последний полностью загруженный список и показывайте, что обновление не завершено. Успешное завершённое чтение с пустым результатом и неудачный запрос — разные состояния.

Сохраняйте идентификаторы без изменений. ID участников из события не обязательно взаимозаменяемы с peer_id из списка. В частности, метод управления участниками WhatsApp требует возвращённый LID участника. Не создавайте его из номера телефона и не приравнивайте разные форматы ID путём преобразования строк.

Не потеряйте следующий сигнал во время обновления

Ниже — рекомендуемый алгоритм приложения. Это не дополнительные поля UnifyPort и не обещание серверной транзакции.

  1. Надёжно принимайте события. Подпишитесь на group.updated, сохранив остальные нужные подписки. Прежде чем доверять телу, проверьте подпись и время по правилам доставки webhook. Подпись — шестнадцатеричный HMAC-SHA256 с ключом signing_secret от X-Device-Timestamp, точки и исходного тела запроса.
  2. Атомарно фиксируйте необходимость обновления. В одной транзакции сохраните проверенное обычное событие с дедупликацией по ID и увеличьте локальное поколение обновления этой группы. Затем ответьте 2xx. Повторная доставка не должна создавать новую бизнес-операцию.
  3. Пусть одну группу в заданном контексте читает один worker. Зафиксируйте текущее локальное поколение и загрузите все страницы участников. Несколько ожидающих событий можно объединить в одно чтение, а не запрашивать список отдельно для каждого участника.
  4. Проверьте поколение перед публикацией. В транзакции, согласованной с приёмом событий, сравните исходное и текущее поколения. Если за время пагинации оно изменилось, считайте результат предварительным и запланируйте новый проход. Не отмечайте список актуальным.
  5. Публикуйте завершённое наблюдение. Если все страницы получены и новых локальных сигналов нет, замените отображаемый список и отметьте поколение обработанным. Событие, зафиксированное после этого, создаст новую работу.

После сбоя worker должен восстанавливать незавершённые поколения. Флаг только в памяти может потерять запрос на обновление. Последовательное выполнение или защита записи должны исключать ситуацию, когда медленное старое чтение перезаписывает более новый результат.

Такая защита обнаруживает события, полученные приложением во время чтения. Она не доказывает, что состав на стороне платформы всё это время был неизменным: API не определяет общую ревизию снимка для страниц и webhook. Показывайте время последнего наблюдения, а не обещание абсолютно актуального состава. Запоздавшее событие может просто запустить новое чтение — применять старую разницу к текущему списку необязательно.

Учитывайте отсутствие уведомлений и ошибки чтения

UnifyPort — неофициальный интерфейс. Матрица поддержки событий описывает возможности парсеров, а не гарантирует уведомление от каждого аккаунта платформы. Воспроизведение пропущенных событий также не гарантируется.

Загружайте список при первом открытии группы, предоставьте явную кнопку обновления и при необходимости добавьте ограниченную периодическую сверку для активно используемых групп. Выбирайте расписание по эксплуатационным потребностям: статья не устанавливает квоту опроса или гарантию свежести.

Ошибка получения участников сама по себе не доказывает роспуск группы или выход всех пользователей. Отделяйте недоступность и устаревшие данные от пустого списка. Заявители тоже относятся к другому процессу: group.join_request не означает подтверждённое вступление.

Вопросы и ответы

Можно ли восстановить полный состав из changes[].members[]?

Нет. Эти массивы содержат участников, затронутых конкретными изменениями, а не всех текущих членов группы. Получите список с полной пагинацией.

data.actor — это вошедший или вышедший участник?

Это тот, кто выполнил изменение. Затронутые участники указаны в соответствующем members[], а текущий состав нужно читать отдельным запросом.

Может ли изменение роли автоматически выдавать права в приложении?

Не приравнивайте роль в мессенджере к полномочиям в вашем приложении. Политика доступа операторов должна быть отдельной; перед чувствительными действиями повторно проверяйте разрешения.

Следующий шаг и источники

Реализуйте worker обновления по документации List conversation members. Проверьте участника на поздней странице, ошибку промежуточной страницы, повтор события, несколько изменений в одном событии, новое изменение во время пагинации и сбой worker перед публикацией. Это предлагаемые проверки, а не результаты проведённых испытаний.

Источники проверены 2026-11-09:

UnifyPort API

Превратите интеграцию сообщений в стабильный продуктовый pipeline.

Начните с отправки через единый API, затем возвращайте входящие сообщения в бизнес-систему стандартными событиями.