# Pull Request Template
## Description
This PR adds support for WhatsApp campaigns to Chatwoot, allowing
businesses to reach their customers through WhatsApp. The implementation
includes backend support for WhatsApp template messages, frontend UI
components, and integration with the existing campaign system.
Fixes#8465
Fixes https://linear.app/chatwoot/issue/CW-3390/whatsapp-campaigns
## Type of change
- [x] New feature (non-breaking change which adds functionality)
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] Breaking change (fix or feature that would cause existing
functionality not to work as expected)
- [ ] This change requires a documentation update
## How Has This Been Tested?
- Tested WhatsApp campaign creation UI flow
- Verified backend API endpoints for campaign creation
- Tested campaign service integration with WhatsApp templates
- Validated proper filtering of WhatsApp campaigns in the store
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
## What we have changed:
We have added support for WhatsApp campaigns as requested in the
discussion.
Ref: https://github.com/orgs/chatwoot/discussions/8465
**Note:** This implementation doesn't exactly match the maintainer's
specification and variable support is missing. This is an initial
implementation that provides the core WhatsApp campaign functionality.
### Changes included:
**Backend:**
- Added `template_params` column to campaigns table (migration + schema)
- Created `Whatsapp::OneoffCampaignService` for WhatsApp campaign
execution
- Updated campaign model to support WhatsApp inbox types
- Added template_params support to campaign controller and API
**Frontend:**
- Added WhatsApp campaign page, dialog, and form components
- Updated campaign store to filter WhatsApp campaigns separately
- Added WhatsApp-specific routes and empty state
- Updated i18n translations for WhatsApp campaigns
- Modified sidebar to include WhatsApp campaigns navigation
This provides a foundation for WhatsApp campaigns that can be extended
with variable support and other enhancements in future iterations.
---------
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
## Description
This PR introduces WhatsApp Embedded Signup functionality, enabling
users to connect their WhatsApp Business accounts through Meta's
streamlined OAuth flow without manual webhook configuration. This
significantly improves the user experience by automating the entire
setup process.
**Key Features:**
- Embedded signup flow using Facebook SDK and Meta's OAuth 2.0
- Automatic webhook registration and phone number configuration
- Enhanced provider selection UI with card-based design
- Real-time progress tracking during signup process
- Comprehensive error handling and user feedback
## Required Configuration
The following environment variables must be configured by administrators
before this feature can be used:
Super Admin Configuration (via
super_admin/app_config?config=whatsapp_embedded)
- `WHATSAPP_APP_ID`: The Facebook App ID for WhatsApp Business API
integration
- `WHATSAPP_CONFIGURATION_ID`: The Configuration ID for WhatsApp
Embedded Signup flow (obtained from Meta Developer Portal)
- `WHATSAPP_APP_SECRET`: The App Secret for WhatsApp Embedded Signup
flow (required for token exchange)

## How Has This Been Tested?
#### Backend Tests (RSpec):
- Authentication validation for embedded signup endpoints
- Authorization code validation and error handling
- Missing business parameter validation
- Proper response format for configuration endpoint
- Unauthorized access prevention
#### Manual Test Cases:
- Complete embedded signup flow (happy path)
- Provider selection UI navigation
- Facebook authentication popup handling
- Error scenarios (cancelled auth, invalid business data, API failures)
- Configuration presence/absence behavior
## Related Screenshots:





Fixes
https://linear.app/chatwoot/issue/CW-2131/spec-for-whatsapp-cloud-channels-sign-in-with-facebook
---------
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: iamsivin <iamsivin@gmail.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: Sojan Jose <sojan@pepalo.com>
Added conversation_status, assignee_id, team_id, and priority to the
message_created event to allow users to build automations based on
conversation details. Also introduced a new open_conversation action.
---------
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
- Add `actor=app` parameter to Linear OAuth authorization URL for
consistent app-level authorization
https://linear.app/developers/oauth-actor-authorization
- Implement user attribution for Linear issue creation and linking using
`createAsUser` and `displayIconUrl` parameters
- Enhance Linear integration to properly attribute actions to specific
Chatwoot agents
**Note**
- The displayIconUrl parameter is being sent correctly to Linear's
GraphQL API (verified through testing), but there is an issues with icon
is not attaching properly.
- We might need to disconnect the integration connect again.
This PR adds a composite index (:account_id, :content_type, :created_at)
on the table messages.
This index is added as a temporary fix for performance issues in the
CSAT responses controller where we query messages with account_id,
content_type and created_at. The current implementation
(account.message.input_csat.count) times out with millions of messages.
TODO: Create a dedicated csat_survey table and add entries when surveys
are sent, then query this table instead of the entire messages table for
better performance.
This PR fixes the reply time calculation for reopened conversations.
Previously, when a customer sent a message to reopen a resolved
conversation, the reply time metric would be calculated incorrectly
because the `waiting_since` timestamp was not properly set before the
reply event was dispatched. This would create a case where you'd have
reporting events like the following
```
[[33955732, "reply_time", 19.0],
[33955847, "reply_time", 24.0],
[33955666, "reply_time", 89.0],
[33955530, "conversation_bot_handoff", 4.0],
[33955567, "first_response", 42.0],
[33955745, "reply_time", 21.0],
[33955934, "reply_time", 49.0],
[33955906, "reply_time", 121.0],
[33987938, "conversation_resolved", 26285.0],
[35571005, "reply_time", 985492.0]]
```
Note the `reply_time` after `conversation_resolved`
The fix ensures that `waiting_since` is correctly updated when
conversations are reopened, either through incoming messages or manual
status changes, resulting in accurate reply time metrics that measure
only the time from the customer's new message to the agent's response.
## Type of change
Please delete options that are not relevant.
- [x] Bug fix (non-breaking change which fixes an issue)
## How Has This Been Tested?
The changes have been tested with comprehensive specs that verify:
1. **Reply time calculation after conversation reopening** - Ensures
correct timestamps are used when calculating reply times for reopened
conversations
2. **Waiting since updates on status changes** - Verifies that
`waiting_since` is properly set when conversation status changes from
resolved to open
3. **Test the happy path** - Happy path is tested to ensure the
`reply_time` and `first_response_time` is correctly calculated
Test instructions:
1. Create a conversation with the last message from a customer and
resolve it
2. Have an agent reopen it and reply to it
4. When an agent replies, verify that the agent reply_time event is not
created for this message
To fix any existing data, I've written a small script:
https://gist.github.com/scmmishra/fdf458863f2d971978327bbfd5232d0c
---------
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
* feat: add received messages handling in WhatsApp services
* feat: ensure received messages are processed in the conversation
* tests: add received messages specs
* tests: add spec for call provider received_messages after save incoming message
* test: add spec to prevent calling received_messages for outgoing messages
* feat: add received_messages to error handling methods
* test: add spec for sending received messages request in WhatsappBaileysService
* fix: update fromMe flag in WhatsappBaileysService
* test: add spec to verify received_messages is not called for protocol messages
* test: improve received_messages stub
---------
Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com>
Added support for Telegram Business bots. Telegram webhooks from such bots include the business_message field, which we transform into a standard message for Chatwoot. This PR also modifies how we handle replies, attachments, and image uploads when working with Telegram Business bots.
demo: https://drive.google.com/file/d/1Yz82wXBVRtb-mxjXogkUju4hlJbt3qyh/view?usp=sharing&t=4Fixes#10181
* fix: fill whatsapp provider url with value from inbox provider config
* chore: compact blank on setup channel provider
* fix: deadlock on `reconnecting` state
<img width="1240" alt="Screenshot 2025-06-05 at 12 39 04 AM"
src="https://github.com/user-attachments/assets/0071cd23-38c3-4638-946e-f1fbd11ec845"
/>
## Changes
Give the admins an option to delete conversation via the context menu
- enable conversation deletion in routes and controller
- expose delete API on conversations
- add delete option in conversation context menu and integrate with card
and list
- implement store action and mutation for delete
- update i18n with new strings
fixes: https://github.com/chatwoot/chatwoot/issues/947
---------
Co-authored-by: iamsivin <iamsivin@gmail.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: Pranav <pranavrajs@gmail.com>
* feat: add store in additional_attributes to conversation model
* feat: set default mark_as_read to true in additional_attributes for conversation params
* fix: remove mark_as_read from additional_attributes in conversation
* refactor: move message read logic to mark_messages_as_read method in ConversationsController
* feat: add 'Mark messages as read' option to WhatsApp channel settings
* feat: add 'mark_as_read' option in factorie for WhatsApp channel
* feat: integrate Checkbox component for 'mark as read' option in WhatsApp settings
* fix: ensure 'mark_as_read' option is included in channel creation payload
* feat: add 'Mark as read' settings for WhatsApp inbox, including UI and state management
* chore: remove redundant content update test from IncomingMessageBaileysService spec
* feat: update 'Mark as read' label to 'Read receipts' and replace Checkbox with Switch component in WhatsApp settings
* fix: handle potential nil value for 'mark_as_read' in provider config
* feat: refactor provider config to streamline channel creation with 'mark_as_read' option
* feat: add test for MESSAGE_READ event dispatch in update_last_seen action
* fix: update subheader for 'Mark as read' setting to read receipt behavior in WhatsApp
* feat: update mark_messages_as_read behavior to handle false value in provider config
* chore: update label for 'Mark as read' option
* feat: update update_last_seen to send WhatsApp read receipt for WhatsApp channels
* test: remove MESSAGE_READ event dispatch tests in wrong file
* feat: enhance update_last_seen behavior for WhatsApp channel to conditionally dispatch messages.read event
* feat: update update_last_seen to dispatch messages.read event
* test: refactor update_last_seen tests
* chore: refactor to ensure provider_service responds to read_messages before ensure the mark_as_read provider config
* test: enhance #read_messages with provider config mark_as_read expected behaviors
* chore: clarify test names and remove useless expect
---------
Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com>
…on (#11584)"
This reverts commit b5ebc47637.
# Pull Request Template
## Description
Please include a summary of the change and issue(s) fixed. Also, mention
relevant motivation, context, and any dependencies that this change
requires.
Fixes # (issue)
## Type of change
Please delete options that are not relevant.
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality not to work as expected)
- [ ] This change requires a documentation update
## How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide
instructions so we can reproduce. Please also list any relevant details
for your test configuration.
## Checklist:
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
Fixes https://github.com/chatwoot/chatwoot/issues/11569
## Problem
On platforms like WhatsApp and Facebook Messenger, customers cannot
reply to messages after 24 hours (or other channel-specific messaging
windows). Despite this limitation, the system continued sending CSAT
surveys to customers outside their messaging window, making it
impossible for them to respond.
## Solution
Added a check for `conversation.can_reply?` in the
`should_send_csat_survey?` method. This leverages the existing
`MessageWindowService` which already handles all channel-specific
messaging window logic.
* fix: correct structure of lastMessages in message content
* fix: update send_message to store external_created_at timestamp with result from request
* fix: filter incoming messages for unread conversation logic
* fix: improve extraction of message timestamp in send_message method
* feat: enhance message timestamp extraction and update logic in send_message method
* refactor: send_message to improve error handling and update external_created_at timestamp
* chore: move message timestamp extraction to helper
* fix: use message timestamp extract on incoming
* fix: update unread_conversation to handle last message correctly for Baileys provider
---------
Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com>
* feat: add MESSAGES_UNREAD event and implement unread action in ConversationsController
* feat: rename MESSAGES_UNREAD event to CONVERSATION_UNREAD and update unread action in ConversationsController
* feat: implement send_unread_conversation method and update conversation_unread event handling
* feat: add test for dispatching conversation.unread event in ConversationsController
* feat: add conversation_unread event handling in ChannelListener
* feat: add send_unread_conversation method and corresponding tests in Whatsapp channel
* feat: add logging for nil last_message in send_unread_conversation method
* feat: add send_unread_conversation to error handling methods
* feat: implement send_unread_conversation method with logging for nil last_message
* fix: add nil check and logging for last_message in send_unread_conversation method
* fix: update conversation_unread method to call unread_conversation instead of send_unread_conversation
* refactor: rename send_unread_conversation to unread_conversation and update method implementation
* refactor: rename send_unread_conversation to send_unread_messages and update implementation to handle multiple messages
* refactor: rename send_read_messages to read_messages and send_unread_messages to unread_message for clarity
* refactor: rename send_read_messages to read_messages and send_unread_messages to unread_message for clarity
* refactor: rename send_read_messages to read_messages for consistency
This PR will prevent saving user preferences and online status when impersonating. Previously, these settings could be updated during impersonation, causing the user to see a different view or UI settings.
Fixes https://linear.app/chatwoot/issue/CW-4163/impersonation-improvements
We made so many improvements for CSAT via https://github.com/chatwoot/chatwoot/pull/11485. However, we missed showing message content in the dashboard for CSAT URLs created in non-widget inboxes. This PR fixes the issue by ensuring that CSAT-configured messages are passed along with CSAT responses, otherwise defaulting to the translation.
Show captain messages under the name of the assistant which generated
the message.
- Add support for `Captain::Assistant` sender type
- Add push_event_data for captain_assistants
- Add activity message handler for captain_assistants
- Update UI to show captain messages under the name of the assistant
- Fix the issue where openAI errors when image is sent
- Add support for custom name of the assistant
---------
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
# Pull Request Template
## Description
This PR introduces basic customization options for the CSAT survey:
* **Display Type**: Option to use star ratings instead of emojis.
* **Message Text**: Customize the survey message (up to 200 characters).
* **Survey Rules**: Send surveys based on labels — trigger when a
conversation has or doesn't have a specific label.
Fixes
https://linear.app/chatwoot/document/improve-csat-responses-a61cf30e054e
## Type of change
- [x] New feature (non-breaking change which adds functionality)
## How Has This Been Tested?
### Loom videos
**Website Channel (Widget)**
https://www.loom.com/share/7f47836cde7940ae9d17b7997d060a18?sid=aad2ad0a-140a-4a09-8829-e01fa2e102c5
**Email Channel (Survey link)**
https://www.loom.com/share/e92f4c4c0f73417ba300a25885e093ce?sid=4bb006f0-1c2a-4352-a232-8bf684e3d757
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
---------
Co-authored-by: Pranav <pranavrajs@gmail.com>
This PR introduces support for optionally exposing more data during LLM
function calls. This will be useful as we expand Copilot’s capabilities.
Changes included:
- Add support for ArticleLlmFormatter
- Add missing specs for ContactLLMFormatter and ArticleLLMFormatter
- Add additional spec for ConversationLLMFormatter based on config
- Currently Chatwoot manages Twilio Inbox creation in a separate
controller , We want to move this to inboxes api so that we have a
unified API for inbox related changes
---------
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Added support for typing events in webhooks. Two new events are now
available: `conversation_typing_on` and `conversation_typing_off`.
<img width="746" alt="Screenshot 2025-05-08 at 4 50 24 PM"
src="https://github.com/user-attachments/assets/62da7b38-de0f-42c5-84f4-066e653da331"
/>
---------
Co-authored-by: Pranav <pranav@chatwoot.com>
Co-authored-by: Pranav <pranavrajs@gmail.com>
* feat: implement send_read_messages method for WhatsApp channel
* feat: implement messages_read event handling and dispatch for conversations
* feat: enhance messages_read handling to include last_seen_at and conversation context
* feat: update last_seen handling to reference agent_last_seen_at for messages read event
* chore: fix rebase
* feat: update error handling
* feat: update send_read_messages to mark received messages as not sent by the user
* test: controller spec
* test: channel listener
* test: channel and provider
---------
Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com>
### Summary
- Converts conversation auto-resolution duration from days to minutes
for more
granular control
- Updates validation to allow values from 10 minutes (minimum) to 999
days (maximum)
- Implements smart messaging to show appropriate time units in activity
messages
### Changes
- Created migration to convert existing durations from days to minutes
(x1440)
- Updated conversation resolver to use minutes instead of days
- Added dynamic translation key selection based on duration value
- Updated related specs and documentation
- Added support for displaying durations in days, hours, or minutes
based on value
### Test plan
- Verify account validation accepts new minute-based ranges
- Confirm existing account settings are correctly migrated
- Test auto-resolution works properly with minute values
- Ensure proper time unit display in activity messages
---------
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>