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

Ответ с цитатой в WhatsApp: reply_token и ID родительского сообщения

Чтобы процитировать сообщение WhatsApp через UnifyPort, передайте его data.message.reply_token без изменений в reply_to.reply_token отдельного запроса отправки. Не подставляйте data.message.reply_to_message_id: это идентификатор родительского сообщения, на которое ссылается входящий ответ, а не самого полученного сообщения. Если токена нет, не создавайте его из ID и не отправляйте обычное сообщение без явного решения пользователя.

Главное

  • Разделяйте ID текущего сообщения, ID его родителя и непрозрачный токен ответа.
  • Берите аккаунт и диалог из выбранного сообщения, а не из последнего сообщения в чате.
  • Документированная операция отправки с цитатой сейчас поддерживает только WhatsApp.
  • В истории токенов ответа нет; переход к обычной отправке должен быть явным.

Какое сообщение будет процитировано?

Рассмотрим условный диалог: сообщение A содержит вопрос, B цитирует A и добавляет уточнение, а оператор хочет ответить с цитатой B.

A ← B ← ваш новый ответ

Справочник стандартных webhook-событий различает следующие значения:

Поле входящего BЗначениеПрименение
data.message.idИдентификатор BСохранение и выбор B в интерфейсе
data.message.reply_to_message_idИдентификатор AОтображение связи B с родителем
data.message.reply_tokenНепрозрачный дескриптор для цитирования BПередача без изменений в запрос отправки
data.conversation.id и typeИсходный диалогАдресат отправки
account_idПодключённый аккаунт обмена сообщениямиСохранение правильного аккаунта отправителя

Если в интерфейсе выбрано A, нужен собственный сохранённый токен A. ID родителя из B его не заменяет. Родительского сообщения может не быть в вашей базе: показывайте недоступную ссылку, а не выдумывайте текст.

Это не тот же вопрос, что отправка сообщения внутри HTTP-ответа на webhook. Сравнение webhook-ответа и отдельного запроса объясняет транспортный механизм. Здесь важно, на какое сообщение указывает исходящая цитата.

Соберите запрос из выбранного события

Сначала проверьте подлинность входящего события и надёжно сохраните его. Включите signing_secret и соблюдайте контракт доставки webhook: проверяйте HMAC-SHA256 от временной метки, точки и исходного тела запроса до использования данных. Проверка свежести метки и дедупликация остаются отдельными мерами; подробнее — в руководстве по защите от повторного воспроизведения.

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

function buildQuotedReply(event, text) {
  const conversation = event.data?.conversation;
  const message = event.data?.message;

  if (event.type !== 'message.received' ||
      event.provider !== 'whatsapp' ||
      message?.direction !== 'inbound') {
    throw new Error('Select an inbound WhatsApp message');
  }
  if (!event.account_id || !conversation?.id || !conversation.type) {
    throw new Error('Missing destination context');
  }
  if (typeof message.reply_token !== 'string' || !message.reply_token) {
    throw new Error('Quoted reply unavailable');
  }
  if (typeof text !== 'string' || !text.trim()) {
    throw new Error('Reply text is required');
  }

  return {
    account_id: event.account_id,
    to: { id: conversation.id, type: conversation.type },
    message: { type: 'text', text },
    reply_to: { reply_token: message.reply_token }
  };
}

Отправьте полученное тело через POST /v1/messages с аутентификацией X-Api-Key, как указано в справочнике отправки с цитатой. Ключ должен оставаться на сервере. В групповом чате conversation обозначает группу; подстановка data.sender.id меняет адресата, а не выбирает цитату.

Перед отправкой проверьте доступ оператора к выбранному аккаунту и диалогу. Сохраните идентификатор выбранного сообщения в локальном задании: новое входящее сообщение не должно менять цель. Ограничьте доступ к сохранённым токенам и не включайте их в общие журналы или запросы к ИИ.

Нет токена, токен недействителен или канал не поддерживается?

НаблюдениеДокументированная границаРекомендуемое действие
У сообщения реального времени нет токенаWhatsApp-токен появляется при настроенной подписи токенов ответаПроверьте источник события и конфигурацию; явно предложите обычную отправку
Сообщение пришло в conversation.historyВ истории нет reply_tokenНе создавайте токен и не обещайте восстановление из истории
400 invalid_reply_tokenТокен изменён, зашифрован другим ключом или не читаетсяПроверьте сохранённое значение и сериализацию; сохраните ошибку для расследования
501 unsupported_by_providerВыбранный провайдер не реализует отправку с цитатойОтключите этот путь, не запускайте бесконечные повторы
reply_to отсутствуетОтправляется обычное сообщениеТребуйте осознанного выбора альтернативы

Webhook-параметр signing_secret подтверждает подлинность доставки. Не считайте, что его замена исправит нечитаемый зашифрованный дескриптор ответа. Справочник ошибок определяет значения ошибок, но не обещает способ исправления токена или срок его действия.

Приёмочные проверки и ограничения

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

Фиксируйте фактический результат отправки. data.status: accepted не является уведомлением о прочтении, а сетевой тайм-аут не доказывает, что сообщение не отправлено. Не повторяйте отправку вслепую и не удаляйте reply_to автоматически после ошибки.

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

Частые вопросы

Можно ли подставить reply_to_message_id в reply_to.reply_token?

Нет. Первое поле указывает на родителя входящего сообщения. Во втором должен быть неизменённый непрозрачный токен выбранного сообщения.

Можно ли процитировать сообщение из истории, имея только его ID?

Без соответствующего токена — не через эту документированную операцию. Данные истории токен не предоставляют. Обычная отправка допустима лишь как явно выбранная альтернатива.

Работает ли это для Telegram, LINE и Zalo через UnifyPort?

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

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

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

Проверено 2026-09-26:

UnifyPort API

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

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