Skip to main content

WhatsApp Webhooks

Agent-TS is Kapso-first for WhatsApp messaging. It keeps a compatibility webhook for external client testing, but production traffic should use Kapso / Meta webhooks.

Endpoints

Compatibility Webhook

POST /api/v1/external/whatsapp For local testing or temporary bridge scenarios.

Meta Business API Webhook

GET /api/v1/webhooks/whatsapp - Verification POST /api/v1/webhooks/whatsapp - Message handling For Meta’s official WhatsApp Business API.

External Client Integration

Text Message Payload

{
  "event": "message",
  "message": "What is my balance?",
  "from": "23279648205@c.us",
  "phoneE164": "+23279648205"
}

Image Message Payload

{
  "event": "message",
  "messageType": "image",
  "hasMedia": true,
  "phoneE164": "+23279372497",
  "message": "Here is my ID",
  "media": {
    "data": "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
    "mimetype": "image/jpeg",
    "filename": "id_card_front.jpg",
    "size": 52643
  }
}
The media.data field must include the data URI prefix (data:image/jpeg;base64,).

Response Format

{
  "answer": "Your balance is 5,000 SLE",
  "status": "success"
}

Kapso-first messaging

Kapso is the supported WhatsApp transport for:
  • free-text conversations
  • interactive list menus
  • reply buttons for confirmations and navigation
  • WhatsApp Flows for structured data capture and PIN/auth steps
  • template messages from internal services when approved by WhatsApp

Meta WhatsApp Business API

Webhook Verification

Meta sends a GET request to verify your webhook:
GET /api/v1/webhooks/whatsapp?hub.mode=subscribe&hub.verify_token=YOUR_TOKEN&hub.challenge=CHALLENGE
The agent responds with the challenge if the verify token matches WHATSAPP_VERIFY_TOKEN.

Incoming Message Payload

{
  "object": "whatsapp_business_account",
  "entry": [{
    "id": "WHATSAPP_BUSINESS_ACCOUNT_ID",
    "changes": [{
      "value": {
        "messaging_product": "whatsapp",
        "metadata": {
          "display_phone_number": "15551234567",
          "phone_number_id": "PHONE_NUMBER_ID"
        },
        "contacts": [{
          "profile": { "name": "John Doe" },
          "wa_id": "23279648205"
        }],
        "messages": [{
          "from": "23279648205",
          "id": "wamid.xxx",
          "timestamp": "1234567890",
          "type": "text",
          "text": { "body": "What is my balance?" }
        }]
      }
    }]
  }]
}

Meta Developer Console Setup

  1. Go to Meta for Developers
  2. Create or select your app
  3. Add WhatsApp product
  4. Configure webhook URL: https://your-domain.com/api/v1/webhooks/whatsapp
  5. Set verify token: Same as WHATSAPP_VERIFY_TOKEN
  6. Subscribe to messages webhook field

Payload Fields Reference

FieldTypeRequiredDescription
eventstringYesEvent type (always “message”)
fromstringYesSender identifier
phoneE164stringYesPhone in E.164 format
messagestringNoText message content
messageTypestringNoMessage type (text, image, etc.)
hasMediabooleanNoWhether message has media
mediaobjectNoMedia data (if hasMedia)
media.datastringNoBase64 with data URI prefix
media.mimetypestringNoMIME type
media.filenamestringNoOriginal filename
media.sizenumberNoFile size in bytes

Error Responses

Validation Error

{
  "error": "Missing required field: phoneE164",
  "status": "error"
}

Agent Error

{
  "error": "Internal agent error",
  "status": "error"
}

Rate Limited

{
  "error": "Too many requests",
  "status": "error",
  "retryAfter": 60
}

Health Check

Verify the agent is running:
curl http://localhost:8000/health
Response:
{
  "status": "healthy",
  "service": "olive-agent",
  "version": "1.0.0",
  "activeConversations": 5
}

Testing

Test Compatibility Text Message

curl -X POST http://localhost:8000/api/v1/external/whatsapp \
  -H "Content-Type: application/json" \
  -d '{
    "event": "message",
    "message": "what is my balance?",
    "from": "23279648205@c.us",
    "phoneE164": "+23279648205"
  }'

Test Compatibility Transfer

curl -X POST http://localhost:8000/api/v1/external/whatsapp \
  -H "Content-Type: application/json" \
  -d '{
    "event": "message",
    "message": "send 5000 to CARD0001",
    "from": "23279648205@c.us",
    "phoneE164": "+23279648205"
  }'

Security Considerations

All incoming messages are sanitized to prevent injection attacks.
30 requests per minute per phone number by default.
Meta webhooks are verified using the configured verify token.
Production webhook endpoints must use HTTPS.

Next Steps

Configuration

Environment variable setup

KYC Validation

Image processing details