Developer Tools March 31, 2025 10 min read

How to Mock Webhook Events for Testing

Sarah Johnson

Sarah Johnson

Integration Specialist at CloudConnect

Webhook testing dashboard

Testing webhook integrations is notoriously challenging. You need to deploy your code to receive external events, set up proper environments, and trigger events from third-party services. In this guide, I'll show you how to use mockly.me's webhook testing tools to easily test webhook integrations locally without any of these headaches.

Understanding the Webhook Testing Challenge

Webhooks are a powerful way for applications to communicate asynchronously, but they present unique testing challenges:

  • Your application needs to be publicly accessible to receive webhooks
  • You need to trigger real events from third-party services
  • Testing edge cases and error scenarios is difficult
  • Setting up test environments with proper security is time-consuming

Mockly.me's webhook testing tools solve these problems by providing a complete webhook development environment on your local machine.

Getting Started with Mockly Webhook Inspector

The Webhook Inspector gives you an instant endpoint that captures webhook events and lets you inspect, replay, and forward them to your local environment.

Step 1: Create Your Webhook Endpoint

# Using the mockly CLI
mockly webhook create --name stripe-payment

# Or via the web dashboard at https://mockly.me/dashboard/webhooks

This creates a unique endpoint like https://mockly.me/webhook/abc123 that will capture any incoming webhook events.

Tip

You can create multiple webhook endpoints for different services or scenarios, keeping your testing organized.

Step 2: Configure Your Webhook Provider

Use your mockly endpoint URL in your third-party service's webhook configuration. For example, in Stripe's dashboard:

# In Stripe Dashboard > Developers > Webhooks > Add endpoint
Endpoint URL: https://mockly.me/webhook/abc123
Events to send: payment_intent.succeeded, payment_intent.failed
Stripe webhook configuration

Stripe webhook configuration example

Step 3: Inspect Incoming Webhooks

When your webhook endpoint receives an event, you can inspect it in real-time through the Mockly dashboard or CLI:

# View incoming webhooks via CLI
mockly webhook logs --name stripe-payment

# Or view through the web dashboard
# https://mockly.me/dashboard/webhooks/stripe-payment

Each webhook event shows you complete details including:

  • Full request headers and body
  • Request method and timestamp
  • JSON validation and prettification
  • Source IP address

Simulating Webhook Events

Rather than waiting for real events from a third-party service, you can simulate webhook events using Mockly's event templates.

Using Pre-Made Event Templates

Mockly provides templates for popular webhook providers:

# Send a simulated Stripe payment succeeded event
mockly webhook send stripe-payment-succeeded --to http://localhost:3000/webhook

Available templates for popular services include:

Stripe

  • payment_intent.succeeded
  • payment_intent.failed
  • checkout.session.completed
  • customer.subscription.created
  • invoice.payment_succeeded

GitHub

  • push
  • pull_request.opened
  • pull_request.closed
  • issues.opened
  • release.published

Discord

  • interaction.command
  • message.created
  • guild.member.added
  • channel.created

Shopify

  • orders.created
  • products.created
  • customers.created
  • carts.updated
  • fulfillments.created

Creating Custom Webhook Events

You can also create custom webhook events for your specific needs:

# Create a custom event from a JSON file
mockly webhook send custom --file ./my-event.json --to http://localhost:3000/webhook

# Or specify a JSON string directly
mockly webhook send custom --json '{"event": "test", "data": {"id": 123}}' --to http://localhost:3000/webhook

This is useful for testing edge cases or specific data scenarios in your webhook handlers.

Testing Stripe Webhook Integration

Let's walk through a complete example of testing a Stripe webhook integration for a subscription payment system.

Step 1: Set Up Your Webhook Endpoint

# Create a webhook endpoint for Stripe
mockly webhook create --name stripe-subscription

# Copy your unique webhook URL
https://mockly.me/webhook/abc123

Step 2: Configure Stripe (Test Mode)

In your Stripe dashboard (in test mode), add your Mockly webhook URL and select the subscription-related events:

  • customer.subscription.created
  • customer.subscription.updated
  • customer.subscription.deleted
  • invoice.payment_succeeded
  • invoice.payment_failed

Step 3: Create a Node.js Webhook Handler

// webhook-handler.js
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = 3000;

// Parse JSON requests
app.use(bodyParser.json());

// Webhook endpoint
app.post('/webhook', (req, res) => {
  const event = req.body;
  
  console.log('Received event:', event.type);
  
  // Handle different event types
  switch (event.type) {
    case 'customer.subscription.created':
      handleSubscriptionCreated(event.data.object);
      break;
    case 'invoice.payment_succeeded':
      handlePaymentSuccess(event.data.object);
      break;
    case 'invoice.payment_failed':
      handlePaymentFailure(event.data.object);
      break;
    // Add more cases as needed
    default:
      console.log(`Unhandled event type: ${event.type}`);
  }
  
  // Return a 200 response to acknowledge receipt of the event
  res.status(200).send('Webhook received');
});

// Subscription handlers
function handleSubscriptionCreated(subscription) {
  console.log('New subscription created:', subscription.id);
  // Add your subscription creation logic here
}

function handlePaymentSuccess(invoice) {
  console.log('Payment succeeded for invoice:', invoice.id);
  // Add your payment success logic here
}

function handlePaymentFailure(invoice) {
  console.log('Payment failed for invoice:', invoice.id);
  // Add your payment failure logic here
}

app.listen(port, () => {
  console.log(`Webhook server listening at http://localhost:${port}`);
});

Step 4: Forward Webhooks to Your Local Server

Use the Mockly CLI to forward incoming webhook events to your local server:

# Forward webhooks to your local server
mockly webhook forward --from stripe-subscription --to http://localhost:3000/webhook

Now, any events received by your Mockly endpoint will be automatically forwarded to your local server.

Step 5: Trigger Test Events

You can trigger test events either from the Stripe dashboard or using Mockly's simulation features:

# Simulate a subscription created event
mockly webhook send stripe-subscription-created --to http://localhost:3000/webhook

# Simulate a payment succeeded event
mockly webhook send stripe-payment-succeeded --to http://localhost:3000/webhook

# Simulate a payment failed event
mockly webhook send stripe-payment-failed --to http://localhost:3000/webhook

Debugging Tip

If your webhook handler isn't responding as expected, use the Mockly dashboard to inspect the exact request that was sent and compare it with what your handler expects.

Advanced Webhook Testing

Testing GitHub Webhooks

GitHub webhooks are commonly used for CI/CD pipelines and automation. Here's how to test them with Mockly:

# Create a webhook endpoint for GitHub
mockly webhook create --name github-events

# Configure in GitHub repository settings:
# Settings > Webhooks > Add webhook
# Payload URL: https://mockly.me/webhook/github-abc123
# Content type: application/json
# Events: Choose specific events (e.g., push, pull_request)

To simulate a GitHub push event:

# Simulate a GitHub push event
mockly webhook send github-push --to http://localhost:3000/webhook

Securing Webhooks with Signatures

Many webhook providers sign their payloads to verify authenticity. Mockly supports testing signature verification:

// Verify Stripe signatures
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const crypto = require('crypto');

// Your webhook secret from Stripe
const webhookSecret = 'whsec_1234567890';

app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => {
  const signature = req.headers['stripe-signature'];
  let event;
  
  try {
    // Verify the signature
    const payload = req.body;
    const signedPayload = `${req.headers['stripe-signature'].split(',')[0].split('=')[1]}.${payload}`;
    const hmac = crypto.createHmac('sha256', webhookSecret);
    const digest = hmac.update(signedPayload).digest('hex');
    const checksum = req.headers['stripe-signature'].split(',')[1].split('=')[1];
    
    if (digest !== checksum) {
      throw new Error('Invalid signature');
    }
    
    event = JSON.parse(payload);
  } catch (err) {
    return res.status(400).send(`Webhook Error: ${err.message}`);
  }
  
  // Handle the event
  console.log('Verified event:', event.type);
  res.status(200).send('Signature verified');
});

With Mockly, you can include proper signatures when simulating events:

# Send a signed webhook event
mockly webhook send stripe-payment-succeeded --sign whsec_1234567890 --to http://localhost:3000/webhook

Testing Error Scenarios

It's important to test how your application handles webhook errors. Mockly allows you to simulate various error scenarios:

# Simulate a malformed JSON payload
mockly webhook send malformed-json --to http://localhost:3000/webhook

# Simulate a webhook with missing required fields
mockly webhook send stripe-payment-succeeded --field-remove data.object.id --to http://localhost:3000/webhook

# Simulate a webhook with incorrect event type
mockly webhook send custom --json '{"type": "unknown.event"}' --to http://localhost:3000/webhook

Integrating Webhook Testing into CI/CD

You can incorporate webhook testing into your CI/CD pipeline using Mockly's API:

# Example GitHub Action workflow
name: Test Webhooks

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test-webhooks:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    - name: Set up Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '16'
    
    - name: Install dependencies
      run: npm ci
    
    - name: Start webhook server
      run: node webhook-server.js &
    
    - name: Install Mockly CLI
      run: npm install -g @mockly/cli
    
    - name: Run webhook tests
      run: |
        mockly auth --token secrets.MOCKLY_API_KEY
        mockly webhook create --name ci-test
        
        # Run test scenarios
        mockly webhook send stripe-payment-succeeded --to http://localhost:3000/webhook
        mockly webhook send stripe-payment-failed --to http://localhost:3000/webhook
        
        # Verify test results
        npx jest tests/webhook.test.js

Best Practices for Webhook Testing

1. Use Idempotency Keys

Always design your webhook handlers to be idempotent, meaning they can safely process the same event multiple times without side effects. This is crucial for production reliability, and Mockly helps you test this by allowing you to replay events:

# Replay a specific webhook event
mockly webhook replay --id webhook_123456 --to http://localhost:3000/webhook

2. Test Concurrency

Webhooks often arrive in rapid succession or out of order. Test how your system handles concurrent webhook processing:

# Send multiple events concurrently
mockly webhook send stripe-payment-succeeded --count 10 --concurrent 5 --to http://localhost:3000/webhook

3. Validate Request Headers

Always verify that your webhook handler checks for required headers, especially those related to security:

// Example of header validation
app.post('/webhook', (req, res) => {
  // Check for required headers
  if (!req.headers['content-type'] || !req.headers['user-agent']) {
    return res.status(400).send('Missing required headers');
  }
  
  // Continue processing
  // ...
});

4. Use Timeouts

Webhooks should be processed quickly to avoid timeouts. Most providers expect a response within 5-10 seconds:

// Use async processing for long-running tasks
app.post('/webhook', (req, res) => {
  // Send immediate response
  res.status(200).send('Webhook received');
  
  // Then process asynchronously
  processWebhookEventAsync(req.body).catch(err => {
    console.error('Async processing error:', err);
  });
});

Pro Tip

For long-running webhook processing, acknowledge receipt immediately and then process the event asynchronously. This prevents timeout errors from the webhook provider.

Conclusion

Webhook testing doesn't have to be complicated. With Mockly's webhook testing tools, you can:

  • Create realistic test environments without deploying code
  • Simulate webhooks from any provider with accurate payloads
  • Test error scenarios and edge cases easily
  • Debug webhook issues with detailed request inspection
  • Integrate webhook testing into your development workflow and CI/CD pipeline

By incorporating these tools and practices into your development workflow, you'll build more reliable webhook integrations and catch issues before they affect your production systems.

Have you struggled with webhook testing? What approaches have worked for you? Share your experiences in the comments below!

Sarah Johnson

About the Author

Sarah Johnson is an Integration Specialist at CloudConnect with 8+ years of experience building API integrations. She specializes in webhook design, event-driven architectures, and developer tooling for third-party integrations.