Repository navigation
fix(chatwoot): find existing conversation by contact and inbox - #2756
Open
kauecostax wants to merge 1 commit into
Open
kauecostax wants to merge 1 commit into
kauecostax wants to merge 1 commit into
Conversation
The contact conversations endpoint returns at most 20 conversations across all inboxes. When the same contact is present in more than 20 inboxes of an account (a WhatsApp group shared by many instances, or a person who talks to many of them), the conversation for the current inbox is often missing from that list, so createConversation opens a new one every time the cache expires. One group reached 14k open conversations, and contact updates that render all contact_inboxes started timing out in Chatwoot. Query the conversation filter by contact_id and inbox_id instead, in both createConversation and getOpenConversationByContact. Chatwoot versions whose filter does not accept contact_id answer 400/422; for those, fall back to the previous endpoint and remember it per Chatwoot URL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Reviewer's GuideThe PR fixes duplicate Chatwoot conversations by querying conversations directly by contact and inbox, while retaining compatibility with older Chatwoot versions through a per-URL capability cache and fallback to the legacy endpoint. Sequence diagram for inbox-scoped conversation lookupsequenceDiagram
participant Service as ChatwootService
participant Chatwoot as Chatwoot
participant Cache as contactFilterUnsupported
Service->>Cache: has(providerUrl)
alt filter supported
Service->>Chatwoot: conversations.filter(contact_id, inbox_id)
Chatwoot-->>Service: payload
else filter returns 400 or 422
Chatwoot-->>Service: error
Service->>Cache: add(providerUrl)
Service->>Chatwoot: contacts.listConversations(contactId)
Chatwoot-->>Service: payload
else filter has another error
Chatwoot-->>Service: error
Service->>Chatwoot: contacts.listConversations(contactId)
Chatwoot-->>Service: payload
end
Service-->>Service: find open conversation in inbox
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Contributor
There was a problem hiding this comment.
Hey - I've reviewed your changes and they look great!
Sourcery assessment
Needs a human reviewer. If the new filter misses an existing conversation, the integration may create a duplicate conversation record; reverting restores the old lookup but does not remove records already created. The likely impact is bounded and can be repaired in Chatwoot.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📋 Description
createConversationandgetOpenConversationByContactlook for the contact's conversation in the current inbox by callingGET /api/v1/accounts/:account_id/contacts/:id/conversationsand filtering the result byinbox_id. Chatwoot returns at most 20 conversations from that endpoint, across all inboxes, ordered by last activity (limit(20)inApi::V1::Accounts::Contacts::ConversationsController#index).When the same contact exists in more than 20 inboxes of one Chatwoot account, the conversation for the current inbox is often missing from those 20. Evolution then assumes there is no conversation and creates a new one. This happens on every cache miss (the conversation ID is cached for 30 minutes). Typical cases are a WhatsApp group that many connected numbers belong to, a person who talks to many of those numbers, and the
EvolutionAPIbot contact (123456) that posts connection notices in every inbox.In production, with about 50 instances connected to one Chatwoot account, one group contact accumulated more than 14,000 open conversations, and others had thousands. Besides cluttering the conversation lists, this made Chatwoot unusable. Updating such a contact (
PUT /contacts/:id, which Evolution sends when the group picture changes) renders everycontact_inboxin the response and went past Chatwoot's 60 s request timeout, holding the Rails threads for all accounts.This PR asks Chatwoot only for the conversations of that contact in that inbox, through
POST /api/v1/accounts/:account_id/conversations/filterwithcontact_idandinbox_id. The result has the same shape as before (payloadsorted by last activity), so the logic after the lookup is unchanged, includingreopenConversationandconversationPending.The
contact_idattribute was added to Chatwoot's conversation filter in chatwoot/chatwoot#14629 (June 2026). Older Chatwoot versions reject it with 400/422. In that case the service falls back to the previous endpoint and remembers it per Chatwoot URL, so it does not try the filter again on every message. Other errors (e.g. a timeout) fall back for that call only.🔗 Related Issue
No existing issue. The root cause is described above.
🧪 Type of Change
🧪 Testing
The same change was applied on top of
2.3.7and tested against Chatwoot v4.17 before running in production:GET /contacts/:id/conversationsfollowed byPOST /conversations).POST /conversations/filteronly). Text and audio messages verified.conversations/filterlookups.On
develop, the change compiles (tsc --noEmit) and passes ESLint.✅ Checklist
📝 Additional Notes
Duplicates already created are not removed by this PR. They stop growing once it is deployed.
🤖 Generated with Claude Code
Summary by Sourcery
Prevent duplicate Chatwoot conversations by using inbox-scoped contact lookups with compatibility fallback for older Chatwoot versions.
Bug Fixes:
Enhancements: