When building payment infrastructure with Stripe, understanding the event type system is fundamental to creating robust, reliable integrations. Stripe generates over 200 different webhook event types that notify your application when meaningful actions occur--from successful payments to subscription cancellations. This guide covers the essential event types you need to handle, their payloads, and best practices for implementation.
Why Event Types Matter
Stripe's event types follow a consistent naming convention that makes it intuitive to understand what each event represents. Event types follow the pattern resource.action, where the resource indicates the affected object and the action describes what happened. This structured approach helps developers quickly identify relevant events for their integration needs, as covered in MagicBell's comprehensive webhook guide.
For teams building payment systems as part of a broader web development initiative, mastering webhook event handling ensures your application responds accurately to payment state changes.
Event Naming Convention
The event type naming convention provides immediate context about each event. For example, payment_intent.succeeded clearly indicates a PaymentIntent resource that has succeeded, while customer.subscription.deleted signals a deleted subscription for a customer.
Event Categories
Payment Events cover the complete payment lifecycle:
payment_intent.succeeded- Payment completed successfullypayment_intent.payment_failed- Payment attempt failedcharge.succeeded- Charge created successfullycharge.refunded- Charge has been refunded
Subscription Events manage recurring billing:
customer.subscription.created- New subscription beginscustomer.subscription.updated- Subscription details changedcustomer.subscription.deleted- Subscription has endedcustomer.subscription.trial_will_end- Trial ending in 3 days
Checkout Events relate to Stripe Checkout:
checkout.session.completed- Customer completed checkout payment
For a complete list of all event types, refer to Stripe's official API reference.
Understanding these event types is essential when implementing Stripe Checkout for your e-commerce platform.
The checkout.session.completed Event
The checkout.session.completed event is one of the most important events for e-commerce integrations using Stripe Checkout. This event fires when a customer successfully completes a payment flow through Stripe's hosted checkout page.
Event Payload
The event includes a comprehensive session object with payment details, customer information, and order data:
- Payment intent ID and amount
- Customer email for confirmations
- Line items and product details
- Shipping information if applicable
- Payment method used
Best Practices for Handling
Signature Verification: Always verify the webhook signature using Stripe's constructEvent method with your endpoint secret. This ensures the webhook actually came from Stripe and prevents malicious actors from spoofing events.
Idempotency: Stripe may deliver the same event multiple times due to their retry mechanism. Store processed event IDs in your database and skip duplicate handling to prevent issues like double-charging or duplicate order fulfillment.
Order Fulfillment Workflow: When handling this event, mark orders as paid in your database, update inventory systems, and trigger any necessary fulfillment processes. The session object contains everything you need without additional API calls.
Confirmation Emails: Use the customer email from the session to send order confirmations, shipping notifications, and receipts. This communication builds trust and reduces customer support inquiries.
For secure payment handling, consider implementing 3D Secure for additional fraud protection on high-risk transactions.
1app.post('/webhooks/stripe', express.raw({type: 'application/json'}), (req, res) => {2 const sig = req.headers['stripe-signature'];3 const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;4 5 let event;6 try {7 event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);8 } catch (err) {9 return res.status(400).send(`Webhook Error: ${err.message}`);10 }11 12 if (event.type === 'checkout.session.completed') {13 const session = event.data.object;14 // Handle successful checkout15 fulfillOrder(session);16 }17 18 res.json({received: true});19});Essential Payment Event Types
Successful Payment Events
The payment_intent.succeeded event indicates that a payment has been successfully processed and the funds are secured. This event contains the PaymentIntent object with complete payment details including amount, currency, payment method, and customer information.
For many integrations, this event triggers:
- Order fulfillment
- Access grant to paid features
- Service delivery
- Payment confirmation emails
Failed Payment Events
The payment_intent.payment_failed event alerts you when a payment attempt cannot complete. The event payload includes:
- Failure reason and error code
- Customer-facing message
- Next payment attempt timestamp
Refund Events
The charge.refunded event fires when a refund is processed. The event indicates whether the refund was full or partial through the amount_refunded field. This event is essential for maintaining accurate financial records and updating order status accordingly.
According to MagicBell's webhook implementation guide, failed payment handling requires careful consideration of user experience, including providing clear instructions for updating payment methods and implementing retry logic.
When handling payment events, ensure your authentication flow properly validates user identity through Stripe Authentication for secure transactions.
Subscription Lifecycle Events
Creation and Updates
The customer.subscription.created event marks the beginning of a new subscription relationship. The event payload includes subscription details such as the price ID, current period end, and status.
Subscription updates trigger customer.subscription.updated events when:
- Plan upgrades or downgrades occur
- Payment method changes
- Quantity adjustments
- Trial conversions
Trial Events
The customer.subscription.trial_will_end event provides a critical three-day warning before a trial converts to a paid subscription. This notification window enables proactive customer engagement--send reminders about trial expiration, highlight product value, and offer incentives for conversion.
Cancellation Events
The customer.subscription.deleted event signals the final end of a subscription. Handle this event by:
- Revoking subscription access
- Sending confirmation communications
- Initiating win-back campaigns
The customer.subscription.updated event includes both old and new subscription values, enabling you to calculate proration and adjust customer access accordingly, as documented in MagicBell's webhook guide.
Subscription handling is a core component of backend development for SaaS platforms offering recurring billing.
Security Best Practices
Signature Verification
Always verify webhook signatures using Stripe's constructEvent method before processing any event. This verification ensures the webhook originated from Stripe and hasn't been tampered with. The signature is sent in the stripe-signature header and validated against your webhook endpoint secret, as recommended in Stripe's official webhook documentation.
Idempotency Implementation
Design your webhook handlers to process events idempotently. Stripe may deliver the same event multiple times due to their retry mechanism. Track processed event IDs in your database and skip duplicate processing. This prevents duplicate orders, access grants, or other unintended actions.
HTTPS Requirements
Production webhook endpoints must use HTTPS to encrypt webhook data in transit. This requirement protects sensitive payment information and prevents eavesdropping or tampering. For local development, use the Stripe CLI to forward webhooks securely to your local environment, as covered in Stripe's webhook setup guide.
Implementing secure webhooks is a critical part of building secure payment infrastructure that protects both your business and your customers.
1// Verify webhook signature2try {3 event = stripe.webhooks.constructEvent(4 req.body,5 req.headers['stripe-signature'],6 endpointSecret7 );8} catch (err) {9 console.log(`Signature verification failed: ${err.message}`);10 return res.status(400).send(`Webhook Error: ${err.message}`);11}12 13// Implement idempotency14async function handlePaymentSucceeded(paymentIntent) {15 const existing = await db.payments.findOne({16 stripe_payment_intent_id: paymentIntent.id17 });18 19 if (existing) {20 console.log(`Payment ${paymentIntent.id} already processed`);21 return;22 }23 24 await db.payments.create({25 stripe_payment_intent_id: paymentIntent.id,26 amount: paymentIntent.amount,27 status: 'completed'28 });29}Event Object Structure
Every Stripe webhook event follows a consistent structure:
{
"id": "evt_1234567890",
"object": "event",
"api_version": "2024-11-20.acacia",
"created": 1732800000,
"type": "payment_intent.succeeded",
"data": {
"object": {
"id": "pi_1234567890",
"amount": 2000,
"currency": "usd",
"status": "succeeded",
"customer": "cus_1234567890"
}
}
}
Key Fields:
id- Unique event identifier for idempotency trackingtype- The event type string (e.g.,payment_intent.succeeded)api_version- Stripe API version for consistent interpretationdata.object- The full resource that triggered the event
The api_version field indicates which Stripe API version was used, ensuring consistent event structure interpretation. According to MagicBell's implementation guide, understanding this structure is essential for building reliable webhook handlers.
This consistent structure makes it easier to build robust payment integrations that can handle various event types reliably.
Best Practices Summary
When implementing Stripe event type handling, prioritize the events most critical to your business logic:
-
Start with essential events:
checkout.session.completed,customer.subscription.created,payment_intent.payment_failed -
Implement security first: Signature verification and HTTPS are non-negotiable for production
-
Design for idempotency: Handle Stripe's retry mechanism gracefully
-
Respond quickly: Return 2xx status codes within 5 seconds, process asynchronously
-
Test thoroughly: Use Stripe CLI for local testing before deployment
-
Monitor deliveries: Use the Stripe Dashboard to track webhook success rates
Additional Resources
Explore our other Stripe integration guides: