BillingWebhookKit

Stripe refund webhook rollback in Next.js

A refund route is not done when it returns 200. It is done when signed Stripe refund events revoke or hold access once, leave support evidence, and survive duplicate replay.

Generate Stripe fixtures Draft rollback evidence

Events to cover

charge.refunded

Map the charge to the original checkout session, payment intent, customer, price, and access grant before rollback.

refund.created

Record refund ID, amount, reason, full or partial state, and the product policy that decides access changes.

charge.dispute.created

Hold or revoke access according to dispute policy, then leave support-safe evidence without exposing customer data.

unknown refund-like events

Return a safe response or quarantine for review, but never grant or revoke access by default.

Next.js App Router order

Read await request.text(), verify Stripe-Signature against the exact raw body, parse the event, build an idempotency key, then run the rollback decision once.

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 === "charge.refunded" || event.type === "refund.created") {
    await runOnce(`stripe:${event.id}`, async () => {
      await applyRefundRollback(event);
    });
  }

  return new Response("ok", { status: 200 });
}

CI gates

Rollback evidence

Keep the report secret-free: event type, event ID, refund ID, mapped payment object, entitlement decision, duplicate replay result, support action, and CI run link are enough for launch review.

FAQ

Which Stripe refund events should a Next.js webhook test cover?

Start with charge.refunded, refund.created, charge.dispute.created, and the original checkout.session.completed or invoice.paid object used to grant access.

How should a Stripe refund webhook rollback stay idempotent?

Build an idempotency key from the Stripe event or refund object, write one rollback record, and prove duplicate replay cannot revoke, email, or log support actions more than once.

Use the free generators before launch

The Stripe fixture generator and refund rollback report help document the route before public checkout. The CNY 69 Pro Kit is for teams that want copy-ready fixtures, idempotency tests, and review templates in one package.