Thank you! And honestly — re-fetch alone WAS enough for state correctness, and that's the part I'd emphasize to anyone pre-payments: if every handler re-fetches live state by subscription ID instead of trusting the payload, processing becomes convergent. A duplicate event just re-fetches the same truth and writes the same row. Duplicates become harmless no-ops against the DB. Where it still bites is side effects. The DB converges, but nothing stops a duplicate from re-sending the "Welcome to Pro" email, double-logging an upgrade analytics event, or burning a redundant Stripe API call. So no — I didn't originally store event IDs, and I learned the hard way that state idempotency ≠ side-effect idempotency. What's on the backlog now: a small processed_events table (event_id PK, type, created_at, processed_at). Handler checks it first and returns 200 early on duplicates, plus an ordering guard — only apply if event.created is newer than the last applied timestamp for that subscription, so a stale retry can't overwrite fresher state under concurrent delivery. Since you're pre-payments on Supabase, the combo I'd wire from day one: (1) verify signatures, (2) re-fetch live state, (3) event-ID store for side effects. It's maybe 30 lines of Edge Function and it deletes an entire class of 2 AM bugs. Happy to share my handler skeleton if it's useful — good luck with the wiring, it's about to get interesting!
