diff --git a/packages/console/app/src/routes/stripe/webhook.ts b/packages/console/app/src/routes/stripe/webhook.ts index dfff3bd809b4..ecc1ca37cbb3 100644 --- a/packages/console/app/src/routes/stripe/webhook.ts +++ b/packages/console/app/src/routes/stripe/webhook.ts @@ -60,6 +60,15 @@ export async function POST(input: APIEvent) { const customer = await Billing.get() if (customer?.customerID && customer.customerID !== customerID) throw new Error("Customer ID mismatch") + const existingPayment = await Database.use((tx) => + tx + .select({ id: PaymentTable.id }) + .from(PaymentTable) + .where(eq(PaymentTable.invoiceID, invoiceID)) + .then((rows) => rows[0]), + ) + if (existingPayment) return + // set customer metadata if (!customer?.customerID) { await Billing.stripe().customers.update(customerID, { @@ -272,6 +281,17 @@ export async function POST(input: APIEvent) { const invoice = await Billing.stripe().invoices.retrieve(invoiceID, { expand: ["payments"], }) + const paymentID = invoice.payments?.data[0]?.payment.payment_intent as string | undefined + + const existingPayment = await Database.use((tx) => + tx + .select({ id: PaymentTable.id }) + .from(PaymentTable) + .where(eq(PaymentTable.invoiceID, invoiceID)) + .then((rows) => rows[0]), + ) + if (existingPayment) return + await Database.transaction(async (tx) => { await tx .update(BillingTable) @@ -286,7 +306,7 @@ export async function POST(input: APIEvent) { id: Identifier.create("payment"), amount: centsToMicroCents(amountInCents), invoiceID, - paymentID: invoice.payments?.data[0].payment.payment_intent as string, + paymentID, customerID, }) }) diff --git a/packages/console/core/src/schema/billing.sql.ts b/packages/console/core/src/schema/billing.sql.ts index 915646cf3da0..ef32839c83a1 100644 --- a/packages/console/core/src/schema/billing.sql.ts +++ b/packages/console/core/src/schema/billing.sql.ts @@ -107,7 +107,7 @@ export const PaymentTable = mysqlTable( } >(), }, - (table) => [...workspaceIndexes(table)], + (table) => [...workspaceIndexes(table), uniqueIndex("payment_invoice_id").on(table.invoiceID)], ) export const UsageTable = mysqlTable(