Skip to content

feat: WhatsApp Business Cloud API channel integration adapter #583

Description

@ginccc

Problem / Motivation

WhatsApp (2B+ users globally) is the dominant messaging platform for customer engagement in APAC, LATAM, Europe, and Africa. EDDI's conversational agents can power customer support, sales qualification, and onboarding workflows via WhatsApp Business.

Note: WhatsApp Business API is primarily 1:1 (business-to-customer). A Groups API exists for Official Business Accounts (max 8 participants), but it is a restricted, premium feature - not the standard use case. The initial adapter should support AGENT targets only. GROUP target support via the Groups API can be a future enhancement.

Key WhatsApp constraints:

  • Primarily 1:1 - Standard use case is business-to-customer direct messaging
  • Groups API - Exists but requires Official Business Account (OBA) status, max 8 participants
  • 24-hour messaging window - Businesses can only send free-form messages within 24 hours of the customer's last message. Outside this window, only pre-approved message templates are allowed.
  • Cloud API (Meta-hosted) - Modern REST API via Meta's Graph API
  • Webhook with HMAC-SHA256 - Same algorithm as Slack (different header: X-Hub-Signature-256)
  • Meta app verification - Production use requires Meta business verification

Architecture Principle

No platform SDKs. All adapters use java.net.http.HttpClient + Jackson for raw HTTP/JSON - no Twilio, no third-party WhatsApp libraries. Every messaging platform's API is just REST under the hood. Raw HTTP keeps the dependency tree lean, the single-JAR deployment simple, and gives full control over retry logic, error handling, and message formatting. See the existing SlackWebApiClient (245 lines, zero external dependencies) as the reference pattern.

Proposed Solution

Create ai.labs.eddi.integrations.whatsapp package:

Class Responsibility Slack Equivalent
RestWhatsAppWebhook JAX-RS endpoint with @GET for Meta's webhook verification challenge (hub.verify_token + hub.challenge echo) and @POST for event payloads. RestSlackWebhook
WhatsAppSignatureVerifier HMAC-SHA256 verification using Meta App Secret. Same algorithm as Slack but header is X-Hub-Signature-256 with sha256= prefix. SlackSignatureVerifier
WhatsAppEventHandler Routes WhatsApp messages to EDDI via ChannelTargetRouter. Only supports AGENT targets - rejects GROUP targets with a user-facing error. Tracks message timestamps for 24-hour window enforcement. SlackEventHandler
WhatsAppApiClient Sends messages via Meta Graph API (POST /v21.0/{phone-number-id}/messages). Supports text, interactive buttons (for HITL approvals), and message templates (for out-of-window). Marks messages as read. SlackWebApiClient
WhatsAppDeliveryException Retryable delivery failure. SlackDeliveryException

Note: No WhatsAppGroupDiscussionListener - GROUP targets are not supported in the initial adapter. The event handler should return a clear error message if a WhatsApp message routes to a GROUP target: "Multi-agent discussions are not available on WhatsApp. This target requires a platform that supports group conversations (Slack, Teams, Discord)."

Configuration Model

{
  "name": "Customer Support WhatsApp",
  "channelType": "whatsapp",
  "platformConfig": {
    "phoneNumberId": "123456789",
    "accessToken": "${vault:whatsapp-access-token}",
    "appSecret": "${vault:whatsapp-app-secret}",
    "verifyToken": "${vault:whatsapp-verify-token}",
    "businessAccountId": "987654321"
  },
  "defaultTargetName": "support",
  "targets": [...]
}

Key Design Decisions

  1. AGENT targets only (initial scope) - GROUP targets are not supported in the initial adapter. WhatsApp's Groups API exists but requires OBA status, has a max of 8 participants, and is a fundamentally different workflow from the core 1:1 business messaging use case. GROUP support via the Groups API is a natural Phase 2 enhancement.
  2. Cloud API only - Use Meta's Cloud API. No on-premise BSP partnership required.
  3. Webhook verification (GET challenge) - Meta sends GET with hub.mode=subscribe, hub.verify_token, hub.challenge. Echo hub.challenge on token match. This is the WhatsApp equivalent of Slack's url_verification.
  4. 24-hour window tracking - Track customer's last message timestamp per conversation. Within 24 hours: send free-form text. Outside: send pre-approved message template OR log a warning and skip. Do NOT silently drop messages.
  5. Interactive buttons - Use WhatsApp's Interactive Message buttons (up to 3) for HITL approval flows.
  6. Message formatting - WhatsApp supports *bold*, _italic_, ~strikethrough~, `monospace`. Very close to Slack's mrkdwn - can largely reuse SlackWebApiClient.convertMarkdownToSlackMrkdwn() with minor adjustments.
  7. Read receipts - Mark messages as read via the API for better UX feedback.
  8. Loop prevention - WhatsApp Cloud API only delivers customer messages to the webhook (not the bot's own messages). Infinite loops are impossible at the API level. Still implement dedup by messages[].id for webhook retries.

Deliverables

  • 5 Java classes in ai.labs.eddi.integrations.whatsapp (no GroupDiscussionListener)
  • Unit tests (HMAC-SHA256 verification testable with same approach as Slack)
  • Add "whatsapp" to REGISTERED_CHANNEL_TYPES
  • Documentation page: docs/whatsapp-integration.md

Alternatives Considered

  • Twilio as intermediary - Adds cost and dependency. Direct Cloud API integration is cleaner and consistent with the no-SDK principle.
  • On-Premise API via BSP - More complex setup, requires partnership with a Business Solution Provider. Cloud API is the modern, recommended approach.

Additional Context

Acceptance Criteria

  • All classes listed in Deliverables are implemented and compile without warnings
  • Unit tests for every class (HMAC-SHA256 verification testable with same approach as Slack)
  • "whatsapp" added to REGISTERED_CHANNEL_TYPES in RestChannelIntegrationStore
  • ./mvnw test passes with zero failures
  • Code coverage meets project targets: >90% instruction coverage, >80% branch coverage (measured by JaCoCo)
  • GROUP targets are rejected with a clear user-facing error message
  • Documentation page docs/whatsapp-integration.md exists (following docs/slack-integration.md structure)
  • PR description includes screenshots or curl transcripts demonstrating:
    • Webhook verification challenge (GET) handled correctly
    • WhatsApp message received and routed to an EDDI agent
    • EDDI agent response delivered back to the WhatsApp chat
    • HMAC-SHA256 signature verification rejecting an invalid request
  • PR submitted for review - do NOT merge without approval

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementhelp wantedintegrationChannel integration adapters (Slack, Teams, Discord, Telegram, WhatsApp)javaPull requests that update java codesize: LLarge: full day+, significant scope, design discussion likely

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions