Fix: @lid problems, messages events and chatwoot integration errors
This Pull Request resolves critical stability issues and functional bugs in the Evolution API, focusing on Chatwoot integration robustness and support for modern WhatsApp identifiers (LID). The fixes ensure reliable message processing, prevent application crashes due to webhook errors, and normalize identifier handling across services, the fixes also ensure that messages update, delete and poll events work fine as good.
Fixes:
WhatsApp LID (Linked Identity Device) Support: Problem: Messages originating from users with the new @lid identifier format were failing in Typebot and general message sending. The codebase aggressively stripped the domain using .split('@')[0], causing the API to lose the valid JID required for these specific identifiers. Solution: Updated BaseChatbotService, TypebotService, and ChatwootService logic to preserve the full JID when necessary. Refactored getNumberFromRemoteJid to safely handle and clean complex JID formats (e.g., removing device suffixes like :27 while keeping the user ID intact).
Chatwoot Integration Stability (Duplicate Identifiers & Participant Errors): Problem: The Chatwoot integration suffered from two main issues: crashes due to participantAlt being undefined when parsing message keys, and "Identifier has already been taken" (422) errors during contact creation when a contact existed but wasn't initially found. Solution: Added safe access checks for participantAlt to prevent runtime errors. Implemented a fallback mechanism in createContact to recover the existing contact by identifier if creation fails due to duplication, ensuring the flow continues without error.
Webhook Crashes on Group Participant Updates: Problem: The GROUP_PARTICIPANTS_UPDATE webhook event caused the application to crash when processing participant IDs that were not strings (undefined or null) in the normalizePhoneNumber function. Solution: Added strict type coercion (String(id || '')) in WhatsappBaileysService to ensure input is always a string before processing, preventing the crash.
Unhandled Database Rejections in Chatwoot Import: Problem: The chatwoot_import feature caused unhandled promise rejections crashing the process when the separate Postgres connection was missing or failed. Solution: Wrapped the updateMessageSourceID and connection logic in proper try/catch blocks to gracefully handle database connectivity issues without bringing down the main application.
Messages update and delete handle Problem: A wrong verifying logic was stopping api to send webhook events of deleted, updated and poll votes. Solution: Enhanced and changed, cached message, update message content and poll vote verifications, now the cached message verification uses the message timestamp to ignore it, wich makes the webhook to send poll vote, message update and message delete events. The poll message type verification that makes poll update not work was removed.
Summary by Sourcery
Improve system stability and Chatwoot integration reliability by identifier handling, and error resilience.
Bug Fixes:
Enable full support for WhatsApp @lid identifiers in Typebot and Chatbot services by refining JID parsing. Fix participantAlt undefined errors and "Identifier has already been taken" loops in Chatwoot integration. Prevent GROUP_PARTICIPANTS_UPDATE webhook crashes by sanitizing participant ID inputs. Handle database connection failures gracefully in Chatwoot import services to prevent unhandled rejections. Summary by Sourcery Improve WhatsApp and Chatwoot integrations to better handle modern JID formats, avoid crashes, and gracefully recover from external and database errors. Restored message update, poll and message delete events to work again.
Enhancements:
Support WhatsApp LID and other JID formats end‑to‑end by preserving full remoteJid where necessary and normalizing only the domain/suffix parts. Add a Chatwoot helper to search contacts by identifier across multiple API shapes for more robust contact resolution.
Summary by Sourcery
Improve WhatsApp and Chatwoot integrations to better handle modern identifiers, prevent crashes, and restore message lifecycle webhooks.
Bug Fixes:
- Recover existing Chatwoot contacts when creation fails with 422 errors instead of failing the flow.
- Avoid runtime errors when resolving group participants by checking for participantAlt before accessing it.
- Prevent crashes on GROUP_PARTICIPANTS_UPDATE webhooks by safely normalizing potentially non-string participant IDs.
- Restore delivery/read, update, delete, and poll vote webhooks by refining message cache checks, status defaults, and update filtering logic.
- Avoid failures when Chatwoot import message source ID updates throw by wrapping them in error handling.
Enhancements:
- Support WhatsApp LID and other JID formats end-to-end by preserving full remoteJid in chatbot and Typebot services instead of stripping domains.
- Expose a Chatwoot helper to search contacts by identifier across multiple API endpoints and response shapes for more robust contact resolution.
- Improve duplicate message update detection by caching and comparing timestamps rather than simple presence flags.
Reviewer's Guide
Refactors WhatsApp identifier handling to support @lid JIDs end‑to‑end, hardens Chatwoot integration and imports against 422s and DB failures, and fixes webhook/update handling logic so updates, deletes, and participant events no longer crash or get dropped.
Sequence diagram for Chatwoot contact creation with 422 fallback
sequenceDiagram
participant WS as BaileysStartupService
participant CS as ChatwootService
participant CW as ChatwootAPI
WS->>CS: createContact(instance, jid)
CS->>CW: POST contacts (identifier = jid)
CW-->>CS: 422 Unprocessable Entity (identifier taken)
alt status 422 and jid defined
CS->>CS: logger.warn("creation failed (422)...")
CS->>CS: findContactByIdentifier(instance, jid)
CS->>CW: GET contacts/search?q=jid
CW-->>CS: existing contact payload or empty
alt contact found in search
CS->>CS: addLabelToContact(nameInbox, contactId)
CS-->>WS: existingContact
else not found in search
CS->>CW: POST contacts/filter (attribute_key = identifier)
CW-->>CS: contactByAttr payload or empty
alt contact found by attribute
CS-->>WS: contactByAttr[0]
else contact not found anywhere
CS->>CS: logger.error("Error creating contact")
CS-->>WS: null
end
end
else non-422 error
CS->>CS: logger.error("Error creating contact")
CS-->>WS: null
end
Sequence diagram for chatbot media/text sending with preserved remoteJid
sequenceDiagram
actor U as EndUser
participant WA as WhatsApp
participant BSvc as BaseChatbotService
participant TSvc as TypebotService
participant Inst as InstanceAdapter
U-->>WA: sends message to bot (may use @lid JID)
WA-->>TSvc: webhook with session.remoteJid
alt Typebot sends image/video/audio
TSvc->>Inst: mediaMessage or audioWhatsapp
activate TSvc
TSvc-->>Inst: payload { number = session.remoteJid, ... }
deactivate TSvc
end
alt Typebot sends list or buttons
TSvc->>Inst: processListMessage or processButtonMessage
TSvc->>Inst: payload { number = remoteJid, ... }
end
alt BaseChatbotService sends generic media
BSvc->>Inst: audioWhatsapp or mediaMessage
BSvc-->>Inst: payload { number = remoteJid, ... }
end
alt BaseChatbotService sends text
BSvc->>Inst: textMessage
BSvc-->>Inst: payload { number = remoteJid, ... }
end
Inst-->>WA: outgoing WhatsApp message
WA-->>U: bot response delivered
Class diagram for updated identifier handling and Chatwoot integration
classDiagram
class ChatwootService {
+createContact(instance: InstanceDto, jid: string) Promise<any>
+findContactByIdentifier(instance: InstanceDto, identifier: string) Promise<any>
+findContact(instance: InstanceDto, phoneNumber: string) Promise<any>
+getNumberFromRemoteJid(remoteJid: string) string
+handleUpsertMessage(instance: InstanceDto, key: any, body: any) Promise<void>
+handleImportHistory(instance: InstanceDto, key: any, chatwootMessageIds: any) Promise<void>
}
class BaileysStartupService {
+handleMessagesUpsert(upsert: any, type: string) Promise<void>
+handleMessagesUpdate(update: any, key: any) Promise<void>
+normalizePhoneNumber(id: string~or~any) string
-baileysCache: BaileysCache
-instanceId: string
-instance: any
-configService: ConfigService
-localChatwoot: any
}
class BaseChatbotService {
<<abstract>>
+sendMediaMessage(instance: any, remoteJid: string, mediaType: string, url: string, altText: string, settings: any) Promise<void>
+sendTextMessage(instance: any, remoteJid: string, message: string, linkPreview: boolean, settings: any) Promise<void>
}
class TypebotService {
+processListMessage(instance: any, formattedText: string, remoteJid: string) Promise<void>
+processButtonMessage(instance: any, formattedText: string, remoteJid: string) Promise<void>
+handleImageMessage(instance: any, session: any, message: any, settings: any) Promise<void>
+handleVideoMessage(instance: any, session: any, message: any, settings: any) Promise<void>
+handleAudioMessage(instance: any, session: any, message: any, settings: any) Promise<void>
}
class ChatwootImport {
+updateMessageSourceID(chatwootMessageId: string, sourceId: string) Promise<void>
}
class BaileysCache {
+get(key: string) Promise<any>
+set(key: string, value: any, ttlSeconds: number) Promise<void>
}
class ConfigService {
+get~Chatwoot~(key: string) Chatwoot
}
class Chatwoot {
+ENABLED: boolean
}
ChatwootService --> ChatwootImport : uses
ChatwootService --> ConfigService : uses
BaileysStartupService --> BaileysCache : uses
BaileysStartupService --> ConfigService : uses
TypebotService --|> BaseChatbotService
File-Level Changes
| Change | Details | Files |
|---|---|---|
| Improve Chatwoot contact creation robustness and add identifier-based contact lookup helpers. |
|
src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts |
| Harden group participant handling and WhatsApp JID normalization for webhooks and Chatwoot integration, including LID support. |
|
src/api/integrations/chatbot/chatwoot/services/chatwoot.service.tssrc/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts |
| Fix Baileys message/update webhook filtering and caching so updates, deletions, and polls are emitted correctly without deadlocks. |
|
src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts |
| Propagate full remoteJid (including @lid) through chatbot services instead of stripping domain parts. |
|
src/api/integrations/chatbot/base-chatbot.service.tssrc/api/integrations/chatbot/typebot/services/typebot.service.ts |
Possibly linked issues
- #[Bug] Typebot fails to send messages to users with LID - BadRequestException jidOptions.exists false: The PR updates BaseChatbot/Typebot to preserve full remoteJid, correctly supporting LID users and fixing the reported bug.
Tips and commands
Interacting with Sourcery
-
Trigger a new review: Comment
@sourcery-ai reviewon the pull request. - Continue discussions: Reply directly to Sourcery's review comments.
-
Generate a GitHub issue from a review comment: Ask Sourcery to create an
issue from a review comment by replying to it. You can also reply to a
review comment with
@sourcery-ai issueto create an issue from it. -
Generate a pull request title: Write
@sourcery-aianywhere in the pull request title to generate a title at any time. You can also comment@sourcery-ai titleon the pull request to (re-)generate the title at any time. -
Generate a pull request summary: Write
@sourcery-ai summaryanywhere in the pull request body to generate a PR summary at any time exactly where you want it. You can also comment@sourcery-ai summaryon the pull request to (re-)generate the summary at any time. -
Generate reviewer's guide: Comment
@sourcery-ai guideon the pull request to (re-)generate the reviewer's guide at any time. -
Resolve all Sourcery comments: Comment
@sourcery-ai resolveon the pull request to resolve all Sourcery comments. Useful if you've already addressed all the comments and don't want to see them anymore. -
Dismiss all Sourcery reviews: Comment
@sourcery-ai dismisson the pull request to dismiss all existing Sourcery reviews. Especially useful if you want to start fresh with a new review - don't forget to comment@sourcery-ai reviewto trigger a new review!
Customizing Your Experience
Access your dashboard to:
- Enable or disable review features such as the Sourcery-generated pull request summary, the reviewer's guide, and others.
- Change the review language.
- Add, remove or edit custom review instructions.
- Adjust other review settings.
Getting Help
- Contact our support team for questions or feedback.
- Visit our documentation for detailed guides and information.
- Keep in touch with the Sourcery team by following us on X/Twitter, LinkedIn or GitHub.
top, tenho visto relamações aumentando sobre msgs não aparecendo no chatwoot devido essas alterações do identificador lid