3.3 KiB
3.3 KiB
CRM Step 11 — Integration: WhatsApp Business API
Context
Read .claude/crm-build-plan.md for full context and IMPORTANT NOTES.
Steps 01–10 must be complete.
Prerequisites (manual setup required before this step)
- A Meta Business account with WhatsApp Business API enabled
- A dedicated phone number registered to WhatsApp Business API (NOT a personal number)
- A Meta App with webhook configured to point to:
https://yourdomain.com/api/crm/whatsapp/webhook - The following values ready:
WHATSAPP_PHONE_NUMBER_ID,WHATSAPP_ACCESS_TOKEN,WHATSAPP_VERIFY_TOKEN
Task
Receive inbound WhatsApp messages via webhook and send outbound messages, all logged to crm_comms_log.
Backend changes
1. Add to backend/config.py
whatsapp_phone_number_id: str = ""
whatsapp_access_token: str = ""
whatsapp_verify_token: str = "change-me" # you set this in Meta webhook config
2. Create backend/crm/whatsapp.py
async def send_whatsapp(to_phone: str, message: str) -> str:
"""
POST to https://graph.facebook.com/v19.0/{phone_number_id}/messages
Headers: Authorization: Bearer {access_token}
Body: { messaging_product: "whatsapp", to: to_phone, type: "text", text: { body: message } }
Returns the wamid (WhatsApp message ID).
"""
3. Add webhook + send endpoints to backend/crm/router.py
GET /api/crm/whatsapp/webhook
— Meta webhook verification. Check hub.verify_token == settings.whatsapp_verify_token.
Return hub.challenge if valid, else 403.
No auth required on this endpoint.
POST /api/crm/whatsapp/webhook
— Receive inbound message events from Meta.
No auth required on this endpoint.
Parse payload:
entry[0].changes[0].value.messages[0]
.from → sender phone number (e.g. "306974015758")
.id → wamid
.type → "text"
.text.body → message content
.timestamp → unix timestamp
For each message:
- Look up customer by phone number in crm_customers contacts (where type=phone or whatsapp)
- If found: create crm_comms_log entry (type=whatsapp, direction=inbound, ext_message_id=wamid)
- If not found: still log it but with customer_id="unknown:{phone}"
POST /api/crm/whatsapp/send
Body: { customer_id, to_phone, message }
Requires auth.
→ calls send_whatsapp(...), creates outbound comms_log entry
Frontend changes
Update Comms tab in CustomerDetail.jsx
- WhatsApp entries: green background, WhatsApp icon
- "Send WhatsApp" button → modal with: to_phone (pre-filled from customer's whatsapp/phone contacts), message textarea
- On send: POST
/api/crm/whatsapp/send
Update InboxPage.jsx
- WhatsApp entries are already included (from crm_comms_log)
- Add type filter option for "WhatsApp"
Notes
- Phone number format: Meta sends numbers without
+(e.g. "306974015758"). Normalize when matching against customer contacts (strip+and spaces). - Webhook payload can contain multiple entries and messages — iterate and handle each
- Rate limits: Meta free tier = 1000 conversations/month (a conversation = 24h window with a customer). More than enough.
- If whatsapp_phone_number_id is empty, the send endpoint returns 503. The webhook endpoint must always be available (it's a public endpoint).
- Media messages (images, docs): in this step, just log "Media message received" as body text. Full media download is a future enhancement.