javascript
42 lines · 7 steps
Verifying Stripe webhooks in Express
An Express route that authenticates incoming Stripe events with a signature check before acting on them.
Explained by
highlit
1const express = require('express');
2const Stripe = require('stripe');
3
4const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
5const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;
6
7const router = express.Router();
8
9router.post(
10 '/webhooks/stripe',
11 express.raw({ type: 'application/json' }),
12 async (req, res) => {
13 const signature = req.headers['stripe-signature'];
14
15 let event;
16 try {
17 event = stripe.webhooks.constructEvent(req.body, signature, endpointSecret);
18 } catch (err) {
19 console.error(`Webhook signature verification failed: ${err.message}`);
20 return res.status(400).send(`Webhook Error: ${err.message}`);
21 }
22
23 switch (event.type) {
24 case 'checkout.session.completed': {
25 const session = event.data.object;
26 await fulfillOrder(session);
27 break;
28 }
29 case 'invoice.payment_failed': {
30 const invoice = event.data.object;
31 await notifyPaymentFailure(invoice.customer);
32 break;
33 }
34 default:
35 console.log(`Unhandled event type: ${event.type}`);
36 }
37
38 res.json({ received: true });
39 }
40);
41
42module.exports = router;
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Webhook endpoints must verify a cryptographic signature so attackers can't forge events.
- 2Signature verification needs the unparsed raw body, so the usual JSON parser must be bypassed for this route.
- 3Acknowledge the webhook with a 2xx quickly and branch on event type to run the right side effect.
Related explainers
python
import stripe from fastapi import APIRouter, Request, Header, HTTPException from app.config import settings
Handling Stripe webhooks in FastAPI
webhooks
signature-verification
event-routing
Intermediate
7 steps
javascript
async function mapWithConcurrency(items, limit, worker) { const results = new Array(items.length); let nextIndex = 0;
Bounded-concurrency async map in JavaScript
concurrency
async-await
promises
Intermediate
7 steps
javascript
const RETRIABLE_STATUS = new Set([408, 429, 500, 502, 503, 504]); function sleep(ms, signal) { return new Promise((resolve, reject) => {
Retrying fetch with exponential backoff
retry
exponential-backoff
abort-signal
Advanced
8 steps
javascript
import { cookies } from 'next/headers'; import { NextResponse } from 'next/server'; import { SignJWT, jwtVerify } from 'jose';
JWT session cookies in a Next.js Route Handler
authentication
jwt
cookies
Intermediate
8 steps
javascript
'use server' import { revalidatePath } from 'next/cache' import { redirect } from 'next/navigation'
How a Next.js Server Action updates a post
server-actions
authorization
validation
Intermediate
7 steps
javascript
const express = require('express'); const v1 = express.Router();
Versioning an API with Express Routers
api versioning
routing
modularity
Intermediate
10 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/verifying-stripe-webhooks-in-express-explained-javascript-bf2b/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.