Openstatus
www.openstatus.dev
1import { TRPCError } from "@trpc/server";
2import { getHTTPStatusCodeFromError } from "@trpc/server/http";
3import type { NextRequest } from "next/server";
4
5import { createTRPCContext } from "@openstatus/api";
6import { lambdaRouter, stripe } from "@openstatus/api/src/lambda";
7
8import { env } from "@/env";
9
10export async function POST(req: NextRequest) {
11 const payload = await req.text();
12 const signature = req.headers.get("Stripe-Signature");
13 if (!signature) return new Response("No signature", { status: 400 });
14
15 try {
16 const event = stripe.webhooks.constructEvent(
17 payload,
18 signature,
19 env.STRIPE_WEBHOOK_SECRET_KEY,
20 );
21
22 /**
23 * Forward to tRPC API to handle the webhook event
24 */
25 const ctx = await createTRPCContext({ req });
26 const caller = lambdaRouter.createCaller(ctx);
27
28 switch (event.type) {
29 case "checkout.session.completed":
30 await caller.stripeRouter.webhooks.sessionCompleted({ event });
31 break;
32 case "customer.subscription.updated":
33 console.log(event);
34 await caller.stripeRouter.webhooks.customerSubscriptionUpdated({
35 event,
36 });
37 break;
38 case "customer.subscription.deleted":
39 await caller.stripeRouter.webhooks.customerSubscriptionDeleted({
40 event,
41 });
42 break;
43
44 default:
45 throw new Error(`Unhandled event type ${event.type}`);
46 }
47 } catch (error) {
48 if (error instanceof TRPCError) {
49 const errorCode = getHTTPStatusCodeFromError(error);
50 console.error("Error in tRPC webhook handler", error);
51 return new Response(error.message, { status: errorCode });
52 }
53
54 const message = error instanceof Error ? error.message : "Unknown error";
55 return new Response(`Webhook Error: ${message}`, {
56 status: 400,
57 });
58 }
59
60 return new Response(null, { status: 200 });
61}