How to Test Stripe Webhooks: Complete Guide
Master Stripe webhook testing. Learn to capture payment events, verify signatures, test with Stripe CLI, and debug checkout flows. From sandbox to production.
Why Stripe Webhook Testing is Critical
Stripe webhooks are the backbone of payment processing. Every time a payment succeeds, a subscription renews, a dispute is opened, or a payout is sent, Stripe fires a webhook event. If your application doesn't correctly handle these events, you risk missing payments, granting unauthorized access, or failing to fulfill orders.
Unlike API calls where you get an immediate response, Stripe webhooks are asynchronous. A customer may complete a checkout session, but your server might not process the checkout.session.completed event for several seconds. If that webhook fails silently, the customer's order may never be fulfilled — even though they were charged.
This guide walks you through testing every critical Stripe webhook event, from basic payment intents to complex subscription lifecycle management.
Key Stripe Webhook Events You Must Handle
| Event | When It Fires | Priority |
|---|---|---|
payment_intent.succeeded | Payment completed | Critical |
payment_intent.payment_failed | Payment declined | Critical |
checkout.session.completed | Checkout flow finished | Critical |
invoice.paid | Subscription invoice paid | High |
customer.subscription.deleted | Subscription cancelled | High |
charge.dispute.created | Customer filed a dispute | High |
Method 1: Test with Requex.me (Fastest)
The quickest way to understand Stripe webhook payloads is to capture them with Requex.me:
- Visit requex.me and copy your unique webhook URL.
- Go to Stripe Dashboard → Developers → Webhooks → Add Endpoint.
- Paste your Requex URL, select the events you want to test, and click "Add endpoint".
- Click "Send test webhook" in Stripe's dashboard for any event type.
- Watch the payload appear instantly in your Requex dashboard.
This lets you inspect the exact JSON structure Stripe sends, including nested objects, metadata, and edge-case fields that documentation often misses.
Method 2: Stripe CLI for Local Testing
The Stripe CLI provides direct forwarding to your local server:
# Install Stripe CLI brew install stripe/stripe-cli/stripe # Login to your Stripe account stripe login # Forward events to your local server stripe listen --forward-to localhost:3000/api/webhooks/stripe # In another terminal, trigger test events: stripe trigger payment_intent.succeeded stripe trigger customer.subscription.created stripe trigger invoice.payment_failed
The CLI provides a temporary webhook signing secret (displayed when you run stripe listen). Use this secret in your local environment for signature verification.
Stripe Webhook Signature Verification
Stripe signs every webhook with your endpoint's signing secret. Always verify this signature in production:
// Node.js / Express example
const stripe = require('stripe')('sk_test_...');
app.post('/api/webhooks/stripe', express.raw({type: 'application/json'}), (req, res) => {
const sig = req.headers['stripe-signature'];
const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;
let event;
try {
event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
} catch (err) {
console.log('Webhook signature verification failed:', err.message);
return res.status(400).send('Webhook Error');
}
// Handle the event
switch (event.type) {
case 'payment_intent.succeeded':
const paymentIntent = event.data.object;
// Fulfill the order...
break;
case 'payment_intent.payment_failed':
// Notify the customer...
break;
default:
console.log('Unhandled event type:', event.type);
}
res.status(200).json({received: true});
});⚠️ Critical: You must use express.raw() instead of express.json() for the webhook route. Stripe's signature verification requires the raw request body.
Common Stripe Webhook Issues
Signature verification fails every time
Make sure you're using the webhook endpoint secret (starts with whsec_), not your API secret key (starts with sk_). Also ensure the body hasn't been parsed by middleware before verification.
Events received out of order
Stripe doesn't guarantee event order. A invoice.paid might arrive before invoice.created. Always fetch the latest state from the API if order matters.
Duplicate events
Stripe retries failed deliveries. Store processed event IDs in your database and skip duplicates. Use the event.id field as your idempotency key.
Testing Checklist for Stripe Webhooks
- ✓Test
payment_intent.succeeded— Verify order fulfillment - ✓Test
payment_intent.payment_failed— Verify customer notification - ✓Test signature verification with valid and invalid signatures
- ✓Test idempotency by sending the same event twice
- ✓Test timeout handling (use Requex.me delay simulation)
- ✓Test in both Stripe test mode and live mode
Start Testing Webhooks Now
Generate your unique URL and test webhooks instantly. Free, no signup.
Open Webhook Tester →