From ca34e5393af97d276b27d1b17e25f2b877648ca3 Mon Sep 17 00:00:00 2001 From: Moheeb Zara Date: Sun, 17 May 2026 03:43:33 -0700 Subject: [PATCH] fix(billing): webhook reprocesses on handler failure (no lost events) Self-audit finding: the idempotency row is written before processing, so a handler exception/500 followed by Stripe's retry would be suppressed as a duplicate and the event silently dropped. On the error path, delete the dedupe row so the retry reprocesses. (Bad-signature/ config 400s and the non-unique insert-error 500 never wrote the row, so those were already clean.) --- app/api/stripe/webhook/[space]/route.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/api/stripe/webhook/[space]/route.ts b/app/api/stripe/webhook/[space]/route.ts index 73e5af4..faa5479 100644 --- a/app/api/stripe/webhook/[space]/route.ts +++ b/app/api/stripe/webhook/[space]/route.ts @@ -181,6 +181,10 @@ export async function POST( break } } catch (e) { + // The dedupe row was written BEFORE processing; if processing failed, + // remove it so Stripe's retry of this same event is reprocessed rather + // than silently short-circuited as a duplicate (no lost events). + await admin.from('stripe_webhook_events').delete().eq('event_id', event.id) return NextResponse.json( { error: e instanceof Error ? e.message : 'handler error' }, { status: 500 },