Stripe invoice.paid webhook in Next.js
A renewal webhook should extend access exactly once. Test the invoice, billing reason, subscription mapping, and duplicate replay before production traffic arrives.
Fields to trust
Use paid invoice state, invoice ID, customer ID, subscription ID, currency, amount, line items, and price IDs.
Separate subscription creation, renewal, manual invoice, and update flows so the route does not extend access on the wrong signal.
Extend access using provider period data or your subscription record, not local clock guesses.
Key on invoice or provider event identity so duplicate replay cannot extend the same period twice.
Next.js route order
Read await request.text(), verify Stripe-Signature, parse the event, verify the invoice state, then extend the entitlement inside an idempotency guard.
export async function POST(request: Request) {
const rawBody = await request.text();
const signature = request.headers.get("Stripe-Signature");
const event = verifyStripeEvent(rawBody, signature);
if (event.type === "invoice.paid") {
await runOnce(`stripe-invoice:${event.data.object.id}`, async () => {
await extendSubscriptionEntitlement(event.data.object);
});
}
return new Response("ok", { status: 200 });
}
CI gates
- Signed
invoice.paidfixture extends access once. - Mutated raw body returns 400 before entitlement writes.
- Duplicate replay of the same invoice does not double-extend access.
- Unpaid, void, draft, or unknown invoice fixtures do not grant access.
billing_reasonchanges are visible in the release review report.
FAQ
Should Stripe invoice.paid grant access in a Next.js webhook?
It can extend subscription access when the invoice is paid, the subscription and price map to the user, and the idempotency key proves the invoice has not already extended access.
What is the difference between invoice.paid and checkout.session.completed?
checkout.session.completed is often the first purchase signal, while invoice.paid covers paid invoices such as subscription creation, renewal, or manual payment depending on billing_reason.
Turn renewal handling into release evidence
The free fixture and test plan tools cover the renewal path. The CNY 69 Pro Kit is for teams that want fixtures, idempotency tests, entitlement matrices, and review templates already packaged.