From 166a41c31c800da8b24b54f99548e5e77098cf25 Mon Sep 17 00:00:00 2001 From: Muhsin Keloth Date: Wed, 22 Jul 2026 12:40:28 +0400 Subject: [PATCH] fix(whatsapp): prevent invalid automation sends outside reply window (#15113) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WhatsApp automations now fail locally when they attempt to send a free-form message after the 24-hour customer service window has closed. This avoids sending an invalid template request to Meta and gives users a clear, actionable error instead of “Template not found or invalid template name.” Template messages continue to be sent whenever template parameters are present. Free-form messages continue to be sent normally while the conversation is replyable. Fixes https://linear.app/chatwoot/issue/PLA-183/prevent-whatsapp-automations-outside-the-24-hour-window-from-producing ### How to reproduce 1. Create a WhatsApp automation that sends a message without template parameters. 2. Trigger it on a conversation whose 24-hour customer service window is closed. 3. Observe that the message previously reached the template send path and failed with a misleading provider error. ### How to test 1. Trigger an automation with template parameters and confirm it sends as a template message. 2. Trigger an automation without template parameters inside the 24-hour window and confirm it sends as a free-form message. 3. Trigger an automation without template parameters outside the 24-hour window and confirm it fails locally with a clear error and makes no request to Meta. ### Things to know This changes only the invalid closed-window, no-template path. Existing template and in-window message behavior remains unchanged. --------- Co-authored-by: Muhsin <12408980+muhsin-k@users.noreply.github.com> --- app/services/whatsapp/send_on_whatsapp_service.rb | 10 ++++------ config/locales/en.yml | 1 + .../whatsapp/send_on_whatsapp_service_spec.rb | 15 +++++++++++++++ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/app/services/whatsapp/send_on_whatsapp_service.rb b/app/services/whatsapp/send_on_whatsapp_service.rb index 20419c0cd..b8de35d1c 100644 --- a/app/services/whatsapp/send_on_whatsapp_service.rb +++ b/app/services/whatsapp/send_on_whatsapp_service.rb @@ -6,12 +6,10 @@ class Whatsapp::SendOnWhatsappService < Base::SendOnChannelService end def perform_reply - should_send_template_message = template_params.present? || !message.conversation.can_reply? - if should_send_template_message - send_template_message - else - send_session_message - end + return send_template_message if template_params.present? + return send_session_message if message.conversation.can_reply? + + message.update!(status: :failed, external_error: I18n.t('errors.whatsapp.message_outside_messaging_window')) end def send_template_message diff --git a/config/locales/en.yml b/config/locales/en.yml index 735d52205..1efae55e1 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -154,6 +154,7 @@ en: invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.' phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.' phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists' + message_outside_messaging_window: 'Message not sent because the WhatsApp 24-hour customer service window is closed and no template parameters were provided. Send an approved template message instead.' reauthorization: generic: 'Failed to reauthorize WhatsApp. Please try again.' not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.' diff --git a/spec/services/whatsapp/send_on_whatsapp_service_spec.rb b/spec/services/whatsapp/send_on_whatsapp_service_spec.rb index c27295b3e..850685718 100644 --- a/spec/services/whatsapp/send_on_whatsapp_service_spec.rb +++ b/spec/services/whatsapp/send_on_whatsapp_service_spec.rb @@ -72,6 +72,21 @@ describe Whatsapp::SendOnWhatsappService do expect(message.reload.source_id).to eq('123456789') end + it 'fails a free-form message without contacting the provider when outside the 24 hour limit' do + create(:message, message_type: :incoming, content: 'test', created_at: 25.hours.ago, + conversation: conversation, account: conversation.account) + message = create(:message, message_type: :outgoing, content: 'test', + conversation: conversation, account: conversation.account) + + expect(Whatsapp::TemplateProcessorService).not_to receive(:new) + + described_class.new(message: message).perform + + expect(message.reload.status).to eq('failed') + expect(message.external_error).to eq(I18n.t('errors.whatsapp.message_outside_messaging_window')) + expect(a_request(:post, 'https://waba.360dialog.io/v1/messages')).not_to have_been_made + end + it 'marks message as failed when template name is blank' do processor = instance_double(Whatsapp::TemplateProcessorService) allow(Whatsapp::TemplateProcessorService).to receive(:new).and_return(processor)