fix(billing): deep-audit P0/P1 fixes for the pinned Stripe API (2026-04-22.dahlia)
Independent audit (verified vs Stripe Basil 2025-03-31 changelog): - P0: period end moved off the top-level Subscription -> read sub.items.data[0].current_period_end (grace/lapse now actually fires; was always null -> past_due members never went 'late'). - P0: invoice subscription metadata moved under invoice.parent. subscription_details -> read parent (metadata member-resolution was always failing, mislinking dues payments). - P1: handle only invoice.paid (not also invoice.payment_succeeded) + pre-insert dedupe on (space_id,platform,external_id) -> no double payment-ledger rows. - P2: idempotencyKey on customers.create -> no duplicate Stripe customers under concurrent checkout. - 040: documented the 'do not wrap in manual BEGIN/COMMIT' caveat. (P0 webhook-reprocess-on-failure was fixed in ca34e53.) Audit verdict: isolation/secrets/RLS/status-bounds were already sound.
This commit is contained in:
+10
-5
@@ -141,11 +141,16 @@ export async function startDuesCheckout() {
|
||||
|
||||
let customerId = billing?.stripe_customer_id as string | undefined
|
||||
if (!customerId) {
|
||||
const customer = await stripe.customers.create({
|
||||
email: (m.email as string | null) ?? undefined,
|
||||
name: (m.display_name as string | null) ?? undefined,
|
||||
metadata: { space_id: member.space_id, member_id: member.id },
|
||||
})
|
||||
// Idempotency key keyed by member: concurrent checkouts won't create
|
||||
// duplicate Stripe customers (Stripe returns the same customer).
|
||||
const customer = await stripe.customers.create(
|
||||
{
|
||||
email: (m.email as string | null) ?? undefined,
|
||||
name: (m.display_name as string | null) ?? undefined,
|
||||
metadata: { space_id: member.space_id, member_id: member.id },
|
||||
},
|
||||
{ idempotencyKey: `cust:${member.space_id}:${member.id}` },
|
||||
)
|
||||
customerId = customer.id
|
||||
await admin
|
||||
.from('member_billing')
|
||||
|
||||
Reference in New Issue
Block a user