Ответ с цитатой в 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:
Превратите интеграцию сообщений в стабильный продуктовый pipeline.
Начните с отправки через единый API, затем возвращайте входящие сообщения в бизнес-систему стандартными событиями.