Authentication

All API requests require authentication using your Project API Key:
X-API-Key: your-project-api-key
Find your API keys in your Project settings under “API Keys”. Keep these keys secure and never expose them in client-side code.
For complete endpoint documentation, see the API Reference.

WhatsApp Webhooks

Kapso provides real-time webhooks for WhatsApp messaging events, enabling you to build powerful integrations and automate workflows based on WhatsApp conversations.

Configuring WhatsApp Webhooks

  1. Navigate to your WhatsApp configuration settings
  2. Go to the “Webhooks” tab
  3. Click “Add Webhook” to create a new webhook endpoint
  4. Configure the following:
    • URL: Your endpoint that will receive webhook notifications
    • Events: Select which events you want to subscribe to
    • Secret Key: Auto-generated or provide your own (used for HMAC signature verification)
    • Custom Headers: Optional additional headers for authentication

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)

WhatsApp Webhook Headers

Every WhatsApp webhook request includes these headers:
X-Webhook-Event: whatsapp.message.received
X-Webhook-Signature: <hmac-hex-signature>
X-Idempotency-Key: <unique-key-per-event>
Content-Type: application/json
For batched message deliveries, additional headers are included:
X-Webhook-Batch: true
X-Batch-Size: <number-of-messages>

WhatsApp Webhook Payloads

Message Event Payload

For message-related events (received, sent, delivered, read, failed):
{
  "message": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "message_type": "text",
    "content": "Hello, I need help with my order",
    "direction": "inbound",
    "status": "received",
    "processing_status": "pending",
    "whatsapp_message_id": "wamid.HBgNNTU0MTIzNDU2Nzg5MA",
    "phone_number": "+1234567890",
    "has_media": false,
    "media_data": null,
    "message_type_data": {},
    "created_at": "2024-01-15T14:30:00Z",
    "updated_at": "2024-01-15T14:30:00Z"
  },
  "conversation": {
    "id": "660e8400-e29b-41d4-a716-446655440001",
    "phone_number": "+1234567890",
    "status": "active",
    "last_active_at": "2024-01-15T14:30:00Z",
    "whatsapp_config_id": "770e8400-e29b-41d4-a716-446655440002",
    "metadata": {},
    "created_at": "2024-01-15T14:00:00Z",
    "updated_at": "2024-01-15T14:30:00Z"
  },
  "is_new_conversation": false,
  "whatsapp_config": {
    "id": "770e8400-e29b-41d4-a716-446655440002",
    "name": "Production WhatsApp",
    "phone_number_id": "123456789012345",
    "business_account_id": "987654321098765",
    "is_coexistence": false,
    "webhook_verified_at": "2024-01-10T08:00:00Z",
    "created_at": "2024-01-10T08:00:00Z",
    "updated_at": "2024-01-15T14:30:00Z",
    "customer_id": "880e8400-e29b-41d4-a716-446655440003",
    "display_name": "Production WhatsApp",
    "display_phone_number": "+1 (555) 123-4567",
    "display_phone_number_normalized": "+15551234567"
  }
}

Conversation Created/Ended Payload

For the whatsapp.conversation.created and whatsapp.conversation.ended events:
{
  "conversation": {
    "id": "660e8400-e29b-41d4-a716-446655440001",
    "phone_number": "+1234567890",
    "status": "active", // "ended" for conversation.ended events
    "last_active_at": "2024-01-15T14:30:00Z",
    "whatsapp_config_id": "770e8400-e29b-41d4-a716-446655440002",
    "metadata": {},
    "created_at": "2024-01-15T14:30:00Z",
    "updated_at": "2024-01-15T14:30:00Z"
  },
  "whatsapp_config": {
    "id": "770e8400-e29b-41d4-a716-446655440002",
    "name": "Production WhatsApp",
    "phone_number_id": "123456789012345",
    "business_account_id": "987654321098765",
    "is_coexistence": false,
    "webhook_verified_at": "2024-01-10T08:00:00Z",
    "created_at": "2024-01-10T08:00:00Z",
    "updated_at": "2024-01-15T14:30:00Z",
    "customer_id": "880e8400-e29b-41d4-a716-446655440003",
    "display_name": "Production WhatsApp",
    "display_phone_number": "+1 (555) 123-4567",
    "display_phone_number_normalized": "+15551234567"
  }
}
For whatsapp.conversation.ended events, the conversation status will be “ended”. This event is triggered when:
  • An agent ends the conversation through an action
  • A human manually closes the conversation
  • The conversation automatically ends after 24 hours of inactivity
The last_active_at timestamp indicates when the conversation was last active.

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

The message_type_data field contains different information based on the message type:

Media Messages (image/video/document/audio)

{
  "message_type": "image",
  "message_type_data": {
    "caption": "Photo description",
    "has_media": true
  },
  "media_data": {
    "url": "https://app.kapso.ai/rails/active_storage/blobs/...",
    "filename": "photo.jpg",
    "content_type": "image/jpeg",
    "byte_size": 204800
  }
}

Location Messages

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

Template Messages

{
  "message_type": "template",
  "message_type_data": {
    "name": "order_confirmation",
    "language": "en_US",
    "params": ["John", "12345", "$99.99"]
  }
}

Interactive Messages

{
  "message_type": "interactive",
  "message_type_data": {
    "type": "button",
    "body_text": "Please select an option",
    "header_text": "Quick Actions",
    "footer_text": "Choose one"
  }
}

Reaction Messages

{
  "message_type": "reaction",
  "message_type_data": {
    "emoji": "👍",
    "message_id": "wamid.HBgNNTU0MTIzNDU2Nzg5MA"
  }
}

WhatsApp Message Buffering

Message buffering allows you to receive multiple whatsapp.message.received events in a single batched webhook, reducing the load on your servers during high-volume conversations.

How It Works

  1. Debounce Pattern: Messages are collected in a buffer until the configured time window expires without receiving new messages
  2. Automatic Batching: Multiple messages from the same conversation are grouped together
  3. Immediate Delivery: Batches are sent when the maximum batch size is reached or the buffer window expires
  4. Per-Conversation Buffering: Each conversation has its own independent buffer

Configuration

When creating or editing a webhook, enable message buffering for the whatsapp.message.received event:
  • Buffer Window: Time to wait before sending batched messages (1-60 seconds, default: 5)
  • Maximum Batch Size: Maximum messages per batch (1-100, default: 50)

Batched Webhook Format

When messages are buffered, your endpoint receives the same whatsapp.message.received event type with an array of messages:
{
  "type": "whatsapp.message.received",
  "batch": true,
  "data": [
    {
      "message": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "message_type": "text",
        "content": "First message",
        // ... full message object
      },
      "conversation": {
        // ... conversation object
      },
      "is_new_conversation": false,
      "whatsapp_config": {
        // ... config object
      }
    },
    {
      "message": {
        "id": "660e8400-e29b-41d4-a716-446655440001",
        "message_type": "text",
        "content": "Second message",
        // ... full message object
      },
      "conversation": {
        // ... conversation object
      },
      "is_new_conversation": false,
      "whatsapp_config": {
        // ... config object
      }
    }
  ],
  "batch_info": {
    "size": 2,
    "window_ms": 5000,
    "first_sequence": 1,
    "last_sequence": 2,
    "conversation_id": "770e8400-e29b-41d4-a716-446655440002"
  }
}
Single messages continue to use the original format. Check the batch field or X-Webhook-Batch header to determine if you’re receiving a batched delivery.

Verifying WhatsApp Webhooks

Always verify the webhook signature to ensure the request is authentic:
const crypto = require('crypto');

app.post('/webhook/whatsapp', (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const body = JSON.stringify(req.body);
  
  // Your webhook's secret key
  const secret = process.env.WHATSAPP_WEBHOOK_SECRET;
  
  // Calculate expected signature
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(body, 'utf8')
    .digest('hex');
  
  if (signature !== expectedSignature) {
    return res.status(401).send('Invalid signature');
  }
  
  // Process the webhook
  const event = req.headers['x-webhook-event'];
  const idempotencyKey = req.headers['x-idempotency-key'];
  
  // Handle the event...
  
  res.status(200).send('OK');
});

Testing WhatsApp Webhooks

You can test your webhook endpoints directly from the Kapso interface:
  1. Go to your WhatsApp webhook configuration
  2. Click the “Test Webhook” button
  3. Select an event type to test
  4. Review the sample payload that will be sent
  5. Click “Send Test” to trigger a test webhook
The test will use realistic sample data that matches the exact structure of production webhooks.

Webhook Reliability

Kapso implements several features to ensure reliable webhook delivery:
  • Retries: Failed webhooks are retried up to 3 times with fast exponential backoff (10 seconds, 40 seconds, 90 seconds)
  • Total Time to Failure: Approximately 2.5 minutes from first attempt to final failure
  • Timeout: Webhook requests timeout after 30 seconds
  • Idempotency: Each event has a unique idempotency key to prevent duplicate processing
  • Delivery Tracking: All webhook deliveries are logged with full request/response details
  • Message Ordering: WhatsApp message webhooks are delivered in sequence order within conversations to maintain message chronology

WhatsApp Message Ordering

Kapso ensures WhatsApp messages are delivered to your webhooks in the correct order within each conversation:
  • Sequence-based Ordering: Each webhook delivery within a conversation is assigned a sequence number
  • Automatic Queuing: Messages are automatically queued if earlier messages haven’t been delivered yet
  • Ordering Timeout: After 30 seconds, messages are delivered regardless of ordering to prevent indefinite delays
  • Applies To: Message received (whatsapp.message.received) and message sent (whatsapp.message.sent) events
  • Per Conversation: Ordering is maintained within each conversation independently
This ensures your webhook endpoint receives messages in the same order they were sent/received, making it easier to maintain conversation context and state.

Best Practices for WhatsApp Webhooks

  1. Handle Events Asynchronously: Process webhook data in background jobs to respond quickly
  2. Implement Idempotency: Use the X-Idempotency-Key header to prevent processing duplicates
  3. Monitor Failures: Set up alerts for webhook delivery failures
  4. Secure Your Endpoint: Always verify signatures and use HTTPS
  5. Handle All Event Types: Even if you only need certain events now, handle all types gracefully
  6. Process Quickly: Respond within 5 seconds to avoid being marked as failed delivery

Agent Webhooks

Webhooks allow two-way communication: your systems can trigger Kapso agents, and Kapso agents can notify your systems.

Incoming Webhooks (Triggering Agents)

Use incoming webhooks to start an agent’s execution flow from your application (e.g., backend, CRM).
  • Endpoint: Each agent has a unique webhook URL.
    POST https://app.kapso.ai/api/v1/agents/{AGENT_ID}/executions
    
  • Authentication: Include your Project API Key in the X-API-Key request header.
    X-API-Key: your-project-api-key
    
  • Request Body (Optional): Send initial data in the JSON payload.
    {
      "message": "Optional initial message for the agent",
      "phone_number": "1234567890" // Optional identifier
    }
    
  • Example (Node.js):
    const agentWebhookUrl = 'https://app.kapso.ai/api/v1/agents/YOUR_AGENT_ID/executions';
    const apiKey = 'YOUR_PROJECT_API_KEY';
    
    const payload = JSON.stringify({
      message: 'Hello agent!',
      phone_number: '1987654321'
    });
    
    fetch(agentWebhookUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-API-Key': apiKey
      },
      body: payload
    })
    .then(response => response.json())
    .then(data => console.log('Agent execution started:', data))
    .catch(error => console.error('Error triggering agent:', error));
    

Outbound Webhooks (Agent Notifications)

Configure your agents to send real-time notifications to your systems when important events occur during execution.

Configuration

  1. Navigate to your agent’s “API & Webhooks” settings
  2. Add webhook endpoints for the events you want to monitor
  3. Configure a Secret Key for request verification
  4. Select which events to subscribe to

Supported Events

Execution Started

agent_execution_startedFired when an agent begins processing

Execution Ended

agent_execution_endedFired when an agent completes successfully

Execution Failed

agent_execution_failedFired when an agent encounters an error

Handoff Required

agent_execution_handoffFired when human intervention is needed

Security & Verification

Every webhook request includes an X-Webhook-Signature header containing an HMAC SHA-256 signature of the request body. Verify this signature using your configured Secret Key to ensure authenticity.
const crypto = require('crypto');

function verifyWebhookSignature(body, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(body, 'utf8')
    .digest('hex');
  
  return signature === expectedSignature;
}

Webhook Payloads

All webhook payloads include base execution data plus event-specific information:
Base Payload Structure
{
  "event": "event_type",
  "agent_execution": {
    "id": "exec_123abc",
    "started_at": "2024-01-01T12:00:00Z",
    "ended_at": "2024-01-01T12:05:00Z", // null if still running
    "status": "completed", // started, completed, failed, handoff
    "agent_id": "agent_456def"
  },
  "agent": {
    "id": "agent_456def",
    "name": "Customer Support Agent"
  }
}
Event-Specific Data
Handoff Event includes handoff details:
{
  "event": "agent_execution_handoff",
  // ... base payload ...
  "handoff": {
    "node_name": "Escalate to Human",
    "handoff_datetime": "2024-01-01T12:04:30Z",
    "handoff_reason": "Customer requested to speak with a human"
  }
}
Failed Event includes error information:
{
  "event": "agent_execution_failed",
  // ... base payload ...
  "failure": {
    "error": {
      "message": "Failed to connect to external API",
      "type": "ConnectionError"
    },
    "failed_at": "2024-01-01T12:03:15Z"
  }
}

Webhook Best Practices

Important considerations:
  • Respond quickly (within 5 seconds) with a 2xx status code
  • Process webhook data asynchronously if needed
  • Store the webhook secret securely
  • Always verify webhook signatures
  • Implement idempotency handling using the provided idempotency key