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

Как защитить ответы в очереди 24-часовым send guard WhatsApp

Ответ WhatsApp в очереди может пересечь 24-часовую границу во время согласования, повтора или ожидания worker. Надёжный send guard перед фактической отправкой заново читает серверное состояние, вычисляет срок по последнему проверенному сообщению пользователя и блокирует просроченный свободный текст. Категории и тарифы разобраны в дереве решений service vs utility; здесь рассматривается именно защита от ошибочной отправки.

Главное

  • Храните два срока и монотонно растущий state_version, а не один логический флаг.
  • Сбрасывать 24-часовое окно может только проверенное и дедуплицированное входящее сообщение пользователя.
  • После получения задачи worker перечитывает состояние в той же транзакции или под той же блокировкой.
  • Просроченный черновик останавливается и маршрутизируется заново, а не превращается в шаблон без подтверждения.
  • Проверьте дубликаты, события не по порядку, конкурирующие worker и секундные границы.

Постройте send guard вокруг ответов в очереди

Официальная страница тарифов Business Platform указывает, что сообщение пользователя открывает или сбрасывает 24-часовое окно. В реализации эта граница разрешения становится финальным условием отправки. Изменения категорий и тарифов октября 2026 года отдельно описаны в существующем руководстве и здесь не повторяются.

Для каждой задачи в очереди отправитель отвечает на три практических вопроса:

  1. Прочитана ли последняя версия состояния? Старый worker не должен перезаписывать обновлённый срок.
  2. Открыто ли окно в момент фактической отправки? Нельзя повторно использовать решение, принятое при создании или согласовании черновика.
  3. Разрешён ли выбранный путь? После закрытия окна допустим только действительно подходящий одобренный шаблон; иначе задачу следует остановить и вернуть оператору.

Храните два таймера, а не один статус

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

ПолеЧто запускает или сбрасываетЧто контролирует
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, может дождаться утверждения уже после закрытия окна. При получении задачи отправитель должен перечитать актуальное состояние и выбрать:

  1. Отправить нетиповой сервисный ответ, пока окно открыто.
  2. После закрытия перейти на одобренный шаблон, если он соответствует намерению.
  3. Остановить отправку и вернуть диалог оператору, если оба пути недопустимы.

Не преобразуйте свободный текст в шаблон незаметно. Категория шаблона, переменные и одобрение — отдельные контракты.

Не продлевайте окно неправильным событием

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

Последовательность обработки:

  1. Проверить webhook провайдера до изменения состояния.
  2. Удалить дубликаты по стабильному ID сообщения или события.
  3. Убедиться, что это входящее сообщение пользователя, а не receipt или echo.
  4. Установить service_window_expires_at на 24 часа после принятого времени сообщения.
  5. Создать отдельный 72-часовой срок только для подходящего referral.
  6. Увеличить state_version и сохранить исходное событие для аудита.
  7. Пересчитать оба срока непосредственно перед каждой отправкой.

Не прибавляйте 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 года: