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

Как добавлять и удалять реакции на сообщения через UnifyPort

Чтобы добавить реакцию через UnifyPort, вызовите POST /v1/messages/reaction, указав выбранный аккаунт, диалог, сообщение, автора исходного сообщения и emoji. Чтобы удалить существующую реакцию подключённого аккаунта, отправьте тот же объект назначения с emoji: "". Главное: sender_id обозначает автора сообщения, на которое ставится реакция, а не оператора и не произвольного пользователя, чью реакцию вы хотите изменить.

Главное

  • Исходящее действие поддерживается для whatsapp и telegram. Получение событий реакций — отдельная возможность.
  • Берите цель из выбранного исходного сообщения, а не из идентификатора самой реакции.
  • Для чужого сообщения явно задавайте sender_id: по умолчанию используется подключённый аккаунт.
  • Добавление и удаление должны быть явными намерениями, а не переключателем, повторяемым после любой ошибки.

Сопоставьте поля с исходным сообщением

Справочник React to message описывает действие над существующим сообщением. Это не отправка текста с эмодзи и не цитируемый ответ с токеном.

Поле запросаИсточник в сохранённом событии message.received
account_idВерхнеуровневое account_id
conversation_iddata.conversation.id
message_iddata.message.id
sender_iddata.sender.id — автор исходного сообщения
emojiВыбранный эмодзи или пустая строка для удаления

В групповом чате диалог обозначает группу, а отправитель — участника. Не подменяйте идентификатор диалога идентификатором отправителя только потому, что в личной переписке они выглядят похожими. Сохраняйте идентификаторы провайдера без изменений: не составляйте их из имени контакта или номера телефона.

Если исходной точкой служит событие message.reaction, различие другое: data.message.id обозначает саму реакцию, а data.message.target_message_id — исходное сообщение. Отправитель такого события — человек, поставивший реакцию, не обязательно автор исходного сообщения. Сначала найдите сохранённый оригинал. Руководство по обработке webhook реакций объясняет входящий поток и обновление представления состояния; здесь рассматривается отдельный исходящий запрос.

Сформируйте явный запрос добавления или удаления

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

function buildReactionRequest(original, emoji) {
  if (original.type !== 'message.received' ||
      !['whatsapp', 'telegram'].includes(original.provider)) {
    throw new Error('Select a supported original message');
  }

  const conversation = original.data?.conversation;
  const message = original.data?.message;
  const sender = original.data?.sender;
  if (!original.account_id || !conversation?.id ||
      !message?.id || !sender?.id) {
    throw new Error('Original message context is incomplete');
  }
  if (typeof emoji !== 'string') {
    throw new Error('Choose an emoji or an empty string');
  }

  return {
    account_id: original.account_id,
    conversation_id: conversation.id,
    message_id: message.id,
    sender_id: sender.id,
    emoji
  };
}

Передайте "👍" для добавления или "" для удаления. Функция проверяет контекст и тип значения, но не гарантирует, что вышестоящая платформа примет любой эмодзи. Не заменяйте пустую строку на null, не пропускайте поле и не добавляйте недокументированный флаг remove.

Отправляйте полученный JSON с сервера в POST /v1/messages/reaction, используя X-Api-Key. Не помещайте ключ в браузерный код. Перед отправкой проверьте права оператора на аккаунт обмена сообщениями и выбранное сообщение. Зафиксируйте выбор, чтобы новое входящее сообщение не изменило цель действия.

Если нужен текстовый ответ с цитатой, а не реакция, используйте отдельный сценарий цитируемого ответа WhatsApp. Его непрозрачный reply_token не является идентификатором реакции.

Включайте кнопку по поддержке действий, а не событий

Текущие матрица действий провайдеров и матрица webhook-событий описывают разные возможности.

ПровайдерОтправка реакции этим методомПреобразование событий реакций
whatsappПоддерживаетсяПоддерживается
telegramПоддерживаетсяПоддерживается
lineНе поддерживаетсяПоддерживается
twitter, zalo, tiktok, whatsapp-protocolНе поддерживаетсяНе поддерживается

Это документированные возможности адаптеров, а не гарантия доступности для любого аккаунта и любых условий платформы. Интерфейс LINE может показывать входящие реакции, не имея работающей кнопки их отправки. Неподдерживаемое сочетание возвращает 501 unsupported_by_provider; повторение запроса не добавляет поддержку.

UnifyPort предоставляет неофициальный интерфейс для подключённых аккаунтов. Официальный Telegram Bot API отдельно определяет setMessageReaction для ботов. Если требуется именно бот, используйте его нативный контракт. Не переносите формат запроса в этот метод и не считайте ограничения Bot API описанием поведения UnifyPort.

Разделяйте намерение, результат запроса и наблюдаемое состояние

В справочнике успешный ответ — 200 OK с data.ok: true. Сохраните фактический HTTP-результат и полученный request_id. Такой результат не доказывает, что другой человек увидел реакцию.

Рекомендуемая логика приложения:

  1. Выполняйте действия для одной пары «аккаунт — целевое сообщение» последовательно. Задержавшееся добавление не должно бесконтрольно выполняться после более нового удаления.
  2. До отправки сохраните желаемый эмодзи, а HTTP-результат храните отдельно.
  3. При react_message_failed изучите ошибку и исходную цель. При тайм-ауте оставьте результат неопределённым: не отправляйте противоположное действие как автоматическую компенсацию.
  4. При получении соответствующего события идемпотентно обновите наблюдаемое состояние. Не предполагайте, что каждый запрос создаёт callback или что callbacks приходят по порядку.

На стороне получателя настройте signing_secret и соблюдайте контракт доставки: проверяйте HMAC-SHA256 от временной метки, точки и исходных байтов тела, контролируйте свежесть метки и сохраняйте данные до подтверждения. Полученный webhook сам по себе не разрешает автоматически запускать новое исходящее действие.

Приёмочные проверки и FAQ

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

Можно ли через sender_id выбрать, кто поставит реакцию?

Нет. Поле обозначает автора целевого сообщения. Действие выполняет подключённый аккаунт; поле не позволяет выдавать себя за другого пользователя.

Удалит ли реакцию повторная отправка того же эмодзи?

Документированный способ удаления — emoji: "". Не предполагайте семантику переключателя.

Почему реакции LINE можно получать, но нельзя отправлять?

Обработка входящих событий и исходящие действия имеют отдельные матрицы поддержки. Сейчас исходящее действие реакций поддерживает Telegram и WhatsApp.

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

Реализуйте проверки цели по React to message, прежде чем добавлять кнопку в общий inbox. Если данных недостаточно, оставляйте состояние неопределённым: не придумывайте метод чтения реакций или гарантированное воспроизведение событий.

Проверено 2026-10-16:

UnifyPort API

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

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