Webhook Integration Guide

Overview

Our webhook system enables real-time notifications for message events in your conversations. When a message is created or processed in your conversation, our system sends HTTP POST requests to your configured webhook URL with detailed message information.

Quick Start

1. Configure Webhook

Add a webhook URL to your conversation configuration:

{
    "channel": "API",
    "usecase": "WORKFLOW_EXECUTION",
    "config": {
        "workflow_id": "123",
        "callback_url": "https://your-domain.com/webhook" // Required
    }
}

2. Implement Webhook Handler

=== “Django”

from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
import json

@csrf_exempt
def webhook_handler(request):
    try:
        payload = json.loads(request.body)
        # Process payload asynchronously
        process_webhook.delay(payload)
        return HttpResponse(status=200)
    except Exception as e:
        logger.error(f"Webhook processing error: {str(e)}")
        return HttpResponse(status=200)  # Always acknowledge receipt

=== “FastAPI”

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

app = FastAPI()

@app.post("/webhook")
async def webhook_handler(request: Request):
    try:
        payload = await request.json()
        # Process payload asynchronously
        process_webhook.delay(payload)
        return JSONResponse(status_code=200)
    except Exception as e:
        logger.error(f"Webhook processing error: {str(e)}")
        return JSONResponse(status_code=200)

=== “Flask”

from flask import Flask, request

app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def webhook_handler():
    try:
        payload = request.get_json()
        # Process payload asynchronously
        process_webhook.delay(payload)
        return '', 200
    except Exception as e:
        logger.error(f"Webhook processing error: {str(e)}")
        return '', 200

=== “Express.js”

const express = require('express');
const app = express();

app.post('/webhook', express.json(), async (req, res) => {
    try {
        const payload = req.body;
        // Process payload asynchronously
        await processWebhook(payload);
        res.sendStatus(200);
    } catch (err) {
        console.error(`Webhook processing error: ${err.message}`);
        res.sendStatus(200); // Always acknowledge receipt
    }
});

=== “Spring Boot”

@RestController
public class WebhookController {
    @PostMapping("/webhook")
    public ResponseEntity<Void> handleWebhook(@RequestBody String payload) {
        try {
            // Process payload asynchronously
            webhookService.processWebhook(payload);
            return ResponseEntity.ok().build();
        } catch (Exception e) {
            logger.error("Webhook processing error: " + e.getMessage());
            return ResponseEntity.ok().build(); // Always acknowledge receipt
        }
    }
}

=== “PHP”

<?php

// Receive POST data
$rawPayload = file_get_contents('php://input');

try {
    // Parse JSON payload
    $payload = json_decode($rawPayload, true);
    if (json_last_error() !== JSON_ERROR_NONE) {
        throw new Exception('Invalid JSON payload');
    }

    // Log webhook receipt
    error_log('Webhook received: ' . $rawPayload);

    // Process payload asynchronously (using a job queue system like Laravel Queue or Gearman)
    processWebhookAsync($payload);

    // Always return 200 response
    http_response_code(200);
    echo json_encode(['status' => 'success']);

} catch (Exception $e) {
    error_log('Webhook processing error: ' . $e->getMessage());

    // Still return 200 to acknowledge receipt
    http_response_code(200);
    echo json_encode(['status' => 'received']);
}

/**
    * Example async processing function
    * In practice, this should use a proper job queue
    */
function processWebhookAsync($payload) {
    // Add to job queue or process directly
    // Example using Laravel Queue:
    // ProcessWebhook::dispatch($payload);
}

Technical Specifications

Delivery System

  • Protocol: HTTPS only (for security)
  • Method: POST
  • Content-Type: application/json
  • Timeout: 30 seconds per request
  • Retry Logic: 3 attempts with exponential backoff

Retry Configuration

  • Maximum Attempts: 3
  • Backoff Schedule:
    • 1st retry: 4 seconds wait
    • 2nd retry: 8 seconds wait
    • 3rd retry: 10 seconds wait
  • Retry Conditions:
    • Network errors
    • Timeouts
    • Non-2xx responses

Security Requirements

  • HTTPS protocol mandatory
  • Valid SSL certificate
  • Public endpoint accessibility
  • 2xx status code response expected
  • IP whitelist recommended
  • Request signing (optional but recommended)

Webhook Payload

Structure

{
    "conversation_id": "uuid-string",
    "data": {
        "id": "message-uuid",
        "content": "Message content",
        "content_type": "TEXT",
        "filename": "document.pdf", // Only present for media messages
        "type": "USER_INPUT",
        "channel": "API",
        "status": "RECEIVED",
        "metadata": {
            // Optional custom metadata
        },
        "created_by": "user123",
        "updated_by": "user123",
        "created_at": "2024-03-21T10:00:00Z",
        "updated_at": "2024-03-21T10:00:00Z"
    },
    "timestamp": "2024-03-21T10:00:00.000Z"
}

Field Reference

FieldTypeRequiredDescription
conversation_idUUIDYesUnique identifier for the conversation
data.idUUIDYesUnique identifier for the message
data.contentStringYesThe actual message content
data.content_typeEnumYesType of content (TEXT, IMAGE, VIDEO, DOCUMENT, AUDIO)
data.filenameStringNoPresent only for media messages
data.typeEnumYesMessage type (USER_INPUT, SYSTEM, BOT)
data.channelEnumYesCommunication channel (API, WHATSAPP, SMS)
data.statusEnumYesMessage status (RECEIVED, PROCESSED, FAILED)
data.metadataObjectNoCustom metadata for the message
data.created_byStringYesID or name of the creator
data.updated_byStringYesID or name of the last modifier
data.created_atISO 8601YesCreation timestamp
data.updated_atISO 8601YesLast update timestamp
timestampISO 8601YesWebhook event timestamp

Best Practices

Performance

  1. Quick Acknowledgment

    • Return 2xx status immediately
    • Process webhook data asynchronously
    • Keep handler logic minimal
    • Use background workers for processing
  2. Idempotency Handling

    def handle_webhook(payload):
        message_id = payload['data']['id']
        if is_already_processed(message_id):
            logger.info(f"Skipping duplicate message: {message_id}")
            return
    
        try:
            process_message(payload)
            mark_as_processed(message_id)
        except Exception as e:
            logger.error(f"Processing failed for {message_id}: {str(e)}")
            raise
    

Error Handling

  1. Graceful Recovery

    def webhook_handler(request):
        try:
            payload = json.loads(request.body)
            validate_payload(payload)  # Validate required fields
    
            # Store raw webhook for backup
            store_raw_webhook(payload)
    
            # Process asynchronously
            process_webhook.delay(payload)
    
        except json.JSONDecodeError:
            logger.error("Invalid JSON payload")
        except ValidationError as e:
            logger.error(f"Validation failed: {str(e)}")
        except Exception as e:
            logger.exception("Webhook processing failed")
            store_failed_webhook(payload)
    
        # Always acknowledge receipt
        return HttpResponse(status=200)
    
  2. Logging Best Practices

    def log_webhook(payload):
        logger.info("Webhook received", extra={
            'conversation_id': payload['conversation_id'],
            'message_id': payload['data']['id'],
            'content_type': payload['data']['content_type'],
            'channel': payload['data']['channel'],
            'timestamp': payload['timestamp']
        })
    

Testing & Development

Local Testing

  1. Using ngrok

    # Start ngrok
    ngrok http 8000
    
    # Update webhook URL
    {
        "config": {
            "callback_url": "https://your-ngrok-url/webhook"
        }
    }
    
  2. Manual Testing

    # Test payload generator
    def generate_test_payload():
        return {
            "conversation_id": str(uuid.uuid4()),
            "data": {
                "id": str(uuid.uuid4()),
                "content": "Test message",
                "content_type": "TEXT",
                "type": "USER_INPUT",
                "channel": "API",
                "status": "RECEIVED",
                "created_at": datetime.now().isoformat(),
                "updated_at": datetime.now().isoformat()
            },
            "timestamp": datetime.now().isoformat()
        }
    

Webhook Testing Tools

  1. webhook.site

    • Quick webhook inspection
    • Real-time request monitoring
    • Headers and payload validation
    • Response simulation
  2. Custom Test Suite

    class WebhookTests(TestCase):
        def test_webhook_handler(self):
            payload = generate_test_payload()
            response = client.post(
                '/webhook',
                json=payload,
                headers={'Content-Type': 'application/json'}
            )
            self.assertEqual(response.status_code, 200)
    
        def test_invalid_payload(self):
            response = client.post(
                '/webhook',
                data="invalid json",
                headers={'Content-Type': 'application/json'}
            )
            self.assertEqual(response.status_code, 200)
    

Monitoring & Troubleshooting

Health Checks

  1. Metrics to Monitor

    • Webhook delivery success rate
    • Average response time
    • Retry attempt counts
    • Error rates by type
    • Processing time distribution
  2. Alerting Rules

    • High error rate threshold
    • Response time degradation
    • Retry count spikes
    • Failed delivery clusters

Common Issues & Solutions

IssuePossible CausesSolution
TimeoutsSlow processingImplement async processing
Heavy payloadOptimize payload size
Network latencyReduce processing time
SSL ErrorsInvalid certificateUpdate SSL certificate
Expired certificateSet up auto-renewal
Certificate mismatchVerify domain matching
404 ErrorsInvalid URLCheck webhook configuration
URL changedUpdate webhook URL
Service unavailableVerify service status

Debug Checklist

  • Verify webhook URL configuration
  • Check SSL certificate validity
  • Monitor server logs for errors
  • Validate payload format
  • Test endpoint accessibility
  • Verify network connectivity
  • Check rate limiting
  • Monitor system resources

Support

For webhook-related assistance, please provide:

  • Conversation ID
  • Message ID
  • Timestamp of issue
  • Server logs
  • Webhook configuration
  • Error messages
  • Retry attempt logs

Rate Limiting

  • Maximum 10 concurrent webhook deliveries
  • Maximum 100 webhooks per minute per endpoint
  • Automatic back-pressure handling
  • Rate limit headers included in responses