Building WhatsApp + Odoo CRM Sync for Lead Management

Building WhatsApp + Odoo CRM Sync for Lead Management

Modern sales organizations require instantaneous communication channels to engage inbound prospects before response latency degrades conversion rates. Implementing a custom odoo whatsapp crm sync establishes an automated, bidirectional pipeline between the WhatsApp Business Cloud API and Odoo CRM, capturing incoming customer inquiries as actionable sales leads in real time.

While standard email capturing remains a staple of enterprise CRM workflows, messaging platforms provide significantly higher open rates and near-instant customer feedback. By developing an event-driven integration module inside Odoo, technical developers can automate prospect onboarding, log conversation histories directly into lead chatter, and trigger interactive template notifications on key pipeline milestones.

Architecture Overview: Webhook-Driven Lead Ingestion and Two-Way Messaging

A resilient WhatsApp integration architecture separates communication intake into two decoupled streams: inbound webhook processing and outbound API dispatching.

Incoming messages sent by prospects trigger an HTTP POST webhook from Meta servers to a designated Odoo endpoint. The backend controller verifies request signatures, parses the JSON payload, extracts customer metadata, and either creates a new CRM lead or appends the message to an existing lead conversation thread.

Meta Cloud API vs Business Solution Providers (BSPs)

Developers architecting an Odoo messaging gateway generally choose between two connection paths:

  1. Meta WhatsApp Cloud API (Direct): Hosted directly on Meta cloud infrastructure. It offers lower operational costs, zero per-message markup from third parties, higher message throughput, and direct access to the latest Meta features.
  2. Third-Party Business Solution Providers (Twilio, MessageBird, Infobip): Offer simplified REST endpoints and managed webhooks, but introduce ongoing SaaS markups and third-party dependency risks.

For enterprise Odoo implementations, integrating directly with the Meta Cloud API provides maximum control over data residency, reduced latency, and direct webhook management.

Securing Incoming Webhook Payloads and Verification Handshakes

Before Meta sends live message data, your Odoo controller must complete an initial verification handshake (HTTP GET). Once verified, all subsequent incoming notifications (HTTP POST) contain an X-Hub-Signature-256 header containing an HMAC-SHA256 hash computed using your Meta App Secret.

Validating this cryptographic signature inside Odoo ensures that your webhook endpoint cannot be spoofed by unauthorized third-party callers.

Designing the Custom Odoo Integration Module

Building this functionality into a clean, reusable custom module (e.g., whatsapp_crm_sync) ensures maintainability and smooth migration across Odoo releases.

Extending crm.lead and res.partner with WhatsApp Metadata Fields

To store conversation context and unique WhatsApp IDs, extend the core CRM and Partner models:from odoo import models, fields

 

class ResPartner(models.Model):

    _inherit = 'res.partner'

    whatsapp_number = fields.Char(string="WhatsApp Number", index=True)

    whatsapp_id = fields.Char(string="WhatsApp ID (WAID)", index=True)

class CrmLead(models.Model):

    _inherit = 'crm.lead'

    whatsapp_message_id = fields.Char(string="Last Message ID", readonly=True)

    whatsapp_chat_status = fields.Selection([

        ('active', 'Active Conversation'),

        ('opted_out', 'Opted Out'),

        ('closed', 'Closed')

    ], default='active', string="WhatsApp Status")

Indexing whatsapp_number and whatsapp_id ensures that database lookups remain fast even when your CRM contains hundreds of thousands of customer records.

Building the Custom HTTP Controller to Ingest Inbound Messages

The HTTP controller handles both verification handshakes and incoming message ingestion:import json

import logging

from odoo import http

from odoo.http import request

_logger = logging.getLogger(__name__)

class WhatsAppWebhookController(http.Controller):

    @http.route('/webhook/whatsapp', type='http', auth='public', methods=['GET'], csrf=False)

    def verify_webhook(self, **kwargs):

        verify_token = request.env['ir.config_parameter'].sudo().get_param('whatsapp.verify_token')

        mode = kwargs.get('hub.mode')

        token = kwargs.get('hub.verify_token')

        challenge = kwargs.get('hub.challenge')

        if mode == 'subscribe' and token == verify_token:

            _logger.info("WhatsApp Webhook verified successfully.")

            return challenge

        return request.make_response("Forbidden", status=403)

    @http.route('/webhook/whatsapp', type='json', auth='public', methods=['POST'], csrf=False)

    def receive_webhook(self, **kwargs):

        payload = request.get_json_data()

        request.env['crm.lead'].sudo()._process_inbound_whatsapp(payload)

        return {'status': 'success'}

By specifying csrf=False and auth='public', external Meta servers can communicate with Odoo without session cookie authentication, while security is maintained via signature verification in the processing model.

Automated Lead Generation and Pipeline Routing Logic

When an incoming payload arrives, Odoo must intelligently determine whether the sender represents a new opportunity or an ongoing customer inquiry.

Matching Inbound Phone Numbers with Existing Res.Partner Records

Inside crm.lead, the processing logic extracts the sender phone number and checks for existing partners:@api.model

def _process_inbound_whatsapp(self, payload):

    entry = payload.get('entry', [])[0]

    changes = entry.get('changes', [])[0]

    value = changes.get('value', {})

    messages = value.get('messages', [])

    if not messages:

        return

    msg = messages[0]

    sender_phone = msg.get('from')

    message_text = msg.get('text', {}).get('body', '')

    sender_name = value.get('contacts', [])[0].get('profile', {}).get('name', 'WhatsApp Prospect')

    partner = self.env['res.partner'].search([

        '|', ('phone', '=', sender_phone), ('mobile', '=', sender_phone)

    ], limit=1)

    if not partner:

        partner = self.env['res.partner'].create({

            'name': sender_name,

            'mobile': sender_phone,

            'whatsapp_number': sender_phone

        })

    self._route_or_create_lead(partner, message_text, msg.get('id'))

 

For developers seeking an end-to-end framework, check out our technical tutorial on building a custom module to sync WhatsApp with Odoo CRM to download sample controller templates.

Dynamic Sales Team Assignment and Automated Stage Progression

When routing the message, check for open leads linked to that partner. If an open lead exists, log the incoming text into the chatter via lead.message_post() so assigned salespeople receive instant notifications:def _route_or_create_lead(self, partner, message_body, message_id):

    open_lead = self.search([

        ('partner_id', '=', partner.id),

        ('type', '=', 'opportunity'),

        ('stage_id.is_won', '=', False)

    ], order='create_date desc', limit=1)

    if open_lead:

        open_lead.message_post(

            body=f"<b>Inbound WhatsApp Message:</b><br/>{message_body}",

            message_type='comment',

            subtype_xmlid='mail.mt_comment'

        )

    else:

        team_id = self.env['crm.team'].search([('use_leads', '=', True)], limit=1).id

        self.create({

            'name': f"WhatsApp Inquiry: {partner.name}",

            'partner_id': partner.id,

            'description': message_body,

            'team_id': team_id,

            'whatsapp_message_id': message_id

        })

Outbound Automation: Sending Template Notifications from CRM Actions

A complete CRM sync supports outbound messaging triggered by user actions or automated stage changes.

Triggering WhatsApp API Requests on Pipeline Milestones

Meta mandates that business-initiated conversations utilize pre-approved message templates. In Odoo, you can attach an automated action to trigger an outbound API request when an opportunity advances to the "Qualified" or "Proposal Sent" stage:n
import requests

def send_whatsapp_template(self, template_name, recipient_phone, parameters):
token = self.env['ir.config_parameter'].sudo().get_param('whatsapp.api_token')
phone_number_id = self.env['ir.config_parameter'].sudo().get_param('whatsapp.phone_number_id')url = f"https://graph.facebook.com/v19.0/{phone_number_id}/messages"

 

headers = {

    "Authorization": f"Bearer {token}",

    "Content-Type": "application/json"

}

data = {

    "messaging_product": "whatsapp",

    "to": recipient_phone,

    "type": "template",

    "template": {

        "name": template_name,

        "language": {"code": "en_US"},

        "components": [{

            "type": "body",

            "parameters": [{"type": "text", "text": p} for p in parameters]

        }]

    }

}

response = requests.post(url, headers=headers, json=data, timeout=10)

return response.json()

 

If your technical team requires custom API connectors, multi-channel messaging architecture, or dedicated Odoo module development, [Book an Odoo CRM Integration Consultation](https://arsalanyasin.com.au/contact-me/) with our senior ERP software architects.

Asynchronous Message Queueing via Odoo Scheduled Actions

 

Making synchronous external HTTP requests during standard user write actions can cause UI latency if Meta API endpoints experience micro-delays.

To prevent interface lag, store outbound messages in a dedicated queue table (e.g., `whatsapp.outbound.queue`) with statuses like `draft`, `processing`, and `sent`. An Odoo scheduled action (cron job) running every minute dispatches queued messages asynchronously, implementing exponential backoff for failed network transmissions.

Frequently Asked Questions (FAQs)

What is required to connect Odoo CRM to the official WhatsApp Business Cloud API?

You need a Meta Developer Account, a verified Meta Business Manager, a registered WhatsApp Business Account (WABA), and a dedicated phone number not currently tied to a personal WhatsApp device.

How does the custom sync module handle existing contacts versus brand new leads?

The module searches `res.partner` using the incoming international phone number. If a match is found, the message is routed to their active CRM opportunity; otherwise, a new contact and lead are created simultaneously.

Can sales reps reply directly to WhatsApp messages from within Odoo CRM chatter?

Yes. By extending Odoo mail composer or chatter widgets with a custom action button, sales agents can compose outbound text messages that invoke the WhatsApp Cloud API directly.

How are media attachments like PDFs and images handled during inbound webhooks?

The webhook provides a media ID. The Odoo controller queries the Meta Graph API to download the binary payload, saves it as an `ir.attachment` record, and attaches it directly to the CRM lead chatter.

What prevents duplicate CRM leads from being created for repeated WhatsApp messages?

The integration logic checks for existing open opportunities linked to that contact within a configurable time window (e.g., last 30 days) before creating a new lead, appending follow-up messages to the existing lead chatter instead.

Conclusion and Future-Proofing Your Messaging Infrastructure

Integrating WhatsApp with Odoo CRM empowers sales organizations to capture leads instantaneously, streamline conversation tracking, and automate prospect nurturing. By building a custom module with robust webhook validation, clean partner matching, and asynchronous outbound queues, developers deliver an enterprise-grade messaging architecture that boosts conversions while keeping customer records unified inside Odoo.

0 Comments

Post Comment

Your email address will not be published. Required fields are marked *