hooksentinel
Frameworks

Next.js

Handle webhooks in a Next.js App Router route handler with hooksentinel.

Install

npm install @hooksentinel/core

@hooksentinel/core/next exports toRouteHandler for App Router route handlers.

App Router route handler

Next.js Route Handlers give you the raw Request object, so there's no separate raw-body middleware to configure — reading request.text() or request.arrayBuffer() before parsing is the default behavior, not something you opt into.

app/webhooks/stripe/route.ts
import { createWebhookHandler, stripe } from '@hooksentinel/core';
import { toRouteHandler } from '@hooksentinel/core/next';
import { redisStore } from '@hooksentinel/core/stores';

const stripeWebhook = createWebhookHandler({
  provider: stripe({ secret: process.env.STRIPE_WEBHOOK_SECRET! }),
  idempotency: redisStore({ url: process.env.REDIS_URL! }),
  onEvent: async (event) => {
    if (event.type === 'checkout.session.completed') {
      await fulfillOrder(event.data.object.id);
    }
  },
});

export const POST = toRouteHandler(stripeWebhook);

async function fulfillOrder(sessionId: string) {
  // ...
}

toRouteHandler returns a standard (request: Request) => Promise<Response> function — exactly the shape App Router expects for a route's POST export.

Don't add a body config

Older Pages Router API routes needed export const config = { api: { bodyParser: false } } to get the raw body. App Router route handlers don't have this problem — there's no implicit body parsing to disable. If you're migrating a Pages Router webhook, you can delete that config entirely; adding it to an App Router route handler does nothing and isn't needed.

Runtime

hooksentinel's core has zero runtime dependencies and uses only Web Crypto APIs available in both the Node.js and Edge runtimes, so the handler works unmodified with:

app/webhooks/stripe/route.ts
export const runtime = 'edge'; // optional — works either way

Use nodejs (the default) unless you have another reason to run on the edge; there's no verification-speed benefit either way since HMAC-SHA256 is fast on both runtimes.

Multiple providers

One route file per provider, following Next.js's normal file-based routing:

app/
  webhooks/
    stripe/route.ts
    github/route.ts
    shopify/route.ts

Each exports its own POST built from its own createWebhookHandler instance.

Local testing with the Stripe CLI

stripe listen --forward-to localhost:3000/webhooks/stripe

Route handlers work the same in next dev as in production — no proxy or rewrite configuration needed for the raw body to come through correctly.

Last updated on

On this page