From 2ab4e8b40a96f4cf1f07c5a27e7ae31ce887765f Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Wed, 26 Mar 2025 23:24:38 +0000 Subject: [PATCH] fix: support Stripe subscription items (#20389) * fix: Implement backwards compatible stripe change to customer.subscription.deleted * Further handling, including price -> plan change --- .../webhook/_customer.subscription.deleted.ts | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/features/ee/billing/api/webhook/_customer.subscription.deleted.ts b/packages/features/ee/billing/api/webhook/_customer.subscription.deleted.ts index 383c3a144f..0e3c5bdd2b 100644 --- a/packages/features/ee/billing/api/webhook/_customer.subscription.deleted.ts +++ b/packages/features/ee/billing/api/webhook/_customer.subscription.deleted.ts @@ -9,10 +9,25 @@ const STRIPE_TEAM_PRODUCT_ID = process.env.STRIPE_TEAM_PRODUCT_ID || ""; const stripeWebhookProductHandler = (handlers: Handlers) => async (data: Data) => { const subscription = data.object; - // @ts-expect-error - we know subscription.plan.product is defined when unsubscribing - const productId = subscription.plan.product; // prod_xxxxx - - const handlerGetter = handlers[productId]; + let productId: string | null = null; + // @ts-expect-error - support legacy just in case. + if (subscription.plan) { + // @ts-expect-error - we know subscription.plan.product is defined when unsubscribing + productId = subscription.plan.product; // prod_xxxxx + } else { + const subscriptionItem = subscription.items?.data?.[0]; + if (!subscriptionItem) { + throw new Error("Subscription item and plan missing"); + } + const product = subscription.items.data[0]?.plan.product; + if (product) { + productId = typeof product === "string" ? product : product.id; + } + } + if (typeof productId !== "string") { + throw new Error(`Unable to determine Product ID from subscription: ${subscription.id}`); + } + const handlerGetter = handlers[productId as any]; if (!handlerGetter) throw new HttpCode(202, `No product handler found for product: ${productId}`); const handler = (await handlerGetter())?.default; // auto catch unsupported Stripe products.