Guides / Payments
When a payment fails, Stripe retries automatically (dunning). You want to be notified at each stage:
// app/api/webhooks/stripe/route.ts (add to existing handler)
case "invoice.payment_action_required": {
const invoice = event.data.object as Stripe.Invoice;
await logit.now("dunning", {
event: "Payment action required",
description: `Customer ${invoice.customer_email ?? invoice.customer} needs to update card`,
icon: "⚠️",
notify: true,
tags: { stage: "action_required" },
metadata: {
invoiceId: invoice.id,
customerId: invoice.customer as string,
email: invoice.customer_email,
amount: (invoice.amount_due ?? 0) / 100,
},
});
break;
}
case "invoice.payment_succeeded": {
const invoice = event.data.object as Stripe.Invoice;
// Check if this was a recovery (billing_reason = subscription_cycle means initial, not retry)
if (invoice.billing_reason === "subscription_update" || invoice.attempt_count > 1) {
await logit.now("dunning", {
event: "Failed payment recovered",
description: `$${((invoice.amount_paid ?? 0) / 100).toFixed(2)} recovered after ${invoice.attempt_count} attempts`,
icon: "🎉",
notify: true,
tags: { stage: "recovered", attempts: String(invoice.attempt_count) },
metadata: {
invoiceId: invoice.id,
customerId: invoice.customer as string,
amount: (invoice.amount_paid ?? 0) / 100,
attemptCount: invoice.attempt_count,
},
});
}
break;
}
case "customer.subscription.deleted": {
const sub = event.data.object as Stripe.Subscription;
// Check if deleted due to non-payment
if (sub.cancellation_details?.reason === "payment_failed") {
await logit.now("dunning", {
event: "Subscription lost to dunning",
description: `Customer ${sub.customer} churned — all retries exhausted`,
icon: "🚨",
notify: true,
tags: { stage: "lost", reason: "payment_failed" },
metadata: {
subscriptionId: sub.id,
customerId: sub.customer as string,
},
});
}
break;
}
Add these to your Stripe webhook:
invoice.payment_failedinvoice.payment_action_requiredinvoice.payment_succeededcustomer.subscription.deleteddunning channelHaving a dedicated channel lets you see at a glance how many customers are in recovery at any time — and whether your dunning rate is improving.
Try LogIt free
7-day trial. No credit card required.