Skip to main content

Testing Webhooks

Testing webhooks before deploying to production is essential for ensuring your integration works correctly. This guide covers multiple testing approaches, from using the Dasha BlackBox dashboard to setting up local development environments.

Why Test Webhooks?

Testing webhooks helps you:
  • Validate Endpoints: Ensure your webhook URL is accessible and responds correctly
  • Verify Payloads: Confirm your server handles all event types properly
  • Debug Integration: Identify configuration issues before going live
  • Test Security: Validate signature verification and authentication
  • Check Error Handling: Ensure your server handles retries and timeouts correctly
Best Practice: Always test webhooks in a staging environment before enabling them in production. This prevents disrupting live operations during debugging.

Testing Methods Overview

Choose the testing approach that best fits your workflow:
Best For: Quick validation during development
  • Test from Dasha BlackBox dashboard
  • No external tools required
  • Instant feedback on response
  • Simulates all webhook event types

Method 1: Dashboard Testing

The Dasha BlackBox dashboard provides a built-in webhook testing tool that sends realistic payloads to your endpoint.

Accessing the Test Tool

  1. Navigate to the Webhooks section in your dashboard
  2. Click Test Webhook button
  3. Configure test parameters
  4. Send test request
  5. Review response

Using the API Test Endpoint

You can also test webhooks programmatically using the API:
const testWebhook = async () => {
  const response = await fetch('https://blackbox.dasha.ai/api/v1/webhooks/test', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      webHook: {
        url: 'https://your-server.com/webhook',
        headers: {
          'X-Custom-Header': 'your-value'
        }
      },
      webhookType: 'CompletedWebHookPayload',
      agentAdditionalData: {
        companyName: 'Test Company'
      },
      callAdditionalData: {
        userId: 'test-user-123'
      }
    })
  });

  const result = await response.json();

  console.log('Success:', result.success);
  console.log('HTTP Status:', result.httpStatus);
  console.log('Response Data:', result.responseData);
  console.log('Time Taken:', result.timeTaken, 'ms');

  if (!result.success) {
    console.error('Error:', result.error);
  }
};

testWebhook();

Understanding Test Results

The test endpoint returns detailed information about the webhook delivery: Success Response Example:
{
  "success": true,
  "httpStatus": 200,
  "httpStatusText": "OK",
  "responseData": {
    "message": "Webhook received successfully",
    "processedAt": "2025-01-15T14:30:00Z"
  },
  "validationResult": null,
  "error": null,
  "timeTaken": 245
}
Failed Response Example:
{
  "success": false,
  "httpStatus": 500,
  "httpStatusText": "Internal Server Error",
  "responseData": null,
  "validationResult": null,
  "error": "Connection timeout after 30 seconds",
  "timeTaken": 30000
}
Response Fields:
  • success: Whether webhook delivery succeeded
  • httpStatus: HTTP status code from your endpoint
  • httpStatusText: Status text description
  • responseData: Parsed response body from your endpoint
  • validationResult: Validation errors for StartWebHookPayload responses
  • error: Error message if delivery failed
  • timeTaken: Request duration in milliseconds
Timeout Limit: Webhook endpoints must respond within 30 seconds. If your endpoint takes longer, the test will fail with a timeout error.

Method 2: Testing with webhook.site

webhook.site provides free temporary URLs for inspecting webhook requests without setting up a server.

Setup Process

  1. Get Your Temporary URL:
    • Visit https://webhook.site
    • You’ll receive a unique URL immediately
    • Example: https://webhook.site/abc123-def456-ghi789
  2. Configure in Dasha BlackBox Dashboard:
    • Copy the webhook.site URL
    • Add it to your agent’s webhook configuration
    • Configure which events to receive
  3. Trigger Test Webhooks:
    • Use the Dasha BlackBox test tool (Method 1)
    • Or trigger actual events (make test calls)
  4. Inspect Requests:
    • View full HTTP request details
    • See headers, body, and query parameters
    • Copy payloads for testing

Analyzing Webhook Payloads

webhook.site displays all details of incoming requests: HTTP Headers:
POST /abc123-def456-ghi789 HTTP/1.1
Host: webhook.site
Content-Type: application/json
X-Dasha BlackBox-Signature: sha256=abc123...
X-Dasha BlackBox-Event: call.completed
User-Agent: Dasha BlackBox-Webhook/1.0
Request Body:
{
  "eventType": "call.completed",
  "timestamp": "2025-01-15T14:30:00Z",
  "callId": "call_abc123",
  "agentId": "agent_xyz789",
  "status": "completed",
  "duration": 180,
  "transcript": [
    {
      "speaker": "agent",
      "text": "Hello! How can I help you today?",
      "timestamp": "2025-01-15T14:28:00Z"
    },
    {
      "speaker": "user",
      "text": "I'd like to book an appointment.",
      "timestamp": "2025-01-15T14:28:05Z"
    }
  ]
}

Using webhook.site for Development

Workflow:
  1. Copy Payload Structure: Use webhook.site to see real payload formats
  2. Build Handler: Create webhook handler matching payload structure
  3. Switch to ngrok: Replace webhook.site URL with local development URL
  4. Test Integration: Verify your handler processes webhooks correctly
Payload Library: Save example payloads from webhook.site for each event type. Use these as test fixtures when writing unit tests for your webhook handlers.

Method 3: Testing with RequestBin and Beeceptor

Alternative tools for webhook inspection with additional features.

RequestBin

Free Plan: https://requestbin.com Features:
  • Create temporary public endpoints
  • View request history
  • Inspect headers and body
  • Built-in JSON formatting
  • Custom response configuration
Setup:
# 1. Create a bin at requestbin.com
# You'll get: https://requestbin.com/r/abc123

# 2. Test with Dasha BlackBox
curl -X POST https://blackbox.dasha.ai/api/v1/webhooks/test \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "webHook": {
      "url": "https://requestbin.com/r/abc123"
    },
    "webhookType": "CompletedWebHookPayload"
  }'

# 3. View results at requestbin.com

Beeceptor

Free Plan: https://beeceptor.com Features:
  • Mock API endpoints
  • Custom response rules
  • Request matching patterns
  • Latency simulation
  • Response customization
Setup:
// 1. Create endpoint at beeceptor.com
// Example: https://my-webhook-test.free.beeceptor.com

// 2. Configure custom response rules
// Beeceptor dashboard -> Rules -> Add Rule:
{
  "request": {
    "path": "/webhook",
    "method": "POST"
  },
  "response": {
    "status": 200,
    "headers": {
      "Content-Type": "application/json"
    },
    "body": {
      "received": true,
      "timestamp": "{{now}}"
    }
  }
}

// 3. Test from Dasha BlackBox
const testResult = await fetch('https://blackbox.dasha.ai/api/v1/webhooks/test', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    webHook: {
      url: 'https://my-webhook-test.free.beeceptor.com/webhook'
    },
    webhookType: 'StartWebHookPayload'
  })
});
Advanced Use Cases:
  • Simulate Errors: Configure Beeceptor to return 500 errors to test retry logic
  • Test Timeouts: Add latency rules to simulate slow endpoints
  • Validate Headers: Check that Dasha BlackBox sends correct headers

Method 4: Local Testing with ngrok

ngrok creates secure tunnels to your localhost, enabling testing with your actual application.

ngrok Setup

Installation:
# Using Homebrew
brew install ngrok

# Or download from ngrok.com
curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | \
  sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null
Authentication:
# Sign up at ngrok.com and get your auth token
ngrok config add-authtoken YOUR_AUTH_TOKEN

Starting a Tunnel

Basic Tunnel:
# Start local webhook server on port 3000
ngrok http 3000

# Output:
# Forwarding  https://abc123.ngrok.io -> http://localhost:3000
Custom Subdomain (paid plan):
ngrok http 3000 --subdomain=my-blackbox-webhooks

# URL: https://my-blackbox-webhooks.ngrok.io

Local Webhook Server Example

Node.js + Express:
const express = require('express');
const crypto = require('crypto');

const app = express();
app.use(express.json());

// Webhook signature verification
function verifySignature(payload, signature, secret) {
  const hmac = crypto.createHmac('sha256', secret);
  hmac.update(JSON.stringify(payload));
  const expectedSignature = 'sha256=' + hmac.digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// Webhook endpoint
app.post('/webhook', (req, res) => {
  console.log('Received webhook:', req.body);

  // Verify signature
  const signature = req.headers['x-blackbox-signature'];
  const isValid = verifySignature(req.body, signature, process.env.WEBHOOK_SECRET);

  if (!isValid) {
    console.error('Invalid signature');
    return res.status(401).json({ error: 'Invalid signature' });
  }

  // Process webhook based on payload type
  const { type, callId, agentId, status } = req.body;

  switch (type) {
    case 'StartWebHookPayload':
      console.log(`Call ${callId} started for agent ${agentId}`);
      break;
    case 'CompletedWebHookPayload':
      console.log(`Call ${callId} completed with status: ${status}`);
      break;
    case 'FailedWebHookPayload':
      console.error(`Call ${callId} failed: ${req.body.errorMessage}`);
      break;
    default:
      console.log('Unknown payload type:', type);
  }

  // Respond quickly (under 5 seconds)
  res.status(200).json({
    received: true,
    timestamp: new Date().toISOString()
  });
});

// Health check endpoint
app.get('/health', (req, res) => {
  res.status(200).json({ status: 'healthy' });
});

const PORT = 3000;
app.listen(PORT, () => {
  console.log(`Webhook server listening on port ${PORT}`);
  console.log('Start ngrok: ngrok http 3000');
});
Python + Flask:
from flask import Flask, request, jsonify
import hmac
import hashlib
import json
import os

app = Flask(__name__)

def verify_signature(payload, signature, secret):
    """Verify HMAC signature"""
    expected = 'sha256=' + hmac.new(
        secret.encode(),
        json.dumps(payload).encode(),
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected)

@app.route('/webhook', methods=['POST'])
def webhook():
    payload = request.get_json()
    print(f"Received webhook: {payload}")

    # Verify signature
    signature = request.headers.get('X-Dasha BlackBox-Signature')
    secret = os.environ.get('WEBHOOK_SECRET')

    if not verify_signature(payload, signature, secret):
        print("Invalid signature")
        return jsonify({'error': 'Invalid signature'}), 401

    # Process webhook based on payload type
    payload_type = payload.get('type')
    call_id = payload.get('callId')

    if payload_type == 'StartWebHookPayload':
        print(f"Call {call_id} started")
    elif payload_type == 'CompletedWebHookPayload':
        print(f"Call {call_id} completed")
    elif payload_type == 'FailedWebHookPayload':
        print(f"Call {call_id} failed: {payload.get('errorMessage')}")

    # Respond quickly
    return jsonify({
        'received': True,
        'timestamp': datetime.utcnow().isoformat()
    }), 200

@app.route('/health')
def health():
    return jsonify({'status': 'healthy'}), 200

if __name__ == '__main__':
    app.run(port=3000, debug=True)

Testing with ngrok

Complete Workflow:
# 1. Start your webhook server
node webhook-server.js
# or
python webhook-server.py

# 2. In another terminal, start ngrok
ngrok http 3000

# 3. Copy the HTTPS URL from ngrok output
# Example: https://abc123.ngrok.io

# 4. Test with Dasha BlackBox API
curl -X POST https://blackbox.dasha.ai/api/v1/webhooks/test \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "webHook": {
      "url": "https://abc123.ngrok.io/webhook",
      "headers": {
        "X-Custom-Auth": "your-secret-token"
      }
    },
    "webhookType": "CompletedWebHookPayload"
  }'

# 5. Check your server logs for the received webhook
# 6. Inspect the request in ngrok web interface (http://127.0.0.1:4040)

ngrok Web Interface

ngrok provides a local web UI for inspecting requests:
  1. Access: Open http://127.0.0.1:4040 in your browser
  2. View Requests: See all HTTP requests sent through the tunnel
  3. Replay Requests: Resend previous requests for debugging
  4. Inspect Details: View headers, body, response, and timing
Development Workflow: Use ngrok’s replay feature to resend the same webhook multiple times while debugging your handler code. This saves time compared to triggering new webhooks from Dasha BlackBox.

Method 5: Local Testing with localtunnel

localtunnel is a free alternative to ngrok with no account required.

localtunnel Setup

Installation:
npm install -g localtunnel
Start Tunnel:
# Start your webhook server first
node webhook-server.js

# Then create tunnel in another terminal
lt --port 3000

# Output:
# your url is: https://lucky-cats-12345.loca.lt
Custom Subdomain:
lt --port 3000 --subdomain my-blackbox-webhooks

# URL: https://my-blackbox-webhooks.loca.lt

Testing with localtunnel

Complete Example:
// webhook-server.js
const express = require('express');
const app = express();
app.use(express.json());

app.post('/webhook', (req, res) => {
  console.log('Webhook received:', JSON.stringify(req.body, null, 2));
  res.status(200).json({ received: true });
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
  console.log('Start localtunnel: lt --port 3000');
});
# Terminal 1: Start server
node webhook-server.js

# Terminal 2: Start tunnel
lt --port 3000

# Terminal 3: Test webhook
curl -X POST https://blackbox.dasha.ai/api/v1/webhooks/test \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "webHook": {
      "url": "https://lucky-cats-12345.loca.lt/webhook"
    },
    "webhookType": "StartWebHookPayload",
    "toolName": "check_availability",
    "toolArguments": {
      "date": "2025-01-20",
      "time": "14:00"
    }
  }'

localtunnel vs ngrok

Featurelocaltunnelngrok
CostFreeFree tier + paid plans
Account RequiredNoYes
Custom SubdomainsSometimes availablePaid plan only
StabilityGoodExcellent
Web UINoYes (very useful)
SpeedGoodBetter
FeaturesBasic tunnelingAdvanced inspection tools
Recommendation: Use localtunnel for quick tests and simple debugging. Use ngrok for extended development sessions and advanced debugging with the web UI.

Testing Different Event Types

Dasha BlackBox supports multiple webhook event types. Test each one to ensure your handler works correctly.

Available Event Types

StartWebHookPayload
  • Sent when call starts
  • Can modify agent behavior
  • Must respond under 5 seconds
CompletedWebHookPayload
  • Sent when call completes successfully
  • Contains full transcript
  • Includes call duration and metadata
FailedWebHookPayload
  • Sent when call fails
  • Contains error information
  • Includes failure reason

Testing StartWebHookPayload

This event occurs at call start and can modify agent configuration:
// Test start webhook
const testStartWebhook = async () => {
  const response = await fetch('https://blackbox.dasha.ai/api/v1/webhooks/test', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      webHook: {
        url: 'https://your-server.com/webhook/start',
        headers: {
          'Authorization': 'Bearer YOUR_WEBHOOK_SECRET'
        }
      },
      webhookType: 'StartWebHookPayload',
      agentAdditionalData: {
        companyName: 'Acme Corp',
        supportLevel: 'premium'
      },
      callAdditionalData: {
        customerId: 'cust_12345',
        accountType: 'enterprise'
      }
    })
  });

  const result = await response.json();
  console.log('Start webhook test:', result);

  // Check if your endpoint returns valid StartWebhookResponse
  if (result.validationResult && !result.validationResult.isValid) {
    console.error('Validation errors:', result.validationResult.errors);
  }
};
Expected Webhook Payload:
{
  "type": "StartWebHookPayload",
  "status": "Queued",
  "callId": "call_test_abc123",
  "agentId": "agent_xyz789",
  "orgId": "org_123abc",
  "endpoint": "+12025551234",
  "agentAdditionalData": {
    "companyName": "Acme Corp",
    "supportLevel": "premium"
  },
  "callAdditionalData": {
    "customerId": "cust_12345",
    "accountType": "enterprise"
  },
  "originalAgentConfig": {
    "primaryLanguage": "en-US",
    "llmConfig": { "vendor": "openai", "model": "gpt-4.1-mini" }
  }
}
Valid Response Format:
{
  "systemPrompt": "You are a premium support agent for Acme Corp. The customer is an enterprise client (ID: cust_12345). Provide expedited service.",
  "additionalData": {
    "customerHistory": {
      "lastCallDate": "2025-01-10",
      "issuesResolved": 5
    }
  }
}

Testing CompletedWebHookPayload

This event occurs after call completion:
// Test completed webhook
const testCompletedWebhook = async () => {
  const response = await fetch('https://blackbox.dasha.ai/api/v1/webhooks/test', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      webHook: {
        url: 'https://your-server.com/webhook/completed'
      },
      webhookType: 'CompletedWebHookPayload',
      callAdditionalData: {
        orderId: 'order_98765',
        appointmentBooked: true
      }
    })
  });

  const result = await response.json();
  console.log('Completed webhook test:', result);
};
Expected Payload:
{
  "type": "CompletedWebHookPayload",
  "status": "Completed",
  "callId": "call_test_abc123",
  "agentId": "agent_xyz789",
  "orgId": "org_123abc",
  "callType": "OutboundAudio",
  "createdTime": "2025-01-15T14:30:00.000Z",
  "completedTime": "2025-01-15T14:33:00.000Z",
  "durationSeconds": 180,
  "inspectorUrl": "https://blackbox.dasha.ai/calls/call_test_abc123",
  "transcription": [
    {
      "speaker": "assistant",
      "text": "Hello! How can I help you today?",
      "startTime": "2025-01-15T14:30:05.000Z",
      "endTime": "2025-01-15T14:30:08.000Z"
    },
    {
      "speaker": "user",
      "text": "I need to book an appointment.",
      "startTime": "2025-01-15T14:30:10.000Z",
      "endTime": "2025-01-15T14:30:13.000Z"
    }
  ],
  "result": {
    "finishReason": "user_hangup",
    "status": "success"
  },
  "callAdditionalData": {
    "orderId": "order_98765",
    "appointmentBooked": true
  },
  "agentAdditionalData": {}
}

Testing FailedWebHookPayload

Test error handling and retry logic:
// Test failed webhook
const testFailedWebhook = async () => {
  const response = await fetch('https://blackbox.dasha.ai/api/v1/webhooks/test', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      webHook: {
        url: 'https://your-server.com/webhook/failed'
      },
      webhookType: 'FailedWebHookPayload',
      callAdditionalData: {
        attemptNumber: 3,
        originalCallTime: '2025-01-15T14:00:00Z'
      }
    })
  });

  const result = await response.json();
  console.log('Failed webhook test:', result);
};
Expected Payload:
{
  "type": "FailedWebHookPayload",
  "status": "Failed",
  "callId": "call_test_abc123",
  "agentId": "agent_xyz789",
  "orgId": "org_123abc",
  "callType": "OutboundAudio",
  "createdTime": "2025-01-15T14:30:00.000Z",
  "completedTime": "2025-01-15T14:31:00.000Z",
  "errorMessage": "Call did not connect within timeout period",
  "inspectorUrl": "https://blackbox.dasha.ai/calls/call_test_abc123",
  "callAdditionalData": {
    "attemptNumber": 3,
    "originalCallTime": "2025-01-15T14:00:00Z"
  },
  "agentAdditionalData": {}
}

Testing ToolWebHookPayload

Test function calling integration:
// Test tool webhook
const testToolWebhook = async () => {
  const response = await fetch('https://blackbox.dasha.ai/api/v1/webhooks/test', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      webHook: {
        url: 'https://your-server.com/webhook/tool'
      },
      webhookType: 'ToolWebHookPayload',
      toolName: 'check_availability',
      toolArguments: {
        date: '2025-01-20',
        time: '14:00',
        duration: 30
      },
      agentAdditionalData: {
        businessId: 'biz_12345'
      }
    })
  });

  const result = await response.json();
  console.log('Tool webhook test:', result);
  console.log('Your tool response:', result.responseData);
};
Expected Payload:
{
  "eventType": "tool.called",
  "timestamp": "2025-01-15T14:30:30Z",
  "callId": "call_test_abc123",
  "agentId": "agent_xyz789",
  "toolName": "check_availability",
  "toolArguments": {
    "date": "2025-01-20",
    "time": "14:00",
    "duration": 30
  },
  "agentAdditionalData": {
    "businessId": "biz_12345"
  }
}
Expected Response:
{
  "available": true,
  "slots": [
    { "time": "14:00", "duration": 30 },
    { "time": "14:30", "duration": 30 },
    { "time": "15:00", "duration": 30 }
  ],
  "message": "We have several slots available on January 20th."
}

Verifying Webhook Signatures

Always verify webhook signatures to ensure requests come from Dasha BlackBox.

Signature Verification Process

Dasha BlackBox includes an X-Dasha BlackBox-Signature header with each webhook:
X-Dasha BlackBox-Signature: sha256=abc123def456...
Verification Steps:
  1. Extract signature from header
  2. Compute HMAC-SHA256 of request body using your secret
  3. Compare computed signature with received signature
  4. Reject request if signatures don’t match

Implementation Examples

const crypto = require('crypto');

function verifyWebhookSignature(req, webhookSecret) {
  // Get signature from header
  const receivedSignature = req.headers['x-blackbox-signature'];

  if (!receivedSignature) {
    throw new Error('Missing signature header');
  }

  // Extract hash from "sha256=..." format
  const receivedHash = receivedSignature.replace('sha256=', '');

  // Compute expected signature
  const payload = JSON.stringify(req.body);
  const hmac = crypto.createHmac('sha256', webhookSecret);
  hmac.update(payload);
  const expectedHash = hmac.digest('hex');

  // Timing-safe comparison
  const isValid = crypto.timingSafeEqual(
    Buffer.from(receivedHash, 'hex'),
    Buffer.from(expectedHash, 'hex')
  );

  if (!isValid) {
    throw new Error('Invalid webhook signature');
  }

  return true;
}

// Usage in Express route
app.post('/webhook', (req, res) => {
  try {
    verifyWebhookSignature(req, process.env.WEBHOOK_SECRET);

    // Process webhook
    console.log('Valid webhook:', req.body);
    res.status(200).json({ received: true });

  } catch (error) {
    console.error('Signature verification failed:', error);
    res.status(401).json({ error: 'Invalid signature' });
  }
});

Testing Signature Verification

Test Valid Signature:
// Generate valid signature for testing
const crypto = require('crypto');

const payload = {
  eventType: 'call.completed',
  callId: 'call_test_123'
};

const secret = 'your-webhook-secret';
const payloadStr = JSON.stringify(payload);
const signature = 'sha256=' + crypto
  .createHmac('sha256', secret)
  .update(payloadStr)
  .digest('hex');

console.log('Valid signature:', signature);

// Test your endpoint
fetch('https://your-server.com/webhook', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Dasha BlackBox-Signature': signature
  },
  body: payloadStr
});
Test Invalid Signature:
// Send request with wrong signature
fetch('https://your-server.com/webhook', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Dasha BlackBox-Signature': 'sha256=invalid_signature_here'
  },
  body: JSON.stringify({
    eventType: 'call.completed',
    callId: 'call_test_123'
  })
});

// Your endpoint should return 401 Unauthorized
Security Critical: Always verify signatures in production. Failing to verify signatures allows attackers to send fake webhooks to your endpoints.

Testing Retry Behavior

Dasha BlackBox automatically retries failed webhook deliveries. Test your endpoint’s retry handling.

Retry Configuration

Dasha BlackBox retries failed webhooks with exponential backoff:
  • Attempt 1: Immediate
  • Attempt 2: After 1 minute
  • Attempt 3: After 5 minutes
  • Attempt 4: After 15 minutes
  • Attempt 5: After 1 hour
Retry Triggers:
  • HTTP status codes 500-599
  • Connection timeouts (over 30 seconds)
  • Network errors (DNS failures, connection refused)
No Retry:
  • HTTP status codes 200-299 (success)
  • HTTP status codes 400-499 (client errors)

Simulating Retry Scenarios

Test Temporary Failure:
// webhook-server.js
let attemptCount = 0;

app.post('/webhook', (req, res) => {
  attemptCount++;

  console.log(`Webhook attempt ${attemptCount}`);

  // Fail first 2 attempts, succeed on 3rd
  if (attemptCount <= 2) {
    console.log('Simulating failure');
    res.status(500).json({ error: 'Temporary server error' });
  } else {
    console.log('Processing webhook successfully');
    res.status(200).json({ received: true });
  }
});
Test Idempotency:
// Store processed webhook IDs to prevent duplicate processing
const processedWebhooks = new Set();

app.post('/webhook', (req, res) => {
  const webhookId = req.body.callId + '_' + req.body.timestamp;

  // Check if already processed
  if (processedWebhooks.has(webhookId)) {
    console.log('Duplicate webhook, already processed:', webhookId);
    // Still return 200 to prevent retries
    return res.status(200).json({
      received: true,
      duplicate: true
    });
  }

  // Process webhook
  processedWebhooks.add(webhookId);
  console.log('Processing new webhook:', webhookId);

  // Your business logic here

  res.status(200).json({ received: true });
});
Test Timeout Handling:
// Simulate slow endpoint
app.post('/webhook-slow', async (req, res) => {
  console.log('Received webhook, processing slowly...');

  // Simulate 35 second processing (over 30s timeout)
  await new Promise(resolve => setTimeout(resolve, 35000));

  // This will trigger a timeout in Dasha BlackBox
  res.status(200).json({ received: true });
});

Monitoring Retry Attempts

Add Retry Headers (if your server supports them):
app.post('/webhook', (req, res) => {
  // Dasha BlackBox may send retry attempt number in custom header
  const attemptNumber = req.headers['x-blackbox-attempt'] || 1;

  console.log(`Processing webhook attempt ${attemptNumber}`);

  // Process webhook
  res.status(200).json({
    received: true,
    attemptNumber: parseInt(attemptNumber)
  });
});

Testing Timeout Handling

Webhook endpoints must respond within 30 seconds. Test timeout scenarios.

Timeout Requirements

Response Time Limits:
  • StartWebHookPayload: under 5 seconds (blocking call start)
  • ToolWebHookPayload: under 10 seconds (blocking conversation)
  • Other webhooks: under 30 seconds (non-blocking)

Testing Response Times

Measure Endpoint Performance:
// webhook-server.js with timing
app.post('/webhook', (req, res) => {
  const startTime = Date.now();

  // Process webhook
  const eventType = req.body.eventType;
  console.log(`Processing ${eventType}...`);

  // Your business logic here
  processWebhook(req.body);

  const duration = Date.now() - startTime;
  console.log(`Webhook processed in ${duration}ms`);

  // Warn if approaching timeout
  if (duration > 25000) {
    console.warn('WARNING: Response time approaching 30s timeout!');
  }

  res.status(200).json({
    received: true,
    processingTime: duration
  });
});
Optimize Slow Endpoints:
// BAD: Synchronous processing blocks response
app.post('/webhook-bad', (req, res) => {
  // This might take over 30 seconds
  const result = processLargeDataset(req.body);
  updateDatabase(result);
  sendNotifications(result);

  res.status(200).json({ received: true });
});

// GOOD: Async processing with quick response
app.post('/webhook-good', (req, res) => {
  // Respond immediately
  res.status(200).json({ received: true });

  // Process asynchronously
  setImmediate(() => {
    const result = processLargeDataset(req.body);
    updateDatabase(result);
    sendNotifications(result);
  });
});
Use Queue for Heavy Processing:
// webhook-server.js with queue
const Queue = require('bull');
const webhookQueue = new Queue('webhooks');

// Quick response, queue processing
app.post('/webhook', async (req, res) => {
  // Add to queue (fast operation)
  await webhookQueue.add({
    payload: req.body,
    receivedAt: new Date().toISOString()
  });

  // Respond immediately
  res.status(200).json({ received: true, queued: true });
});

// Process queue asynchronously
webhookQueue.process(async (job) => {
  const { payload } = job.data;

  // Heavy processing here (no time limit)
  const result = await processWebhook(payload);
  await updateDatabase(result);
  await sendNotifications(result);

  return result;
});

Debugging Webhook Deliveries

When webhooks fail, use these debugging techniques to identify the issue.

Common Webhook Failures

Symptoms:
  • “Connection refused”
  • “DNS resolution failed”
  • “SSL certificate error”
Solutions:
  • Verify URL is correct and accessible
  • Check firewall and security group rules
  • Ensure SSL certificate is valid
  • Test with curl from external server

Webhook Delivery Logs

Dasha BlackBox logs all webhook delivery attempts. Webhook delivery history and statistics are available in the dashboard only. Dashboard:
  1. Navigate to Webhooks section
  2. Select webhook configuration
  3. Click Delivery Logs
  4. Filter by date, status, or event type
Webhook delivery logs are currently only accessible through the dashboard. There is no API endpoint for retrieving delivery history programmatically.

Debugging Checklist

Pre-Deployment Checklist:
  • Webhook URL is publicly accessible (not localhost)
  • Endpoint responds with 200 status code
  • Response time is under required limit (5s/10s/30s)
  • Signature verification is implemented
  • Error handling is comprehensive
  • Idempotency is handled (duplicate webhooks)
  • Logging is enabled for debugging
  • Retry logic is tested
  • Timeout scenarios are tested
  • All event types are tested
Troubleshooting Steps:
  1. Test with webhook.site: Verify Dasha BlackBox sends webhooks correctly
  2. Test with ngrok: Verify your local handler works
  3. Check server logs: Look for errors in your application logs
  4. Verify signature: Ensure signature verification doesn’t reject valid requests
  5. Measure timing: Confirm response times are under limits
  6. Test retry: Verify idempotency and duplicate handling
  7. Check network: Ensure firewall/proxy allows Dasha BlackBox IPs

Production Testing Checklist

Before enabling webhooks in production, complete this comprehensive checklist.

Security Testing

Authentication & Authorization:
  • Webhook secret is stored securely (environment variable, not code)
  • Signature verification is enabled and tested
  • HTTPS is enforced (reject HTTP webhooks)
  • API keys/tokens use least-privilege access
  • Webhook URLs don’t expose sensitive information
Input Validation:
  • Request body is validated against expected schema
  • Event types are whitelisted
  • Payload size limits are enforced
  • SQL injection protection (if storing webhook data)
  • XSS protection (if displaying webhook data)

Performance Testing

Load Testing:
// Simulate high webhook volume
const loadTest = async () => {
  const promises = [];

  // Send 100 concurrent webhooks
  for (let i = 0; i < 100; i++) {
    promises.push(
      fetch('https://blackbox.dasha.ai/api/v1/webhooks/test', {
        method: 'POST',
        headers: {
          'Authorization': 'Bearer YOUR_API_KEY',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          webHook: {
            url: 'https://your-server.com/webhook'
          },
          webhookType: 'CompletedWebHookPayload'
        })
      })
    );
  }

  const results = await Promise.allSettled(promises);
  const successes = results.filter(r => r.status === 'fulfilled').length;
  const failures = results.filter(r => r.status === 'rejected').length;

  console.log(`Load test complete: ${successes} succeeded, ${failures} failed`);
};
Performance Metrics:
  • Endpoint handles expected webhook volume
  • Response times consistently under limits
  • No memory leaks during extended testing
  • Database connections are properly managed
  • Queue processing keeps up with incoming webhooks

Reliability Testing

Failure Scenarios:
  • Endpoint recovers from crashes
  • Database connection failures are handled
  • External API failures don’t block webhook responses
  • Malformed payloads don’t crash server
  • Very large payloads are handled gracefully
Idempotency Testing:
// Test duplicate webhook handling
const testIdempotency = async () => {
  const payload = {
    webHook: {
      url: 'https://your-server.com/webhook'
    },
    webhookType: 'CompletedWebHookPayload'
  };

  // Send same webhook 3 times
  for (let i = 0; i < 3; i++) {
    await fetch('https://blackbox.dasha.ai/api/v1/webhooks/test', {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer YOUR_API_KEY',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(payload)
    });

    console.log(`Sent duplicate ${i + 1}`);
  }

  // Verify your server only processed it once
};

Monitoring & Alerting

Logging:
  • All webhook receipts are logged
  • Errors are logged with full context
  • Slow requests are logged (over 10 seconds)
  • Signature verification failures are logged
  • Logs include trace IDs for debugging
Alerts:
  • Alert on webhook delivery failures
  • Alert on signature verification failures
  • Alert on response time degradation
  • Alert on error rate spikes
  • Alert on queue backlog growth

Documentation

Runbook:
  • Document webhook endpoint locations
  • Document environment variables needed
  • Document retry behavior expectations
  • Document escalation procedures
  • Document rollback procedures

Next Steps

After testing webhooks thoroughly:
  1. Enable in Production: Configure webhooks in production agents
  2. Monitor Deliveries: Watch webhook logs for issues
  3. Optimize Performance: Improve response times based on metrics
  4. Scale Infrastructure: Add capacity as webhook volume grows