Skip to main content

WhatsApp Integration

PingCRM connects to WhatsApp using the WhatsApp Web protocol via a Node.js sidecar service running whatsapp-web.js. This provides access to personal chat history and contact profile information.

Architecture

Unlike other integrations that run inside the Python backend, WhatsApp uses a separate Node.js service (the "sidecar") that manages WhatsApp Web sessions. The backend communicates with the sidecar over HTTP and receives real-time events via HMAC-signed webhooks.

Browser → Backend API → Sidecar (whatsapp-web.js) → WhatsApp servers
←── Webhooks (message events) ←──

Authentication

WhatsApp authenticates by linking a new device via QR code:

  1. Click Connect WhatsApp in Settings > Integrations.
  2. A QR code appears inline — scan it with your phone (WhatsApp > Settings > Linked Devices > Link a Device).
  3. Once scanned, the session is established and persists across restarts.

Sessions can expire if you remove the linked device from your phone or if WhatsApp revokes the session. PingCRM runs a daily health check and notifies you if your session has disconnected.

What Gets Synced

DataSourceFrequency
Direct messages1:1 chatsReal-time (via webhook) + 30-day backfill on connect
Contact nameWhatsApp profileDuring message sync
About textWhatsApp "About" fieldDuring message sync

Not synced

  • Group messages
  • Media attachments (photos, videos, documents)
  • Read receipts / online status
  • Voice/video calls

Message Sync

Real-time

Once connected, the sidecar forwards incoming and outgoing messages to the backend as they happen via webhook events. Only text messages (type: "chat") are processed; media messages are skipped.

Initial backfill

On first connect, PingCRM triggers a 30-day backfill that fetches recent message history from all 1:1 chats. Messages are streamed to the backend in batches of 50 via webhooks.

Manual sync

Trigger a re-sync from Settings > Integrations > WhatsApp > "Sync Messages". This runs the same backfill process.

Contact Resolution

For each WhatsApp message, PingCRM matches the remote phone number to an existing contact:

  1. whatsapp_phone field (exact match on the Contact model)
  2. phones array (checks if any stored phone number matches)
  3. If no match, a new contact is created with source: "whatsapp"

Phone numbers are normalized to E.164 format (+1234567890) before matching. WhatsApp JID suffixes (@c.us, @s.whatsapp.net) are stripped automatically.

Session Health

A daily Celery beat task (check_whatsapp_sessions, 01:00 UTC) verifies that all active WhatsApp sessions are still connected by querying the sidecar. If a session has died:

  • The user's whatsapp_connected flag is set to false.
  • A notification is created prompting re-authentication.

Disconnecting

From Settings > Integrations > WhatsApp, use the kebab menu to disconnect. This:

  1. Destroys the sidecar session (including stored auth data).
  2. Clears the user's WhatsApp connection fields.
  3. Does not delete synced interactions or contacts.

Deployment

The sidecar runs as a separate Docker container (whatsapp-sidecar) alongside the backend. It requires:

  • Chromium — whatsapp-web.js uses Puppeteer to run the WhatsApp Web client.
  • Persistent volume — session auth data is stored on disk at /data/sessions so sessions survive container restarts.
  • Environment variables:
    • WEBHOOK_URL — backend webhook endpoint (e.g., http://backend:8000/api/v1/webhooks/whatsapp)
    • WEBHOOK_SECRET — shared HMAC signing secret for webhook authentication
    • SESSION_DIR — path to session storage directory

Security

  • Webhook authentication: All sidecar-to-backend webhook calls include an X-Webhook-Signature header (HMAC-SHA256). The backend verifies the signature before processing any event.
  • Session isolation: Each user's session is stored in a separate directory identified by their UUID.
  • No phone numbers in logs: All log messages use contact IDs rather than phone numbers.
  • Unofficial protocol: Like the Telegram integration, WhatsApp uses an unofficial client library. This carries a risk of account restrictions if WhatsApp detects automated usage. Normal usage patterns (no bulk messaging, reasonable sync intervals) minimize this risk.