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 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!