Files
bellsystems-cp/.claude/crm-step-11.md

82 lines
3.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CRM Step 11 — Integration: WhatsApp Business API
## Context
Read `.claude/crm-build-plan.md` for full context and IMPORTANT NOTES.
Steps 0110 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`
```python
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`
```python
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:
1. Look up customer by phone number in crm_customers contacts (where type=phone or whatsapp)
2. If found: create crm_comms_log entry (type=whatsapp, direction=inbound, ext_message_id=wamid)
3. 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.