A WhatsApp message from a prospect looks like the simplest input a business system can get: a phone number, a name and a few lines of text. In practice it is a sales enquiry, a support request and a customer record at once, and most teams handle it on a phone or in a shared inbox that has nothing to do with their CRM or helpdesk. This post walks through how DexVee's WhatsApp intake pipeline is designed, and why one inbound message produces several linked records.
The delivery path
DexVee receives WhatsApp through Twilio, which acts as the WhatsApp Business Solution Provider (BSP) for the business number. Twilio delivers each customer message to a DexVee webhook, and the request's provider signature is verified before anything else happens. Anything that fails verification is rejected and never reaches the CRM.
A message that opens a new enquiry is handed to a channel-neutral intake service. Every messaging source reduces its payload to the same small shape (sender, text, a stable event id) before touching CRM data, so the rules for contacts, leads, activities and tickets live in one place. A WhatsApp enquiry looks the same downstream as a website-form one.
Never count the same message twice
Messaging providers retry webhooks they think have failed. A naive handler opens a fresh ticket on every retry. The pipeline guards against this twice:
- The message log records every message with the provider's unique message id. A delivery whose id is already recorded stops there and returns the existing ticket.
- The lead stores the same id as its source reference, so a replay after a partial failure re-attaches to the open lead it already created instead of opening a second one.
Work out who is writing
A WhatsApp account is tied to a phone number, so the sender's number is the identity. The catch is formatting: the provider sends a prefixed number with a country code, while CRM records hold whatever someone typed, with spaces, dashes, or no country code. A plain string comparison would almost never match, and every message from an existing customer would create a duplicate.
So the lookup compares the last ten digits of the sender's number against the phone and mobile fields of active contacts in the same organisation, with formatting stripped from both sides. If several match, the oldest contact wins. Only when nothing matches does the pipeline fall back to the standard find-or-create step, building a new contact from the WhatsApp profile name and the normalised number.
Why one message produces four linked records
A message that opens a new enquiry fans out into four records, each linked to the others:
| Record | What it holds | Why it exists |
|---|---|---|
| Contact | The person, matched or newly created | One identity across sales, support and billing |
| Lead | Source WHATSAPP, the message in its notes, the number on file | The enquiry enters the pipeline with an owner |
| Activity | A WhatsApp-message entry on the lead's timeline | The lead's history shows the conversation |
| Helpdesk ticket | Channel WhatsApp, linked to the contact and lead | Someone is accountable for answering |
Each record serves a different team. Sales needs a lead with an owner and a reportable source. Support needs a ticket with an assignee and a thread. Management needs both tied to one contact, so the person who asked about pricing on Monday and reported a fault on Thursday is one customer, not two strangers.
A few details matter more than they first appear to:
- Source is the channel, not the vendor. The provider is recorded separately as attribution, so changing BSP later wouldn't split lead-source reports into several buckets that all mean "WhatsApp".
- Repeat enquiries reuse the open lead. The new message is appended to its notes under a timestamped header.
- Human corrections win. The lead's mobile and email are filled only when blank, so a corrected number is never overwritten by a later message.
- Every lead gets an owner. Assignment follows the normal lead rules: the contact's account manager, else a territory owner if the location is known, else a default administrator. The owner gets an in-app notification.
- The ticket inherits the account. When the contact belongs to a known company, the ticket links to that account, so work orders and invoices raised from it later stay with the right customer.
- It's audited. Each intake writes an audit-log entry noting the channel and whether the lead was new.
Conversations, not messages
Customers send five messages in a row, then a photo, then "any update?" an hour later. One ticket per message would bury the helpdesk, so the pipeline threads by conversation:
- The contact has an open WhatsApp ticket: the message joins that ticket's thread and is logged as an activity on the contact's lead. No new lead or ticket is created.
- No open ticket: the full intake runs, even for an existing customer with an older lead.
A closed, completed or cancelled ticket counts as finished, so a later message starts a fresh enquiry rather than reopening an old thread. The shared intake service applies the same open-ticket check, so the rule holds for any channel that uses it.
Media: stored, not linked
Customers send photos of faulty equipment, error screenshots and purchase-order PDFs. The provider's link to each file needs the account's credentials to open and expires after the provider's retention window, so saving the raw link would give an agent something that fails today and disappears later. Instead, DexVee downloads each attachment when the message arrives:
- Downloads are only made from the provider's own media host. Any other address is ignored.
- Each file goes into DexVee's own document storage and is attached to the ticket, and to the lead when the message opened a new enquiry. The message log points to the stored copy.
- A media-only message gets a readable placeholder, so the ticket subject and lead notes aren't blank.
- Each file is best-effort. A failed download is logged and skipped, and never costs you the lead or the ticket.
- Because WhatsApp media often contains customer documents, it is visible only to super administrators and the ticket's assignee.
Replying: who can, and from which number
Answering matters as much as capture, without turning the company's WhatsApp number into something anyone can use for anything. The reply rules are deliberately tight:
- A super administrator can send freely.
- Everyone else can send only as a reply on a ticket. An administrator must be that ticket's assignee. Other users are checked against the rule that decides whether they can open the ticket, so messaging a customer never exceeds seeing the conversation.
- The recipient must be a number already attached to the ticket, so a reply can't be redirected to an unrelated number.
Replies go out from whichever business number the customer messaged, continuing the same WhatsApp conversation. WhatsApp allows free-form replies only within 24 hours of the customer's last message; outside that window DexVee can send a pre-approved message template. Delivery status comes back from the provider, and if a reply isn't delivered the sender gets a plain-language reason (such as "outside the 24-hour window") rather than a message that looks sent but never arrived. Each reply is also written to the ticket thread and the lead's timeline, so both sides of the conversation are on record.
Where the history lives
Every inbound and outbound message lands in one message log, browsable under Helpdesk > Messages. Each row shows direction, body, media, delivery status, and the linked contact and ticket, filterable by channel (WhatsApp or SMS), direction, contact, ticket or phone number.
The list is filtered by row, in line with the reply rules. A new, unassigned conversation is visible only to super administrators. Everyone else sees a message once its ticket is assigned to them, or if they sent it themselves.
A worked example
Hypothetical, to show the flow. Not a real customer.
A facilities manager at a fictional logistics firm messages: "Our warehouse Wi-Fi keeps dropping, can someone take a look?" She's already a contact, saved months ago with spaces in her number and no country code.
- The signature checks out and the message id is new.
- The last-ten-digit match finds her existing contact. No duplicate is created.
- She has no open WhatsApp ticket, so the full intake runs: her open lead gets the message in its notes, an activity is logged, and a ticket opens linked to her contact, lead and company account.
- Ten minutes later she sends two photos of the access point. They join the same ticket's thread and are stored and attached to it.
- The assignee replies from the ticket, from the number she messaged.
One contact, one lead, one ticket, and a complete thread, with nothing re-typed by hand.
What this means if you're evaluating it
Getting WhatsApp messages into a CRM isn't the hard part. The edge cases are: retries, number formats, repeat customers, multi-message conversations, expiring files, and replies from people who shouldn't be sending them. Those are what this pipeline is designed around.
See how the ticket side fits day-to-day support in Helpdesk & Support or the WhatsApp ticket intake feature, or get in touch to see it on your own number.