verihook

Universal typed webhook verifier for Stripe, GitHub, Shopify, Slack, Twilio, Svix, Meta, WhatsApp, Discord, Twitter, PayPal, LemonSqueezy, Paddle, PagerDuty, Webflow, WorkOS, Linear, Razorpay, Cashfree, PhonePe, Mollie, Adyen, Checkout.com, Authorize.net,
6,114 1
Install
npm install verihook
Latest Version:1.21.2
License:MIT
Last Updated:Oct 19, 2026
Links: GitHub  ·  npm
Maintainer: creatorpiyush

verihook 🪝

Universal, typed webhook signature verifier for TypeScript and JavaScript.

npm version JSR docs license CI Verification coverage bundle size OpenSSF Scorecard zero dependencies TypeScript npm downloads

Documentation · Providers · Frameworks · Troubleshooting · Changelog

verihook verifies webhook signatures from Stripe, GitHub, Shopify, Slack, Twilio, Clerk, Resend, Paddle, Razorpay and 30+ other providers with one typed API, so you don't copy a different HMAC snippet for every service or install ten SDKs.

  • Zero dependencies. Web Crypto, so it runs on Node.js 18.17+, Deno, Bun, Cloudflare Workers and Vercel Edge.
  • One-line adapters for Next.js, Express, Fastify, Hono, NestJS, Nuxt/h3, SvelteKit, Remix/React Router, Astro and AWS Lambda. They keep the raw body for you.
  • Says what went wrong. Failed checks return an error code and a hint: a parsed body, an API key instead of the signing secret, a proxy rewriting the URL.
  • Typed events. result.event is the parsed payload, typed per provider; result.eventType is its name.
  • Testing helpers. verihook/testing signs requests for every provider; npx verihook simulate sends them to your local server.
  • Hardened. Timing-safe comparison, replay windows, deduplication keyed only on signed data, body size limits. Conformance-tested against the official Stripe, GitHub, Svix and Twilio SDKs, and fuzz-tested.
  • Small. One provider from verihook/stripe is ~4 kB min+brotli; all of them ~10 kB.

Install

npm install verihook        # or pnpm add / yarn add / bun add
deno add jsr:@verihook/verihook

Quick start

import { verifyWebhook } from 'verihook';

export async function POST(request: Request) {
  const result = await verifyWebhook('stripe', request, process.env.STRIPE_WEBHOOK_SECRET!);

  if (!result.valid) {
    console.warn(result.code, result.reason, result.hint);
    return new Response('Invalid signature', { status: 401 });
  }

  console.log(result.eventType, result.event); // "invoice.paid", typed as StripeEvent
  return Response.json({ received: true });
}

request is a Fetch Request or { headers, body, url? } with the raw body. Signatures cover the exact bytes sent, so verify before any JSON parser touches the body (why).

Frameworks

// Next.js App Router: app/api/webhooks/github/route.ts
import { createWebhookHandler } from 'verihook/next';

export const POST = createWebhookHandler('github', process.env.GITHUB_WEBHOOK_SECRET!, async (payload, result) => {
  // runs only for a valid signature
});
// Express: register before express.json()
import { verihookExpress } from 'verihook/express';

app.post('/webhooks/stripe', verihookExpress('stripe', process.env.STRIPE_WEBHOOK_SECRET!), (req, res) => {
  res.json({ received: true });
});
Framework Import Guide
Next.js verihook/next docs
Express verihook/express docs
Fastify verihook/fastify docs
Hono / Workers / Bun / Deno verihook/hono docs
NestJS verihook/nestjs docs
Nuxt / Nitro / h3 verihook/h3 docs
SvelteKit verihook/sveltekit docs
Remix / React Router verihook/remix docs
Astro verihook/astro docs
AWS Lambda verihook/lambda docs

Every adapter answers 401 to a bad signature, 413 to an oversized body and 200 to a duplicate event.

Providers

Each page says where to find the secret, which headers are sent and how to verify in every framework.

Stripe stripe GitHub github Shopify shopify
Slack slack Twilio twilio Svix svix
Resend resend Clerk clerk Meta / WhatsApp meta
Discord discord X (Twitter) twitter PayPal paypal
Lemon Squeezy lemonsqueezy Paddle paddle PagerDuty pagerduty
Webflow webflow WorkOS workos Linear linear
Razorpay razorpay Square square Zoom zoom
Cashfree cashfree PhonePe phonepe Mollie mollie
Adyen adyen Checkout.com checkout Authorize.net authorizenet
Recurly recurly GitLab gitlab Bitbucket bitbucket
Vercel vercel Sentry sentry Twitch EventSub twitch
Telegram telegram Postmark postmark SendGrid sendgrid
Mailgun mailgun HubSpot hubspot Intercom intercom
Calendly calendly Typeform typeform Standard Webhooks standard-webhooks

Anything else: the generic HMAC verifier or your own provider.

Testing your handlers

import { signWebhook } from 'verihook/testing';

const hook = await signWebhook('stripe', {
  secret: 'whsec_test',
  payload: { id: 'evt_1', type: 'payment_intent.succeeded' },
});

await request(app).post('/webhooks/stripe').set(hook.headers).send(hook.body).expect(200);
npx verihook simulate stripe --url http://localhost:3000/webhooks/stripe

See Testing and the CLI, including the listen relay.

More

Contributing

Contributions are welcome, especially new providers. CONTRIBUTING.md covers setup, the provider template and the PR checklist. npm run test:all runs everything CI runs.

License

MIT © Piyush Anand

Related Packages

lightmoon

Application-layer firewall for every JavaScript server and edge runtime: managed...

1,144
sitegate

A secure, self-hosted password gate for staging and preview websites.

1,488 0
@allturko/nabiz-node

Nabız Hub için Node.js raporlayıcı — sunucu hataları, SSR hataları, yavaş istekl...

1,336 0
@watchforge/browser

WatchForge JavaScript SDK: automatic error, log and performance capture for brow...

5,289
@zeroad.network/token

Offline verification of Zero Ad Network subscriber tokens for publisher backends...

4,274 0

Version History

Version Released License
1.21.2 MIT
1.21.1 MIT
1.21.0 MIT
1.20.0 MIT
1.19.0 MIT