Skip to main content
All webhook payloads use v2 format with phone_number_id at the top level.

Payload structure

Webhook payloads separate message data from conversation data:
  • message.kapso - Message-scoped only: direction, status, processing_status, origin, has_media, content (text representation), transcript (for audio), media helpers (media_data, media_url, message_type_data)
  • conversation - Top-level identifiers (id, phone_number, phone_number_id). Optional conversation.kapso contains summary metrics (counts, last-message metadata, timestamps)
  • phone_number_id - Included at top level for routing

Project webhook events

whatsapp.phone_number.created

Fires when a customer successfully connects their WhatsApp through a setup link. See Connection detection for implementation guide. Payload:
{
  "phone_number_id": "123456789012345",
  "project": {
    "id": "990e8400-e29b-41d4-a716-446655440004"
  },
  "customer": {
    "id": "880e8400-e29b-41d4-a716-446655440003"
  }
}

WhatsApp webhook events

Message received

whatsapp.message.receivedFired when a new WhatsApp message is received from a customer. Supports message buffering for batch delivery.

Message sent

whatsapp.message.sentFired when a message is successfully sent to WhatsApp

Message delivered

whatsapp.message.deliveredFired when a message is successfully delivered to the recipient’s device

Message read

whatsapp.message.readFired when the recipient reads your message

Message failed

whatsapp.message.failedFired when a message fails to deliver

Conversation created

whatsapp.conversation.createdFired when a new WhatsApp conversation is initiated

Conversation ended

whatsapp.conversation.endedFired when a WhatsApp conversation ends (agent action, manual closure, or 24-hour inactivity)

Conversation inactive

whatsapp.conversation.inactiveFired when no messages (inbound/outbound) for configured minutes (1-1440, default 60)

Payload structures

whatsapp.message.received

{
  "message": {
    "id": "wamid.123",
    "timestamp": "1730092800",
    "type": "text",
    "text": { "body": "Hello" },
    "kapso": {
      "direction": "inbound",
      "status": "received",
      "processing_status": "pending",
      "origin": "cloud_api",
      "has_media": false,
      "content": "Hello"
    }
  },
  "conversation": {
    "id": "conv_123",
    "phone_number": "+15551234567",
    "status": "active",
    "last_active_at": "2025-10-28T14:25:01Z",
    "created_at": "2025-10-28T13:40:00Z",
    "updated_at": "2025-10-28T14:25:01Z",
    "metadata": {},
    "phone_number_id": "123456789012345",
    "kapso": {
      "contact_name": "John Doe",
      "messages_count": 1,
      "last_message_id": "wamid.123",
      "last_message_type": "text",
      "last_message_timestamp": "2025-10-28T14:25:01Z",
      "last_message_text": "Hello",
      "last_inbound_at": "2025-10-28T14:25:01Z",
      "last_outbound_at": null
    }
  },
  "is_new_conversation": true,
  "phone_number_id": "123456789012345"
}

whatsapp.message.sent

{
  "message": {
    "id": "wamid.456",
    "timestamp": "1730092860",
    "type": "text",
    "text": { "body": "On my way" },
    "kapso": {
      "direction": "outbound",
      "status": "sent",
      "processing_status": "completed",
      "origin": "cloud_api",
      "has_media": false
    }
  },
  "conversation": {
    "id": "conv_123",
    "phone_number": "+15551234567",
    "status": "active",
    "last_active_at": "2025-10-28T14:31:00Z",
    "created_at": "2025-10-28T13:40:00Z",
    "updated_at": "2025-10-28T14:31:00Z",
    "metadata": {},
    "phone_number_id": "123456789012345",
    "kapso": {
      "contact_name": "John Doe",
      "messages_count": 2,
      "last_message_id": "wamid.456",
      "last_message_type": "text",
      "last_message_timestamp": "2025-10-28T14:31:00Z",
      "last_message_text": "On my way",
      "last_inbound_at": "2025-10-28T14:25:01Z",
      "last_outbound_at": "2025-10-28T14:31:00Z"
    }
  },
  "is_new_conversation": false,
  "phone_number_id": "123456789012345"
}

whatsapp.message.delivered

{
  "message": {
    "id": "wamid.456",
    "timestamp": "1730092888",
    "type": "text",
    "text": { "body": "On my way" },
    "kapso": {
      "direction": "outbound",
      "status": "delivered",
      "processing_status": "completed",
      "origin": "cloud_api",
      "has_media": false
    }
  },
  "conversation": {
    "id": "conv_123",
    "phone_number": "+15551234567",
    "status": "active",
    "last_active_at": "2025-10-28T14:31:28Z",
    "created_at": "2025-10-28T13:40:00Z",
    "updated_at": "2025-10-28T14:31:28Z",
    "metadata": {},
    "phone_number_id": "123456789012345"
  },
  "is_new_conversation": false,
  "phone_number_id": "123456789012345"
}

whatsapp.message.failed

{
  "message": {
    "id": "wamid.789",
    "timestamp": "1730093200",
    "type": "text",
    "text": { "body": "This message failed" },
    "kapso": {
      "direction": "outbound",
      "status": "failed",
      "processing_status": "completed",
      "origin": "cloud_api",
      "has_media": false
    }
  },
  "conversation": {
    "id": "conv_123",
    "phone_number": "+15551234567",
    "status": "active",
    "last_active_at": "2025-10-28T15:00:00Z",
    "created_at": "2025-10-28T13:40:00Z",
    "updated_at": "2025-10-28T15:00:00Z",
    "metadata": {},
    "phone_number_id": "123456789012345"
  },
  "is_new_conversation": false,
  "phone_number_id": "123456789012345"
}

whatsapp.conversation.created

{
  "conversation": {
    "id": "conv_789",
    "phone_number": "+15551234567",
    "status": "active",
    "last_active_at": "2025-10-28T14:00:00Z",
    "created_at": "2025-10-28T14:00:00Z",
    "updated_at": "2025-10-28T14:00:00Z",
    "metadata": {},
    "phone_number_id": "123456789012345",
    "kapso": {
      "contact_name": "John Doe",
      "messages_count": 0,
      "last_message_id": null,
      "last_message_type": null,
      "last_message_timestamp": null,
      "last_message_text": null,
      "last_inbound_at": null,
      "last_outbound_at": null
    }
  },
  "phone_number_id": "123456789012345"
}

whatsapp.conversation.ended

{
  "conversation": {
    "id": "conv_789",
    "phone_number": "+15551234567",
    "status": "ended",
    "last_active_at": "2025-10-28T15:10:45Z",
    "created_at": "2025-10-28T14:00:00Z",
    "updated_at": "2025-10-28T15:10:45Z",
    "metadata": {},
    "phone_number_id": "123456789012345",
    "kapso": {
      "contact_name": "John Doe",
      "messages_count": 15,
      "last_message_id": "wamid.999",
      "last_message_type": "text",
      "last_message_timestamp": "2025-10-28T15:10:45Z",
      "last_message_text": "Thanks!",
      "last_inbound_at": "2025-10-28T15:10:45Z",
      "last_outbound_at": "2025-10-28T15:10:30Z"
    }
  },
  "phone_number_id": "123456789012345"
}

whatsapp.conversation.inactive

{
  "conversation": {
    "id": "conv_789",
    "phone_number": "+15551234567",
    "status": "active",
    "last_active_at": "2025-10-28T13:00:00Z",
    "created_at": "2025-10-28T12:00:00Z",
    "updated_at": "2025-10-28T13:00:00Z",
    "metadata": {},
    "phone_number_id": "123456789012345"
  },
  "since_message": {
    "id": "msg_anchor",
    "whatsapp_message_id": "wamid.ANCHOR",
    "direction": "inbound",
    "created_at": "2025-10-28T13:00:00Z"
  },
  "inactivity": {
    "minutes": 60
  },
  "phone_number_id": "123456789012345"
}

Message origin

The message.kapso.origin field indicates how the message entered the system:
  • cloud_api - Sent via Kapso API (outbound jobs, flow actions, API calls)
  • business_app - Echoed from WhatsApp Business App (when using the Business App)
  • history_sync - Backfilled during message history imports (only if project ran sync)

Message types

The message.type field can be one of:
  • text - Plain text message
  • image - Image attachment
  • video - Video attachment
  • audio - Audio/voice message
  • document - Document attachment
  • location - Location sharing
  • template - WhatsApp template message
  • interactive - Interactive message (buttons, lists)
  • reaction - Message reaction
  • contacts - Contact card sharing

Message type-specific data

Media messages (image/video/document)

{
  "message": {
    "id": "wamid.789",
    "timestamp": "1730093000",
    "type": "image",
    "image": {
      "caption": "Photo description",
      "id": "media_id_123"
    },
    "kapso": {
      "direction": "inbound",
      "status": "received",
      "processing_status": "pending",
      "origin": "cloud_api",
      "has_media": true,
      "content": "Photo description Image attached (photo.jpg) [Size: 200 KB | Type: image/jpeg] URL: https://api.kapso.ai/media/...",
      "media_url": "https://api.kapso.ai/media/...",
      "media_data": {
        "url": "https://api.kapso.ai/media/...",
        "filename": "photo.jpg",
        "content_type": "image/jpeg",
        "byte_size": 204800
      },
      "message_type_data": {
        "caption": "Photo description"
      }
    }
  }
}

Audio messages

{
  "message": {
    "id": "wamid.790",
    "timestamp": "1730093100",
    "type": "audio",
    "audio": {
      "id": "media_id_456"
    },
    "kapso": {
      "direction": "inbound",
      "status": "received",
      "processing_status": "pending",
      "origin": "cloud_api",
      "has_media": true,
      "content": "[Audio attached] (voice.ogg) [Size: 50 KB | Type: audio/ogg] URL: https://api.kapso.ai/media/...\nTranscript: Hello, I need help with my order",
      "transcript": {
        "text": "Hello, I need help with my order"
      },
      "media_url": "https://api.kapso.ai/media/...",
      "media_data": {
        "url": "https://api.kapso.ai/media/...",
        "filename": "voice.ogg",
        "content_type": "audio/ogg",
        "byte_size": 51200
      }
    }
  }
}

Location messages

{
  "message": {
    "type": "location",
    "location": {
      "latitude": 37.7749,
      "longitude": -122.4194,
      "name": "San Francisco",
      "address": "San Francisco, CA, USA"
    }
  }
}

Template messages

{
  "message": {
    "type": "template",
    "template": {
      "name": "order_confirmation",
      "language": {
        "code": "en_US"
      },
      "components": [...]
    }
  }
}

Interactive messages

{
  "message": {
    "type": "interactive",
    "interactive": {
      "type": "button_reply",
      "button_reply": {
        "id": "btn_1",
        "title": "Confirm"
      }
    }
  }
}

Reaction messages

{
  "message": {
    "type": "reaction",
    "reaction": {
      "message_id": "wamid.HBgNNTU0MTIzNDU2Nzg5MA",
      "emoji": "👍"
    }
  }
}