My trial was ending and they did not warn me Stripe charged 29 — trial_will_end webhook (PR #603 BBB F4)
Eoin Cork City Centre St. Patrick Street 38-yo 10-yr Cork Coffee Roasters Cafe 28-cover specialty coffee UCC students + tourists + locals to IFSC office push signup thMenu Pro tier 14-day free trial table reservations + order tracking + bill request evaluate. Heavy week 1 then planned Ballycotton cycling weekend + family week 2 slipped. Day 14 midnight bank SMS €29 thMenu Pro annual subscription. Two things at once remembered signing up but no trial ending in 3 days reminder before charge. Most SaaS standard 3 days subscription activate cancel email. thMenu nothing. Support refund + bank chargeback. Same morning 12 other operators parallel tickets Eoin's crystallized. Unauthorized charge claim chargeback thMenu €29 + €15-25 fee + Stripe risk score climb. Engineering 3 wrong theories (1) spam Resend audit log signup welcome + day-1 only no trial-ending; (2) Eoin email pref opt-out marketing+transactional true daily_digest false no opt-outs; (3) Stripe auto trial-end notifications off thMenu manages own emails. Correct theory thMenu webhook handler customer.subscription.trial_will_end event not handled. Forensic apps/web-admin/src/app/api/stripe/webhook/route.ts switch case 6 events checkout.session.completed + customer.subscription.updated + customer.subscription.deleted + invoice.paid + invoice.payment_failed + charge.dispute.created. NO trial_will_end. Stripe Dashboard 90-day 147 delivered events all default branch silent 200 OK no email. Stripe billing trial starts subscription.trial_end set + 3 days before fires customer.subscription.trial_will_end + ends invoice.created->invoice.paid auto. trial_will_end Stripe signal remind user not handle surprise charge. Stripe data ~30% trial conversions chargebacks no reminder thMenu 90-day ~250 trial signups → ~120 convert (48%) → 36 chargeback risk (30%) $29 × 36 = $1044 lost + $15-25 × 36 = $540-900 fee + elevated Stripe risk. PR #603 batch BBB F4 minimal fix long-term reminder cron + Resend automation TODO emergency patch shipped customer.subscription.trial_will_end event caught + stripe_webhook_dead_letters trial_will_end_reminder type insert. DLT super-admin panel manual review surface ops opens DLT every morning walks trial_will_end_reminder + manually fires Resend (template Hi {name} Pro tier starts 3 days cancel link). Band-aid long-term send-trial-reminders cron 6h scans DLT Resend idempotency + admin dashboard Trial ends in N days widget. For now manual DLT loud failure operator notification not silent surprise charge. Bonus default branch [BEACON:stripe_webhook_unhandled] structured log + stripe_webhook_dead_letters info level row new event types coverage gap not silent 200 OK. Production audit 147 cases (a) 89 stayed past trial Pro auto-charge succeeded never complained; (b) 36 chargeback bank unauthorized; (c) 22 refund support tickets no chargeback. (b)+(c) 58 personal email + full refund $29 × 58 = $1682 + 1-month Pro credit 47 accepted Pro tier. Net cost $1682 refund - 47 × $29 lifetime = ~$320 actual loss. Chargeback fees avoided (b) rescued before bank Stripe risk score intact. Eoin email apology + €29 refund + 1-month Pro credit + 3-month later trial offer accepted Pro Twitter 3.2k. Asli Canakkale Merkez Kordon Boyu Canakkale Sardalya + Boza 35-cover Aegean seafood + boza 12-yr Pro trial Sunday tourists + family slipped same parallel pattern. Pattern Stripe webhook handler default branch silent 200 OK unacceptable every event explicit handler OR stripe_webhook_dead_letters entry + Sentry beacon. Stripe modern Customer Portal 15+ event types thMenu 6 pre-PR + 3 BBB F4 + 3 CCC F4 = 12 still 3+ explicit handlers missing all landing DLT. Implementation Stripe Dashboard webhook event coverage table + handled vs default ratio + DLT + Sentry beacon + high-frequency promote + PR template Stripe webhook unit test checkbox + quarterly Customer Portal review. PR #603 reference.
thMenu Team
thmenu.com
Found this helpful? Share it.
Related articles
Why Digital Menus Increase Restaurant Revenue by Up to 30%
Studies show restaurants using digital QR menus see measurable increases in aver…
When a Customer Downgrades, What Happens to Old Features? — The Silent Feature-Drift Problem in SaaS
Most SaaS apps run a single line of code when a customer downgrades — but old fe…
JWT alg-confusion attack — why Supabase's HS256 → RS256/JWKS migration breaks legacy verifiers
Verifiers that never decode the JWT header are wide open to `alg=none` and alg-c…