WebhookWatch · Integration Guides
Stripe Webhook Testen
Real-time webhook debugging for Dutch developers — capture, inspect, and replay every Stripe event with zero latency.
Step-by-Step
Setup Guide: Connect Stripe to WebhookWatch
Get your Stripe dashboard sending events to WebhookWatch in under three minutes. Every endpoint comes with a unique URL, automatic retry handling, and signature verification out of the box.
1. Generate Your Endpoint URL
Log in to WebhookWatch, click New Endpoint, and copy the generated URL — for example https://w.webhookwatch.nl/ep/7f3a9c2d. This URL forwards all incoming payloads to your dashboard in real time.
2. Add the Endpoint in Stripe
Open your Stripe Dashboard, navigate to Developers → Webhooks, click Add Endpoint, and paste the WebhookWatch URL. Select the events you want to listen for — we recommend starting with payment_intent.succeeded, charge.failed, and invoice.payment_failed.
3. Verify & Start Capturing
Stripe sends a ping event to confirm the endpoint. Once WebhookWatch receives it, your endpoint status turns green. Trigger a test charge in your Stripe sandbox and watch the full payload appear in your WebhookWatch timeline within milliseconds.
Reference
Stripe Event Examples
Below are the most common Stripe events you'll encounter during development. WebhookWatch captures the full JSON payload, headers, and timing metadata for every single one.
payment_intent.succeeded
Fired when a PaymentIntent transitions to succeeded. Contains the amount captured, currency, payment method details, and the connected account ID.
{
"id": "evt_1N2qR4Lp8kYz3mXv",
"type": "payment_intent.succeeded",
"data": {
"object": {
"id": "pi_3N2qR4Lp8kYz3mXv0b1c",
"amount": 4995,
"currency": "eur",
"status": "succeeded",
"payment_method": "pm_card_visa",
"customer": "cus_PqR7sT8uVwXy"
}
},
"created": 1718345622,
"livemode": false
}
charge.failed
Triggered when a charge attempt declines. The payload includes the decline code (e.g., insufficient_funds, card_not_verified) and the raw Stripe error message.
{
"id": "evt_1N2qR5Lp8kYz3mYw",
"type": "charge.failed",
"data": {
"object": {
"id": "ch_3N2qR5Lp8kYz3mYw1d2e",
"amount": 12500,
"currency": "eur",
"status": "failed",
"failure_code": "insufficient_funds",
"failure_message": "Your card has insufficient funds.",
"customer": "cus_PqR7sT8uVwXy"
}
},
"created": 1718345701,
"livemode": false
}
invoice.payment_failed
Sent when a subscription invoice fails to collect payment. Useful for triggering dunning workflows or notifying the customer to update payment details.
{
"id": "evt_1N2qR6Lp8kYz3mZx",
"type": "invoice.payment_failed",
"data": {
"object": {
"id": "in_1N2qR6Lp8kYz3mZx2f3g",
"subscription": "sub_1N2qR6Lp8kYz3mZx",
"customer": "cus_PqR7sT8uVwXy",
"amount_due": 2990,
"currency": "eur",
"status": "open",
"attempt_count": 2,
"next_payment_attempt": 1718432022
}
},
"created": 1718345890,
"livemode": false
}
customer.subscription.updated
Fired when a subscription changes — plan upgrades, downgrades, trial end dates, or proration adjustments. Always check data.previous_attributes to detect what changed.
{
"id": "evt_1N2qR7Lp8kYz3m0y",
"type": "customer.subscription.updated",
"data": {
"object": {
"id": "sub_1N2qR7Lp8kYz3m0y",
"customer": "cus_PqR7sT8uVwXy",
"status": "active",
"items": {
"data": [
{
"plan": {
"id": "price_1N2qR7Lp8kYz3m0y",
"nickname": "Pro Plan",
"amount": 4900,
"currency": "eur"
}
}
]
},
"current_period_end": 1720937622
},
"previous_attributes": {
"status": "trialing"
}
},
"created": 1718346012,
"livemode": false
}
Security
Signature Verification
Stripe signs every webhook payload with your endpoint secret. WebhookWatch validates the Stripe-Signature header automatically and displays the verification result alongside each captured event. Here's how to verify signatures in your own code when you move from testing to production.
Node.js / Express
const express = require('express');
const stripe = require('stripe')('sk_test_...');
const app = express();
const endpointSecret = 'whsec_a1b2c3d4e5f6...';
app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => {
const sig = req.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(
req.body, sig, endpointSecret
);
} catch (err) {
return res.status(400).send(`Webhook Error: ${err.message}`);
}
// Handle the event
switch (event.type) {
case 'payment_intent.succeeded':
console.log('Payment succeeded:', event.data.object.id);
break;
default:
console.log(`Unhandled event type: ${event.type}`);
}
res.json({received: true});
});
PHP
<?php
require 'vendor/autoload.php';
\Stripe\Stripe::setApiKey('sk_test_...');
$payload = @file_get_contents('php://input');
$sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE'];
$endpoint_secret = 'whsec_a1b2c3d4e5f6...';
try {
$event = \Stripe\Webhook::constructEvent(
$payload, $sig_header, $endpoint_secret
);
} catch (\Exception $e) {
http_response_code(400);
exit("Webhook Error: " . $e->getMessage());
}
if ($event->type === 'payment_intent.succeeded') {
$intent = $event->data->object;
echo "Payment received: €" . ($intent->amount / 100);
}
Your endpoint secret is visible in the Stripe Dashboard under Developers → Webhooks → [your endpoint] → Reveal signing secret. Never commit this value to public repositories. WebhookWatch stores your secrets encrypted at rest using AES-256-GCM.