Next.js
In the App Router, a route handler reads the raw body with request.text() and passes
the Fetch Headers straight to verify.
npm install ricochet-webhooksimport { verify, WebhookVerificationError } from 'ricochet-webhooks';
// ricochet-webhooks uses node:crypto.export const runtime = 'nodejs';
export async function POST(request: Request) { const body = await request.text(); let id: string; try { ({ id } = verify(body, request.headers, process.env.RICOCHET_WEBHOOK_SECRET!)); } catch (error) { if (error instanceof WebhookVerificationError) { return new Response(error.reason, { status: 401 }); } throw error; }
// Skip the delivery if `id` was already handled (store it in your database). const event = JSON.parse(body); console.log('received', id, event.type); return new Response(null, { status: 200 });}The route is POST /webhooks; point your destination at
https://<your app>/webhooks.
For the Pages Router, turn off the body parser for the route
(export const config = { api: { bodyParser: false } }) and read the raw body from the
request stream before calling verify(body, req.headers, secret).
Try it locally
Section titled “Try it locally”npm run devricochet listen --forward localhost:3000/webhooksDeliveries through the CLI carry no webhook-signature (a CLI destination has no
signing secret), so turn the check off in local development, for example with an
environment variable. Never skip it just because the header is missing: that would
accept unsigned requests in production too.