Stripe
Handling failed Stripe payments
The Designyff subscription webhook does not listen for invoice.payment_failed. Past-due subscriptions fall back to the free plan.
A failed renewal is an invoice problem. The kits do not subscribe to invoice.payment_failed. They subscribe to checkout completion and to subscription updates.
In the Complete SaaS Starter Kit webhook, a subscription is Pro only when its status is active or trialing:
const active = subscription.status === "active" || subscription.status === "trialing";
await prisma.user.updateMany({
where: { stripeSubscriptionId: subscription.id },
data: { plan: active ? "pro" : "free" }
});
When Stripe moves the subscription to past_due, the next customer.subscription.updated event clears plan to "free". The same happens on customer.subscription.deleted. The Stripe Subscription Starter uses that status check too.
What this does not do
There is no dunning email, no retry counter, and no grace period stored in Prisma. Stripe’s own retry settings still run in the Dashboard. If you need a banner that says the card failed while keeping Pro access, you would store the status string instead of folding every non-active status into "free". The current code does not do that.
Signature verification for these events is in Stripe webhooks with Next.js. Customers can update a card in the Customer Portal.