Как защитить ответы в очереди 24-часовым send guard WhatsApp
Ответ WhatsApp в очереди может пересечь 24-часовую границу во время согласования, повтора или ожидания worker. Надёжный send guard перед фактической отправкой заново читает серверное состояние, вычисляет срок по последнему проверенному сообщению пользователя и блокирует просроченный свободный текст. Категории и тарифы разобраны в дереве решений service vs utility; здесь рассматривается именно защита от ошибочной отправки.
Главное
- Храните два срока и монотонно растущий
state_version, а не один логический флаг. - Сбрасывать 24-часовое окно может только проверенное и дедуплицированное входящее сообщение пользователя.
- После получения задачи worker перечитывает состояние в той же транзакции или под той же блокировкой.
- Просроченный черновик останавливается и маршрутизируется заново, а не превращается в шаблон без подтверждения.
- Проверьте дубликаты, события не по порядку, конкурирующие worker и секундные границы.
Постройте send guard вокруг ответов в очереди
Официальная страница тарифов Business Platform указывает, что сообщение пользователя открывает или сбрасывает 24-часовое окно. В реализации эта граница разрешения становится финальным условием отправки. Изменения категорий и тарифов октября 2026 года отдельно описаны в существующем руководстве и здесь не повторяются.
Для каждой задачи в очереди отправитель отвечает на три практических вопроса:
- Прочитана ли последняя версия состояния? Старый worker не должен перезаписывать обновлённый срок.
- Открыто ли окно в момент фактической отправки? Нельзя повторно использовать решение, принятое при создании или согласовании черновика.
- Разрешён ли выбранный путь? После закрытия окна допустим только действительно подходящий одобренный шаблон; иначе задачу следует остановить и вернуть оператору.
Храните два таймера, а не один статус
Явные сроки позволяют заново оценить повторную попытку, отложенную задачу или передачу другому оператору.
| Поле | Что запускает или сбрасывает | Что контролирует |
|---|---|---|
service_window_expires_at | Каждое входящее сообщение пользователя | Разрешён ли нетиповой сервисный ответ |
free_entry_expires_at | Допустимый вход из Click-to-WhatsApp или кнопки Facebook Page | Освобождена ли доставка от платы на 72 часа |
last_user_message_id | Каждое принятое входящее сообщение | Идемпотентность и аудит текущего окна |
state_version | Каждое событие, меняющее состояние | Защита нового состояния от устаревшей задачи |
72-часовая бесплатная точка входа не превращает окно отправки в 72 часа. Новое сообщение пользователя может сбросить 24-часовой срок, но срок бесплатной доставки остаётся отдельным.
Добавьте защиту перед отправкой
Ниже — пример прикладной модели на TypeScript, а не схема payload Meta. Разрешение и ожидаемая плата возвращаются отдельно.
type WindowState = {
serviceWindowExpiresAt: Date | null;
freeEntryExpiresAt: Date | null;
};
function evaluateWhatsAppSend(state: WindowState, now: Date) {
const serviceWindowOpen =
state.serviceWindowExpiresAt !== null && now < state.serviceWindowExpiresAt;
const freeEntryActive =
state.freeEntryExpiresAt !== null && now < state.freeEntryExpiresAt;
return {
maySendNonTemplate: serviceWindowOpen,
expectedDeliveryCharge: serviceWindowOpen && !freeEntryActive,
requiredPath: serviceWindowOpen ? "service" : "approved_template",
} as const;
}
Используйте результат как последний барьер, а не только подсказку в UI. Ответ, составленный в 10:00, может дождаться утверждения уже после закрытия окна. При получении задачи отправитель должен перечитать актуальное состояние и выбрать:
- Отправить нетиповой сервисный ответ, пока окно открыто.
- После закрытия перейти на одобренный шаблон, если он соответствует намерению.
- Остановить отправку и вернуть диалог оператору, если оба пути недопустимы.
Не преобразуйте свободный текст в шаблон незаметно. Категория шаблона, переменные и одобрение — отдельные контракты.
Не продлевайте окно неправильным событием
Окно сбрасывает только сообщение от пользователя. Отчёты о доставке, статусы, черновики оператора, внутренние заметки, повторы и echo исходящих сообщений его не продлевают.
Последовательность обработки:
- Проверить webhook провайдера до изменения состояния.
- Удалить дубликаты по стабильному ID сообщения или события.
- Убедиться, что это входящее сообщение пользователя, а не receipt или echo.
- Установить
service_window_expires_atна 24 часа после принятого времени сообщения. - Создать отдельный 72-часовой срок только для подходящего referral.
- Увеличить
state_versionи сохранить исходное событие для аудита. - Пересчитать оба срока непосредственно перед каждой отправкой.
Не прибавляйте 24 часа к старому сроку. Если пользователь написал в 09:00 и 12:00, новый срок — 12:00 следующего дня.
Проверьте границы очереди и порядок событий
Используйте фиксированные часы, чтобы воспроизводить секундные границы.
| Сценарий | Ожидаемый результат |
|---|---|
| Сообщение в 10:00, ответ в 09:59:59 следующего дня | Нетиповой ответ разрешён |
| Ответ ровно в 10:00 следующего дня | Окно закрыто |
| Новое сообщение в 09:50 следующего дня | Срок сброшен до 09:50 ещё через день |
| Ответ утверждён до срока, но взят из очереди после | Блокировка и повторная маршрутизация |
| Одно сообщение пользователя доставлено дважды | После дедупликации происходит один переход состояния |
| Старое сообщение пришло позже нового | Сохраняется более поздний срок, состояние не откатывается |
| Два worker одновременно взяли один ответ | Только один проходит проверку версии и отправляет |
В production сверяйте прогноз с официальными статусами и записями о цене. Руководство по учёту сервисных сообщений разделяет объём доставки и рыночную ставку. Выбор между Meta Business Agent и собственным AI описан в сравнении архитектур и тарификации.
Где подходит UnifyPort
Описанный автомат относится к официальной WhatsApp Business Platform. Неофициальный интерфейс UnifyPort — отдельный путь для обычных messaging account; он не предоставляет состояние окна Meta или классификацию Pricing Analytics.
На этом отдельном пути входящее сообщение WhatsApp приходит как нормализованное событие message.received. Если у webhook endpoint задан signing_secret, перед обработкой проверьте X-Device-Timestamp и X-Device-Signature по исходному телу запроса. Стандартные поддерживаемые ответы отправляются через POST /v1/messages. Контракты описаны в справочнике доставки и подписи webhook и события message.received.
Не передавайте событие UnifyPort в автомат официальной тарификации и не заявляйте, что его классифицировала Meta. При смешанной архитектуре храните transport или control_plane и ведите раздельные журналы.
Ограничения и компромиссы
Официальная Platform подходит для одобренных шаблонов, кампаний, атрибуции Click-to-WhatsApp, аналитики Meta и поддержки BSP. Только официальные записи определяют фактическую плату за официальную доставку.
Неофициальный интерфейс не утверждает шаблоны, не продлевает окно Meta, не предоставляет Pricing Analytics и не меняет правила WhatsApp. Он даёт другой способ подключить обычный messaging account и нормализовать события нескольких платформ. Обоим путям нужны идемпотентность, контроль конкурентных операций и аудит.
Тарифы и правила меняются. Перепроверьте официальную документацию перед 1 октября и не встраивайте плановую ставку в логику переходов.
FAQ
Какую временную метку должен использовать send guard?
Время последнего проверенного и принятого сообщения пользователя. Не используйте время получения webhook, создания задачи или таймер в интерфейсе оператора.
Могут ли события не по порядку сократить окно?
Не должны. Дедуплицируйте по стабильному ID и обновляйте срок с state_version только когда входящее сообщение новее текущей записи.
Что делать, если ответ в очереди истёк до отправки?
Остановить свободный текст и выполнить повторную маршрутизацию. Шаблон допустим только при точном совпадении намерения и наличии одобрения; иначе верните диалог оператору.
Можно ли автоматически превратить просроченный текст в шаблон?
Не делайте это без явного решения. Категория, переменные и одобрение шаблона — отдельный контракт, который нужно проверить.
Как не отправить ответ дважды из-за дубликата события?
Сохраняйте ID сообщения или события, а перед отправкой проверяйте ключ идемпотентности и state_version в транзакции или под блокировкой.
Следующий шаг
Сначала реализуйте безопасную входящую границу: изучите доставку и подпись webhook и проверьте, что дубликаты и события не по порядку не продлевают окно ошибочно.
Источники
Официальные источники проверены 27 июля 2026 года: