Stripe webhook · symptom
Out-of-order events
customer.subscription.updated (active) arrived after customer.subscription.deleted, user got Pro backWhat it means
Stripe doesn't guarantee delivery order. A retried older event can land after a newer one, so writing event.data.object blindly can overwrite fresh state with stale state.
Common causes
- Writing the event payload snapshot straight to the database
- Assuming created always arrives before updated
- Retries of an old event
How to fix it
- Take only the object id from the event
- Re-fetch the subscription with stripe.subscriptions.retrieve(id) and write its current state
- Or compare event.created / a stored timestamp and ignore older events
case "customer.subscription.updated":
case "customer.subscription.deleted": {
const sub = await stripe.subscriptions.retrieve(event.data.object.id);
await db.user.updateMany({
where: { stripeCustomerId: sub.customer as string },
data: { subscriptionStatus: sub.status },
});
break;
}stripe listen --forward-to localhost:3000/api/stripe/webhook
# put the whsec_... it prints in .env.local, then restart npm run dev
stripe trigger customer.subscription.updated
stripe events resend evt_... # the customer.subscription.created event from that run
pass if After the older event is replayed, the stored subscription still matches what the Dashboard shows.
Prompt for Cursor or Claude Code
My Stripe webhook can apply stale subscription state when events arrive out of order. Change the handler to take only the subscription id from the event, re-fetch it with stripe.subscriptions.retrieve, and write its current state. Add a test where updated(active) arrives after deleted.Not quite your error? Paste yours into the free VibeBoot Doctor or browse the Stripe webhook fixer.
next: skip the next one
Skip the debugging. The VibeBoot SaaS Starter ships with this already handled: a signature-verified webhook (raw body + constructEvent) that re-fetches the subscription from Stripe before saving it, with Vitest tests. Plus auth and a database on Next.js 16.4.3. $49, one-time.
14-day money-back guarantee · lifetime updates
Other Stripe webhook errors
$ fixed it? get the next one first
New fixes for what AI agents break, by email.
When we add a fix or a Cursor rule for a new Next.js, Auth.js, Prisma or Stripe break, it goes out in the VibeBoot newsletter. Free, occasional, unsubscribe in one click.