Keep stripe customer reference in sync using webhook (#1580)

This commit is contained in:
Luke Vella 2025-02-26 12:48:48 +00:00 committed by GitHub
parent a1f50dc792
commit 34f5555791
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 53 additions and 0 deletions

View file

@ -0,0 +1,30 @@
import type { Stripe } from "@rallly/billing";
import { prisma } from "@rallly/database";
import { z } from "zod";
const customerMetadataSchema = z.object({
userId: z.string(),
});
export async function onCustomerCreated(event: Stripe.Event) {
const customer = event.data.object as Stripe.Customer;
const res = customerMetadataSchema.safeParse(customer.metadata);
if (!res.success) {
// If there's no userId in metadata, ignore the event
return;
}
const { userId } = res.data;
// Update the user with the customer id
await prisma.user.update({
where: {
id: userId,
},
data: {
customerId: customer.id,
},
});
}

View file

@ -0,0 +1,16 @@
import type { Stripe } from "@rallly/billing";
import { prisma } from "@rallly/database";
export async function onCustomerDeleted(event: Stripe.Event) {
const customer = event.data.object as Stripe.Customer;
// Find and update the user with this customerId
await prisma.user.updateMany({
where: {
customerId: customer.id,
},
data: {
customerId: null,
},
});
}

View file

@ -0,0 +1,2 @@
export * from "./created";
export * from "./deleted";

View file

@ -2,6 +2,7 @@ import type { Stripe } from "@rallly/billing";
import { onCheckoutSessionCompleted } from "./checkout/completed"; import { onCheckoutSessionCompleted } from "./checkout/completed";
import { onCheckoutSessionExpired } from "./checkout/expired"; import { onCheckoutSessionExpired } from "./checkout/expired";
import { onCustomerCreated, onCustomerDeleted } from "./customer";
import { onCustomerSubscriptionCreated } from "./customer-subscription/created"; import { onCustomerSubscriptionCreated } from "./customer-subscription/created";
import { onCustomerSubscriptionDeleted } from "./customer-subscription/deleted"; import { onCustomerSubscriptionDeleted } from "./customer-subscription/deleted";
import { onCustomerSubscriptionUpdated } from "./customer-subscription/updated"; import { onCustomerSubscriptionUpdated } from "./customer-subscription/updated";
@ -17,6 +18,10 @@ export function getEventHandler(eventType: Stripe.Event["type"]) {
return onCheckoutSessionCompleted; return onCheckoutSessionCompleted;
case "checkout.session.expired": case "checkout.session.expired":
return onCheckoutSessionExpired; return onCheckoutSessionExpired;
case "customer.created":
return onCustomerCreated;
case "customer.deleted":
return onCustomerDeleted;
case "customer.subscription.created": case "customer.subscription.created":
return onCustomerSubscriptionCreated; return onCustomerSubscriptionCreated;
case "customer.subscription.deleted": case "customer.subscription.deleted":