Skip to content

Hono

import { Hono } from 'hono';
import { verihookHono, type VerihookVariables } from 'verihook/hono';
import type { StripeEvent } from 'verihook';
type Env = {
Bindings: { STRIPE_WEBHOOK_SECRET: string };
Variables: VerihookVariables<StripeEvent>;
};
const app = new Hono<Env>();
app.post('/webhooks/stripe', verihookHono('stripe', (c) => c.env.STRIPE_WEBHOOK_SECRET), (c) => {
const { event, eventType } = c.get('verihook');
return c.json({ received: true });
});
export default app;

The secret function receives the context, so it can read Worker bindings. On Node.js or Bun you can pass a string. The body stays readable after verification (c.req.json() still works).

onError(result, c) returns your own Response for failures.

Situation Response
Invalid, missing or expired signature 401 { error, code }, unless you pass onError
Duplicate event (with dedupeStore) 200 { received: true, duplicate: true }
Body over maxBodySize (default 2 MB) 413 { code: "PAYLOAD_TOO_LARGE" }
Exception during verification 500 with a generic message
Your handler throws or responds >= 500 The dedupe key is released so the retry is processed

All verification options (tolerance, dedupeStore, url, …) can be passed as the last argument. Pick your provider in Providers for the secret and the headers it sends.