Webhooks

Real-time event notifications from Stripe to your application. Learn how to configure webhook endpoints, verify signatures with stripe.webhooks.constructEvent, and handle payment, subscription, and Connect events securely.

What Are Webhooks

Webhooks are HTTP callbacks that deliver real-time event notifications from Stripe to your application. When something happens in your Stripe account--whether a payment is processed, a subscription status changes, or a customer updates their payment method--Stripe creates an event object and sends it to your webhook endpoint via HTTP POST. This enables your application to respond immediately to changes without continuously polling Stripe's API for updates. For businesses processing high transaction volumes, integrating AI automation services can help intelligently route and process these events at scale.

The webhook pattern inverts the traditional request-response model. Instead of your application asking Stripe "did anything happen?" every few seconds, Stripe tells your application "something happened" the moment it occurs. This approach offers significant advantages in terms of efficiency, latency, and system design. Your application consumes fewer API resources, receives information more quickly, and can react to events in real-time rather than on a polling interval.

The technical flow of a Stripe webhook follows a clear sequence. First, an event occurs in Stripe's systems--perhaps a successful charge, a failed payment, or a subscription cancellation. Stripe then creates an Event object capturing all relevant details about what happened. Next, Stripe sends an HTTPS POST request to your registered webhook URL, including the event data in JSON format and a cryptographic signature in the headers. Your endpoint receives this request, verifies the signature to confirm authenticity, processes the event according to your business logic, and returns a 2xx status code to acknowledge receipt. If your endpoint fails to respond with a 2xx code, Stripe will retry the delivery according to its retry schedule.

Event Object Structure

Stripe webhook events follow a consistent JSON structure that makes them easy to parse and process. The event object contains several top-level fields that provide metadata about the event, along with a nested data object containing the actual resource that triggered the event.

The id field provides a unique identifier for the event itself, which you can use for idempotency tracking and logging. This identifier remains constant across retry deliveries, so you can detect duplicate events by checking whether you've already processed a specific event ID. The object field always contains the value "event", indicating this is an event object rather than one of Stripe's other resource types.

The type field uses a dot-separated naming convention that identifies what kind of event was triggered--for example, payment_intent.succeeded indicates a successful payment, while charge.refunded indicates a refund was processed. The data object contains two fields: object and previous_attributes. The object field holds the full resource that was created, updated, or deleted to trigger the event. For a payment_intent.succeeded event, this would contain the complete PaymentIntent object with all its properties. The previous_attributes field, which appears only on update events, shows the values of fields that changed during the update.

{
 "id": "evt_1Mxx"",
 "object": "event",
 "api_version": "2023-10-16",
 "created": 1704067200,
 "type": "payment_intent.succeeded",
 "data": {
 "object": {
 "id": "pi_123",
 "object": "payment_intent",
 "amount": 5000,
 "currency": "usd",
 "status": "succeeded"
 },
 "previous_attributes": {
 "status": "processing"
 }
 }
}

Setting Up Webhook Endpoints

Configuring a webhook endpoint requires attention to both functional and security requirements. Your endpoint must be publicly accessible via HTTPS, capable of receiving and processing POST requests, and designed to respond quickly to avoid timeout-related retries. Partnering with professional web development services ensures your webhook infrastructure is built to production standards with proper security, logging, and error handling from day one.

In production, Stripe requires all webhook endpoints to use HTTPS. This ensures that webhook payloads are encrypted in transit, preventing eavesdropping or tampering during delivery. Your SSL certificate must be valid and properly configured--Stripe will reject connections to endpoints with expired or misconfigured certificates. For development and testing, you can use HTTP endpoints or leverage tools like the Stripe CLI to forward webhooks to local development servers.

The endpoint URL should be specific enough to isolate webhook handling from other routes in your application. Many developers use a dedicated path like /webhooks/stripe or /api/stripe/events to make routing clear and simplify middleware configuration. This dedicated path also makes it easier to apply specific security measures, logging, and rate limiting to webhook requests.

Dashboard Configuration

Navigate to Developers > Webhooks in your Stripe Dashboard to configure endpoints. Each endpoint requires a publicly accessible HTTPS URL, selection of events to receive, and a signing secret for verification. During development, selecting "Select all events" provides comprehensive visibility into Stripe's event stream. In production, it's best practice to select only the events your application actually handles.

Endpoint Requirements

Your webhook endpoint must accept POST requests with a JSON body, parse the incoming payload, verify the Stripe-Signature header, process the event, and return an appropriate response within 5 seconds. Stripe expects your endpoint to respond quickly--if your processing logic requires longer operations, acknowledge receipt immediately and process events asynchronously. The endpoint must also handle duplicate deliveries gracefully since Stripe implements an automatic retry mechanism for failed requests.

stripe.webhooks.constructEvent

The stripe.webhooks.constructEvent method serves as the cornerstone of secure webhook processing. This method performs two critical functions: it verifies that the webhook payload originated from Stripe, and it parses the raw JSON body into a structured event object you can work with programmatically.

Signature verification ensures webhook payloads actually came from Stripe and haven't been tampered with during transit. Every webhook request includes a Stripe-Signature header containing a cryptographic signature calculated using your endpoint's signing secret and the raw request body. The method uses HMAC with SHA-256 to create and validate this signature.

Using the raw request body is essential for correct signature verification. Many web frameworks automatically parse JSON bodies into objects, which changes the content and breaks signature verification. You must capture the raw body before any parsing occurs. In Express.js, this typically means using express.raw({ type: 'application/json' }) as middleware rather than express.json(). Always wrap the call in a try-catch block to handle verification failures gracefully.

Webhook signature verification with constructEvent
1const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);2const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;3 4app.post('/webhooks/stripe', express.raw({type: 'application/json'}), (req, res) => {5 const sig = req.headers['stripe-signature'];6 7 let event;8 9 try {10 // Verify signature and parse event11 event = stripe.webhooks.constructEvent(12 req.body,13 sig,14 endpointSecret15 );16 } catch (err) {17 console.log(`Webhook signature verification failed: ${err.message}`);18 return res.status(400).send(`Webhook Error: ${err.message}`);19 }20 21 // Handle the event22 switch (event.type) {23 case 'payment_intent.succeeded':24 const paymentIntent = event.data.object;25 handlePaymentSucceeded(paymentIntent);26 break;27 case 'customer.subscription.created':28 const subscription = event.data.object;29 handleSubscriptionCreated(subscription);30 break;31 default:32 console.log(`Unhandled event type: ${event.type}`);33 }34 35 // Return success response36 res.json({received: true});37});

Stripe Connect Webhooks

For platforms and marketplaces using Stripe Connect, webhooks provide visibility into activity across your connected accounts. Stripe Connect enables you to facilitate payments on behalf of users--marketplaces, SaaS platforms, and any business model where you need to split payments between parties or manage funds for others.

Connect webhooks follow the same fundamental pattern as standard webhooks but include additional context about connected accounts. When an event occurs on a connected account, you receive webhook notifications that identify which account was affected through the account property. This enables you to track activity across your entire platform, monitor payout schedules, and respond to account-level events.

Platform vs Account Events

Key events for Connect implementations include account.created and account.updated for connected account lifecycle, payout.created, payout.paid, and payout.failed for tracking fund transfers, and transfer.created events for monitoring fund movement. Compliance events like capability changes require particular attention--a connected account might lose the ability to accept payments if verification isn't completed.

You can configure separate webhook endpoints for platform events versus account events, or route all events through a single endpoint and use the event's account property to determine which connected account was affected. Understanding whether you're using direct charges or destination charges helps you interpret events correctly since each pattern generates different webhook events.

Event Types and Categories

Stripe generates over 200 different webhook event types, organized around resources and actions following the resource.action pattern. Understanding the naming convention and common categories helps you identify which events are relevant to your integration and plan your handling logic accordingly.

Payment Events

Event TypeDescription
payment_intent.succeededPayment successfully processed
payment_intent.payment_failedPayment attempt failed
charge.refundedRefund processed (full or partial)
charge.dispute.createdCustomer dispute filed

Subscription Events

Event TypeDescription
customer.subscription.createdNew subscription started
customer.subscription.updatedSubscription details changed
customer.subscription.deletedSubscription ended
customer.subscription.trial_will_endTrial ending in 3 days

Invoice Events

Event TypeDescription
invoice.payment_succeededInvoice payment collected
invoice.payment_failedInvoice payment collection failed
invoice.upcomingInvoice being created in 1 day

Each event category fires at specific points in the payment lifecycle. Payment events handle one-time charges, subscription events manage recurring billing, and invoice events track the billing cycle including dunning management. A well-designed payment system routes events to appropriate handlers based on their type.

Security Best Practices

Securing webhook endpoints is non-negotiable when handling payment-related events. Webhooks contain sensitive customer and transaction data, and a compromised endpoint could enable fraud or unauthorized actions. Implementing comprehensive security measures protects your business and your customers. For enterprise-grade security, consider leveraging AI automation services to detect anomalies and automate threat response alongside manual verification.

Core Security Measures

Always verify webhook signatures using constructEvent--never skip this step in production. Use HTTPS endpoints (required in production) to encrypt data in transit. Store secrets securely using environment variables, never commit to version control. Implement idempotency to handle Stripe's retry mechanism safely, and return 2xx responses within 5 seconds, processing complex logic asynchronously.

Idempotent Processing

Design handlers to process events idempotently. Track processed event IDs using their unique identifiers and skip duplicates. Before taking action, check whether you've already processed that specific event ID and store processed event IDs in a database with timestamps. For resource-level operations, use database constraints or upsert patterns to prevent duplicate records.

Idempotent webhook processing
1async function handlePaymentSucceeded(paymentIntent) {2 // Check if already processed using event ID3 const existing = await db.webhook_events.findOne({4 stripe_event_id: event.id5 });6 7 if (existing) {8 console.log(`Event ${event.id} already processed, skipping`);9 return;10 }11 12 // Process the payment event13 await db.payments.create({14 stripe_payment_intent_id: paymentIntent.id,15 amount: paymentIntent.amount,16 status: 'completed',17 customer_id: paymentIntent.customer18 });19 20 // Record processed event21 await db.webhook_events.create({22 stripe_event_id: event.id,23 event_type: event.type,24 processed_at: new Date()25 });26}

Testing Webhooks

Comprehensive testing is essential before deploying webhook handlers to production. Stripe provides multiple tools for testing, from local development with the Stripe CLI to test mode events that simulate real-world scenarios.

Stripe CLI for Local Development

The Stripe CLI provides a powerful workflow for local webhook development. After installing and authenticating with stripe login, use stripe listen to forward webhooks to your local development server. The CLI outputs a webhook signing secret that you use in your local environment, ensuring your verification code is exercised as it will be in production.

# Install and authenticate
brew install stripe/stripe-cli/stripe
stripe login

# Forward webhooks to local endpoint
stripe listen --forward-to localhost:3000/webhooks/stripe

Triggering Test Events

The Stripe CLI's stripe trigger command sends specific webhook events to your local endpoint. This is invaluable for testing edge cases and error handling--trigger success events, failure events, and various edge conditions without manually walking through actual user flows.

# Trigger specific events
stripe trigger payment_intent.succeeded
stripe trigger invoice.payment_failed
stripe trigger customer.subscription.created

Dashboard Webhook Logs

The Stripe Dashboard provides webhook delivery logs showing recent deliveries, response codes, and response times. Review these logs during testing to verify that your endpoint is receiving events correctly and responding appropriately. Failed deliveries show error details that help diagnose issues.

Troubleshooting Common Issues

Endpoint Not Receiving Events

If your endpoint isn't receiving events, verify the URL configuration in the Stripe Dashboard matches your actual endpoint exactly--typos, trailing slashes, or case sensitivity can cause mismatches. Check that your server is publicly accessible and not blocked by firewall rules or IP restrictions. Confirm HTTPS is properly configured with a valid certificate, and review event selection to ensure you're subscribed to the events you're expecting.

Signature Verification Failing

Signature verification failures typically result from passing parsed JSON instead of raw body content to constructEvent. Many web frameworks automatically parse request bodies, which changes the content and breaks verification. Ensure you're capturing the raw body before any parsing occurs and verify you're using the correct signing secret for the endpoint from the Dashboard.

Timeout Issues

Timeouts occur when your endpoint takes longer than 5 seconds to respond. Review your processing logic for operations that could cause delays--database queries, external API calls, and complex computations should happen asynchronously. Implement background job processing for operations that exceed the 5-second window.

Duplicate Events

Duplicate events result from Stripe's retry mechanism. If your endpoint fails to respond with 2xx, Stripe will retry delivery. Implement idempotent processing using event IDs to detect and skip duplicates. For extreme scenarios, implement a deduplication window where events received after a certain time are automatically discarded.

Webhook Implementation Essentials

Real-Time Notifications

Receive instant alerts when payments succeed, subscriptions renew, or disputes arise--eliminating the need for polling.

Signature Verification

Use stripe.webhooks.constructEvent to verify every webhook payload originated from Stripe and hasn't been tampered with.

Idempotent Processing

Handle Stripe's retry mechanism safely by tracking event IDs and ensuring duplicate events don't cause duplicate actions.

Multi-Account Visibility

Track activity across all connected accounts with Stripe Connect webhooks for marketplaces and platforms.

Common Questions

Build Secure Payment Infrastructure

Implement webhooks correctly to receive real-time payment notifications. Our team can help you design and deploy robust webhook handling for your payment system.

Sources

  1. Stripe Webhooks Documentation - Official documentation covering endpoint setup, event receiving, and signature verification
  2. MagicBell - Stripe Webhooks Complete Guide - Comprehensive tutorial covering payment events, subscription events, security practices, and testing strategies