Webhooks for Next.js, done right

Verified, typed, idempotent webhook receivers for the App Router. Zero dependencies, runs on Node and Edge.

pnpm add next-webhooks
app/api/webhooks/stripe/route.ts
import { webhook, stripe } from "next-webhooks";
import { z } from "zod";

export const POST = webhook({
  provider: stripe({ secret: process.env.STRIPE_WEBHOOK_SECRET! }),
  events: {
    "invoice.paid": z.object({ id: z.string(), amount_due: z.number() }),
  },
  on: {
    "invoice.paid": async (event) => {
      // event.payload is validated and typed from the schema
    },
  },
});

Verified signatures

Every delivery is checked before your handler runs. Forged requests get a 401 with the reason.

Duplicates skipped

The same event id is acknowledged once. A failed handler releases it, so the retry is processed. Ready-made Upstash store for serverless.

Validated, typed events

Declare payloads with zod, valibot, or arktype schemas. Validated at runtime, types inferred, handlers routed per event.

Zero dependencies

About 2 kB gzipped. Web Crypto only, no provider SDKs, nothing added to your lockfile.

Node and Edge

The same route handler runs on a server, on serverless, or on the Edge runtime.

Dev tools

Scaffold routes, fire signed events at localhost, capture and replay real deliveries, and check your setup with the CLI.