TL;DR: Odoo'da /whapi/webhook yolunu csrf=False ile public controller olarak yapılandırın, Whapi messages.post olaylarına abone olun ve her message.id değerini crm.lead oluşturmadan önce saklayın. Aşama uyarılarını POST https://gate.whapi.cloud/messages/text ve Authorization: Bearer ile gönderin. Kanalı yükseltmeden önce Community Edition'da ücretsiz Sandbox ile inbound akışını test edin.
Odoo Community Edition geliştiricileri, kontrol ettikleri özel bir Python modülünde Whapi inbound webhook'ları ve outbound REST ile CRM lead intake'ini devreye alır. Copy-paste çıktı: inbound webhook, idempotent crm.lead, outbound aşama uyarısı.
Outbound WhatsApp gönderimleri çalışıyor ama müşteri yanıtları CRM'e hiç düşmüyorsa, sorun neredeyse her zaman API token'ınızda değil inbound webhook yönlendirmesindedir. Odoo forumunda entegratörler tam bu kalıbı bildiriyor: "Sending messages works, but incoming messages are not appearing in Odoo." Meta'nın yerel Odoo bağlayıcısı Enterprise lisansı ve gerçek bir pipeline'ı test etmeden önce 2–7 iş günü iş doğrulaması gerektirir. Whapi QR taramasıyla bağlanır ve dakikalar içinde controller'ınıza JSON gönderir.
Whapi REST Community CRM Lead Intake'ini Neden Açar
Enterprise yerel WhatsApp'ı kilitler; Whapi REST Meta doğrulaması olmadan Community CRM intake'ini açar.
Odoo'nun resmi WhatsApp uygulaması yalnızca Enterprise sürümündedir. Community Edition ekipleri duvara çarpar: yerleşik bağlayıcı yok, sohbetten otomatik crm.lead oluşturmanın desteklenen yolu yok. Apps Store modülleri boşluğu $50–$300+ OPL-1 lisanslarıyla doldurur; inbound trafik durduğunda debug edecek kaynak kodu yoktur.
Whapi.Cloud, WhatsApp Web'in kullandığı mekanizmayla aynı olan web oturum soketleri üzerinden bağlanır. Panelde QR kodu tarayın, Bearer token'ınızı kopyalayın ve webhook URL'nizi kaydedin. Resmi WhatsApp Business API'de iş doğrulaması genelde production mesajlaşmadan önce 2–7 iş günü sürer; Whapi ile çoğu ekip modülü kurduğu öğleden sonra test inbound mesajı gönderir.
Odoo CRM kullanan emlak acenteleri, e-ticaret mağazaları ve klinik kayıt masaları bu kalıbı her gün uygular: WhatsApp sorgusu puanlı lead oluşturur, aşama değişimi takip hatırlatıcısı tetikler. Burada Meta hub.challenge HMAC doğrulamasını atlıyoruz; bu yol Enterprise Meta bağlayıcılarına aittir, Whapi'nin JSON webhook'u ise Community Edition'ı zaten kapsar.
Entegrasyon Yaklaşımı Karşılaştırması
Community Edition'da deploy edebileceğiniz ve inbound trafik durduğunda debug edebileceğiniz Python yolunu seçin. Odoo WhatsApp CRM projelerinde bugün dört seçenek baskındır.
| Yaklaşım | Community Edition | Kurulum süresi | Kod sahipliği | Inbound güvenilirlik notları |
|---|---|---|---|---|
| Odoo Enterprise yerel WhatsApp | Hayır | Günler (Meta doğrulama + WABA) | Kapalı çekirdek modül | Forum raporları: outbound tamam, WABA/webhook reset'e kadar inbound sessiz |
| Apps Store OPL-1 (örn. whatsapp_lead_hook) | Evet (modüle bağlı) | Saatler (Meta token'ları + kurulum) | Kapalı kaynak (~228+ LOC kara kutu) | Hâlâ Meta WABA'ya bağımlı; sınırlı troubleshooting |
| Özel Meta Cloud API Python controller | Evet | Günler–haftalar | Tam (HMAC + token yenilemeyi siz yönetirsiniz) | Production numara hataları bildirildi; token'lar ~60 günde sona erer |
| Whapi REST + Odoo http.Controller (bu rehber) | Evet | ~2 dk QR + modül kurulumu | Kontrolünüzde tam Python modülü | JSON webhook; aşama bildirimlerinde template kapısı yok |
OCA mail_gateway_whatsapp modülü AGPL ve Community uyumludur, ancak yine Meta WABA, Facebook panelinde manuel webhook bağlantısı ve 24 saatte bir dönen test kimlik bilgileri gerektirir. Discuss mail yönlendirir; kutudan çıkan idempotent crm.lead pipeline'ı sunmaz. Yinelenen lead hataları için tek controller stack trace'e ihtiyaç duyduğunuzda araya n8n koymak yerine public route'lu tek Odoo modülü yeterlidir.
Modül Dosya Yapısı
whapi_crm_lead addon'unu __manifest__.py, controllers/whatsapp_webhook.py, models/crm_lead.py ve security/ir.model.access.csv ile oluşturun. Odoo 17/18 Community'de -i whapi_crm_lead ile kurun. Production trafiği aynı controller'a gelmeden önce inbound ayrıştırmayı doğrulamak için Whapi Sandbox'ı (ayda 5 aktif konuşma, günde 150 mesaj, kalıcı ücretsiz) kullanın.
Whapi Webhook Olaylarını Odoo Alanlarına Eşleme
Whapi payload'ını ayrıştırın, partner telefonunu eşleştirin, açık crm.lead'i upsert edin, chatter'a yazın. Bu dört adımlı zincir pipeline'ın inbound yarısıdır.
Whapi, messages.post olayında URL'nize WebhookPayload JSON gövdesi gönderir. messages dizisi, inbound webhook format referansındaki Message nesnelerini içerir. from_me değeri true olan satırları yok sayın; bunlar müşteri lead'i değil outbound yankılarıdır.
| Whapi webhook alanı | Odoo hedefi | Notlar |
|---|---|---|
messages[].id |
crm.lead.x_whapi_message_id (Char, indexed) |
Idempotency anahtarı; create öncesi kontrol |
messages[].from veya chat_id |
res.partner.phone / mobile |
E.164'e normalize; son 10 hane yedek |
messages[].text.body |
crm.lead.description + mail.message gövdesi |
Yalnızca type text olduğunda |
messages[].from_name |
crm.lead.contact_name |
Pushname mevcut olduğunda |
messages[].timestamp |
crm.lead.create_date bağlamı |
Sağlayıcıdan Unix epoch |
Kanal webhook'unu PATCH https://gate.whapi.cloud/settings ile yapılandırın; HTTPS URL'niz, mode: POST ve messages içeren olaylarla webhooks dizisi girişi geçirin. headers içine paylaşılan gizli anahtar ekleyin ve JSON ayrıştırmadan önce controller'da doğrulayın.
Webhook Controller'ı Oluşturma
Lead işleme sonradan devam etse bile bir saniye içinde HTTP 200 döndürün. Endpoint'iniz 200 yanıtlamazsa Whapi, başarısız callback'leri lineer backoff ile yeniden dener.
Whapi sunucularında Odoo oturum çerezi olmadığı için public route kaydedin. CSRF'yi yalnızca bu route'ta devre dışı bırakın. request.jsonrequest'e dokunmadan önce paylaşılan header'ınızı doğrulayın. Olay-tepki modeli burada geçerlidir: Whapi olayı POST eder, controller tepki verir, yavaş handler yeniden denemeleri tetikler.
# controllers/whatsapp_webhook.py
import logging
from odoo import http
from odoo.http import request
_logger = logging.getLogger(__name__)
class WhapiWebhookController(http.Controller):
@http.route("/whapi/webhook", type="json", auth="public", csrf=False, methods=["POST"])
def whapi_inbound(self, **kwargs):
# Without the shared-secret check, anyone who discovers this URL can POST fake leads.
expected = request.env["ir.config_parameter"].sudo().get_param("whapi.webhook_secret")
incoming = request.httprequest.headers.get("X-Whapi-Secret")
if not expected or incoming != expected:
return {"status": "forbidden"}
payload = request.jsonrequest or {}
messages = payload.get("messages") or []
Lead = request.env["crm.lead"].sudo()
for msg in messages:
if msg.get("from_me"):
continue
Lead.process_whapi_inbound(msg)
return {"status": "ok"}
Whapi'yi https://your-odoo-domain.com/whapi/webhook adresine yönlendirin. Canlı müşteri trafiğinden önce erişilebilirliği doğrulamak için aynı URL ile POST https://gate.whapi.cloud/settings/webhook_test çalıştırın.
Whapi public HTTPS URL gerektirir. Özel LAN'daki ekipler, webhook testi geçmeden önce TLS sonlandırmalı reverse proxy'ye ihtiyaç duyar.
Idempotent Lead Oluşturma
create öncesi message_id saklayın; webhook yeniden denemeleri CRM lead'lerini sessizce çoğaltır. Her inbound olayda idempotency kapısını uygulayın.
Sunucunuz yavaşsa veya 200 dışı durum döndürürse Whapi aynı messages.post payload'ını birden fazla kez iletebilir. Odoo'nun harici webhook ID'leri için yerel upsert'i yoktur. dev.to'da Odoo 19 + n8n yığınını belgeleyen bir geliştirici net özetledi: benzersiz mesaj tanımlayıcısı kontrol edilmeden her POST'ta kayıt oluşturulduğunda yinelenen lead'ler görülür.
# models/crm_lead.py
from odoo import api, fields, models
class CrmLead(models.Model):
_inherit = "crm.lead"
x_whapi_message_id = fields.Char(index=True, copy=False)
x_whapi_chat_id = fields.Char(copy=False)
@api.model
def process_whapi_inbound(self, msg):
message_id = msg.get("id")
if not message_id:
return
existing = self.search([("x_whapi_message_id", "=", message_id)], limit=1)
if existing:
return existing # idempotency gate: retry ignored
phone = msg.get("from") or msg.get("chat_id") or ""
body = (msg.get("text") or {}).get("body") or ""
partner = self.env["res.partner"]._find_or_create_from_whapi(phone, msg.get("from_name"))
open_lead = self.search([
("partner_id", "=", partner.id),
("type", "=", "opportunity"),
("active", "=", True),
("stage_id.is_won", "=", False),
], limit=1)
if open_lead:
open_lead.message_post(body=f"WhatsApp: {body}")
return open_lead
return self.create({
"name": f"WhatsApp - {partner.name or phone}",
"partner_id": partner.id,
"phone": partner.phone or phone,
"description": body,
"x_whapi_message_id": message_id,
"x_whapi_chat_id": msg.get("chat_id"),
})
stage_id.is_won false iken takip mesajlarını açık fırsata birleştirin. Önceki anlaşma kazanıldı veya kaybedildikten sonra yalnızca yeni lead oluşturun.
Whapi REST ile Outbound Aşama Bildirimleri
CRM aşama değişimi Whapi REST mesajını tetikler; inbound-outbound döngüsü kapanır. Yalnızca create olaylarına değil stage_id yazımlarına da kanca takın.
Bir satış temsilcisi lead'i "Site Visit Scheduled" aşamasına taşıdığında müşteri manuel kopyala-yapıştır olmadan WhatsApp onayı almalıdır. crm.lead üzerinde write() metodunu override edin, stage_id değişikliklerini algılayın ve Whapi'nin text endpoint'ini çağırın. Resmi WhatsApp Business API'de 24 saatlik müşteri hizmeti penceresi dışındaki outbound mesajlar önceden onaylı şablon gerektirir; Whapi şablon gönderimi olmadan web oturum soketleri üzerinden oturum tarzı metin gönderir — CRM durum değişikliklerine bağlı aşama uyarıları için uygundur.
# models/crm_lead.py (continued)
import os
import requests
from odoo import models
WHAPI_BASE = "https://gate.whapi.cloud"
class CrmLead(models.Model):
_inherit = "crm.lead"
def write(self, vals):
prev_stage = {lead.id: lead.stage_id for lead in self}
res = super().write(vals)
if "stage_id" not in vals:
return res
token = self.env["ir.config_parameter"].sudo().get_param("whapi.api_token")
for lead in self:
if prev_stage.get(lead.id) == lead.stage_id:
continue
to = lead.x_whapi_chat_id or lead.phone
if not (to and token):
continue
text = f"Hi {lead.contact_name or 'there'}, your deal moved to: {lead.stage_id.name}."
# Missing Bearer token returns 401; log it, do not crash the CRM write().
resp = requests.post(
f"{WHAPI_BASE}/messages/text",
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
json={"to": to, "body": text},
timeout=10,
)
if resp.status_code >= 400:
lead.message_post(body=f"Whapi stage alert failed: HTTP {resp.status_code}")
return res
Metin mesajı gönderme endpoint'i ile doğrulandı: POST /messages/text için to (telefon veya Chat ID) ve body gerekir. API token'ını ir.config_parameter'da saklayın, git'e asla koymayın.
Whapi'nin sabit aboneliği, resmi yollardaki şablon başına BSP faturalandırmasına kıyasla aşama bildirimi maliyetlerini öngörülebilir tutar.
Inbound Hatalarını Giderme
Tek yönlü WhatsApp senkronizasyonu outbound yapılandırmasında değil inbound webhook'larda hata olduğu anlamına gelir. Her debug oturumuna Whapi'nin messages.post olayını URL'nize ilettiğini doğrulayarak başlayın.
Odoo forum konularındaki belirtiler sürümler arasında tekrarlanır: şablonlar gider, yanıtlar kaybolur. Whapi kurulumlarında webhook URL'si DNS geçişinden sonra eski staging tünelini gösterdiğinde aynı tek yönlü kalıbı gördük. Meta doğrulamaları geçtikten sonra bir kullanıcı yazdı: "This would mean the so-publicised whatsapp funcionality in Odoo is absolutely useless." Whapi'de eşdeğer hata genelde yereldir: yanlış URL, eksik HTTPS, gizli anahtar uyuşmazlığı veya çoklu veritabanı filtresinin engellediği public route'ta Odoo'nun 403 döndürmesi.
-
Webhook testi: Whapi panelinden
POST /settings/webhook_testçalıştırın. 2 saniye içinde HTTP 200 ve Odoo loglarında bir kayıt bekleyin. -
Webhook girişinde
messagesetkin mi? Yalnızca bağlantı sağlık ping'leri lead oluşturmaz. -
CSRF / auth: Yalnızca Whapi route'u
auth="public", csrf=Falsekullanmalıdır. JSON route'ları yanlışlıkla portal auth ile sarmak Whapi'ye HTML giriş sayfaları döndürür. -
Yinelenen satırlar mı? Her iki kayıtta
x_whapi_message_idarayın. Boş değerler idempotency kapısının hiç çalışmadığını gösterir.
Bu kontrollerden sonra beklenmeyen davranışla karşılaşırsanız whapi.cloud üzerindeki sohbet widget'ı aracılığıyla Whapi.Cloud destek ekibiyle iletişime geçin. Ekip production webhook sorunlarını çözmede aktif olarak yardımcı olur.
Staging Sunucularda Çoklu Veritabanı Tuzakları
Addon server_wide_modules içinde yüklü değilse ve veritabanı filtresi Whapi trafiğini doğru CRM veritabanına yönlendirmiyorsa auth='public' controller'lar çoklu DB sunucularda bozulur. Belirti: webhook testi yanlış boş veritabanında HTTP 200 dönerken production CRM sessiz kalır. Whapi'de kaydettiğiniz public hostname için açık bir dbfilter ayarlayın.
Bu dört dosyalı modülle Community Edition'da Whapi inbound webhook'larını ve outbound REST'i bağlayın; Odoo/Python geliştiricileri QR kodunu taradıkları gün tam CRM pipeline'ını deneyebilir.









