Skip to content

Commit bb05eff

Browse files
authored
Adds Next.js App Router example for Webhook signing
Addresses: stripe#2100
1 parent ac941b9 commit bb05eff

File tree

1 file changed

+61
-0
lines changed
  • examples/webhook-signing/nextjs/app/api/webhooks

1 file changed

+61
-0
lines changed
+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { buffer, stripe } from "@/lib/stripe";
2+
import { NextRequest } from "next/server";
3+
4+
export const config = {
5+
api: {
6+
bodyParser: false,
7+
},
8+
};
9+
10+
export async function POST(req : NextRequest){
11+
const sig = req.headers.get("stripe-signature")
12+
const wh_sec = process.env.STRIPE_WEBHOOK_SECRET
13+
let event: Stripe.Event;
14+
if (!sig){
15+
throw new Error("Invalid Signature")
16+
}
17+
try {
18+
const body = Uint8Array.from(await buffer(req)) as Buffer<ArrayBufferLike>
19+
event = stripe.webhooks.constructEvent(body, sig!, wh_sec)
20+
}
21+
catch (err : any){
22+
console.log(`❌ Error message: ${err.message}`);
23+
return new Response(`Webhook Error: ${err.message}`, {status : 400})
24+
}
25+
console.log('✅ Success:', event.id);
26+
27+
// Cast event data to Stripe object
28+
if (event.type === 'payment_intent.succeeded') {
29+
const stripeObject: Stripe.PaymentIntent = event.data
30+
.object as Stripe.PaymentIntent;
31+
console.log(`💰 PaymentIntent status: ${stripeObject.status}`);
32+
} else if (event.type === 'charge.succeeded') {
33+
const charge = event.data.object as Stripe.Charge;
34+
console.log(`💵 Charge id: ${charge.id}`);
35+
} else {
36+
console.warn(`🤷‍♀️ Unhandled event type: ${event.type}`);
37+
}
38+
39+
// Return a response to acknowledge receipt of the event
40+
return Response.json({received: true}, {status : 200});
41+
}
42+
43+
const buffer = async(req: NextRequest) => {
44+
const body = req.body;
45+
if (!body) {
46+
throw new Error('Request body is null');
47+
}
48+
const reader = body.getReader();
49+
const chunks = [];
50+
let done, value;
51+
while ({ done, value } = await reader.read(), !done) {
52+
chunks.push(value);
53+
}
54+
const buf = new Uint8Array(chunks.reduce((acc, chunk) => acc + chunk.length, 0));
55+
let offset = 0;
56+
for (const chunk of chunks) {
57+
buf.set(chunk, offset);
58+
offset += chunk.length;
59+
}
60+
return buf;
61+
};

0 commit comments

Comments
 (0)