fix: improve stripe webhook endpoint

Improve the stripe webhook endpoint by checking for
subscriptions prior to performing an update to handle
cases where accounts have no created subscription.

This can happen in sitations such as when a checkout_session has been created but the payment fails.
This commit is contained in:
Mythie
2023-05-31 21:11:54 +10:00
parent 893ab9bea5
commit 19e960f593

View File

@@ -25,9 +25,7 @@ export const webhookHandler = async (req: NextApiRequest, res: NextApiResponse)
}); });
} }
log("constructing body...")
const body = await buffer(req); const body = await buffer(req);
log("constructed body")
const event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!); const event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!);
log("event-type:", event.type); log("event-type:", event.type);
@@ -70,23 +68,38 @@ export const webhookHandler = async (req: NextApiRequest, res: NextApiResponse)
if (event.type === "invoice.payment_succeeded") { if (event.type === "invoice.payment_succeeded") {
const invoice = event.data.object as Stripe.Invoice; const invoice = event.data.object as Stripe.Invoice;
if (invoice.billing_reason !== "subscription_cycle") {
return res.status(200).json({
success: true,
message: "Webhook received",
});
}
const customerId = const customerId =
typeof invoice.customer === "string" ? invoice.customer : invoice.customer?.id; typeof invoice.customer === "string" ? invoice.customer : invoice.customer?.id;
const subscription = await stripe.subscriptions.retrieve(invoice.subscription as string); const subscription = await stripe.subscriptions.retrieve(invoice.subscription as string);
await prisma.subscription.update({ const hasSubscription = await prisma.subscription.findFirst({
where: { where: {
customerId, customerId,
}, },
data: {
status: SubscriptionStatus.ACTIVE,
planId: subscription.id,
priceId: subscription.items.data[0].price.id,
periodEnd: new Date(subscription.current_period_end * 1000),
},
}); });
if (hasSubscription) {
await prisma.subscription.update({
where: {
customerId,
},
data: {
status: SubscriptionStatus.ACTIVE,
planId: subscription.id,
priceId: subscription.items.data[0].price.id,
periodEnd: new Date(subscription.current_period_end * 1000),
},
});
}
return res.status(200).json({ return res.status(200).json({
success: true, success: true,
message: "Webhook received", message: "Webhook received",
@@ -98,15 +111,23 @@ export const webhookHandler = async (req: NextApiRequest, res: NextApiResponse)
const customerId = failedInvoice.customer as string; const customerId = failedInvoice.customer as string;
await prisma.subscription.update({ const hasSubscription = await prisma.subscription.findFirst({
where: { where: {
customerId, customerId,
}, },
data: {
status: SubscriptionStatus.PAST_DUE,
},
}); });
if (hasSubscription) {
await prisma.subscription.update({
where: {
customerId,
},
data: {
status: SubscriptionStatus.PAST_DUE,
},
});
}
return res.status(200).json({ return res.status(200).json({
success: true, success: true,
message: "Webhook received", message: "Webhook received",
@@ -118,18 +139,26 @@ export const webhookHandler = async (req: NextApiRequest, res: NextApiResponse)
const customerId = updatedSubscription.customer as string; const customerId = updatedSubscription.customer as string;
await prisma.subscription.update({ const hasSubscription = await prisma.subscription.findFirst({
where: { where: {
customerId, customerId,
}, },
data: {
status: SubscriptionStatus.ACTIVE,
planId: updatedSubscription.id,
priceId: updatedSubscription.items.data[0].price.id,
periodEnd: new Date(updatedSubscription.current_period_end * 1000),
},
}); });
if (hasSubscription) {
await prisma.subscription.update({
where: {
customerId,
},
data: {
status: SubscriptionStatus.ACTIVE,
planId: updatedSubscription.id,
priceId: updatedSubscription.items.data[0].price.id,
periodEnd: new Date(updatedSubscription.current_period_end * 1000),
},
});
}
return res.status(200).json({ return res.status(200).json({
success: true, success: true,
message: "Webhook received", message: "Webhook received",
@@ -141,15 +170,23 @@ export const webhookHandler = async (req: NextApiRequest, res: NextApiResponse)
const customerId = deletedSubscription.customer as string; const customerId = deletedSubscription.customer as string;
await prisma.subscription.update({ const hasSubscription = await prisma.subscription.findFirst({
where: { where: {
customerId, customerId,
}, },
data: {
status: SubscriptionStatus.INACTIVE,
},
}); });
if (hasSubscription) {
await prisma.subscription.update({
where: {
customerId,
},
data: {
status: SubscriptionStatus.INACTIVE,
},
});
}
return res.status(200).json({ return res.status(200).json({
success: true, success: true,
message: "Webhook received", message: "Webhook received",