Skip to content
Zap Studio
webhooks
Esc
navigateopen⌘Jpreview
On this page

webhooks

Schema-first, type-safe webhook routing built on the standard Web API Request and Response primitives, with runtime-agnostic signature verification support.

webhooks is schema-first, type-safe webhook routing built on the standard Web API Request and Response primitives, with runtime-agnostic signature verification support.

Motivation

Webhook endpoints are usually built by hand, per provider, and this tends to repeat the same two mistakes. First, signature checks often use Node’s crypto module, which does not exist on Cloudflare Workers, Deno, or Bun’s edge runtimes — so the same code cannot run everywhere the webhook needs to be received.

Second, signatures are often compared with ===, which leaks timing information and opens a timing-attack risk that most teams do not know they have.

webhooks fixes both. It is built on the standard Request/Response objects, so the same router works on Bun, Deno, Cloudflare Workers, or any framework that accepts a Request.

Signature verification is opt-in through the verify option, and the built-in HMAC verifier uses the Web Crypto API (globalThis.crypto.subtle) with a constant-time comparison, so once you turn it on, you get the safe comparison without writing it yourself. Payloads are validated and typed straight from your Standard Schema — no any from JSON.parse, no manual casts.

Features

  • Web API nativehandle(request: Request) returns a Response, so the router plugs directly into Bun, Deno, Cloudflare Workers, Next.js route handlers, Hono, and any other fetch-compatible runtime.
  • Type-safe routing — handler payload types are inferred from the route schema.
  • Standard Schema validation — bring Zod, Valibot, ArkType, or any compatible library.
  • Signature verification — built-in HMAC verifier with constant-time comparison, or plug in your own verify function.
  • Lifecycle hooks — global before, after, and onError hooks for cross-cutting behavior.
  • Runtime-agnostic — uses the Web Crypto API, not Node-specific APIs.
  • Optional logging through createWebhookRouter({ logger }) from logger — omit it and there’s zero logging overhead.
  • Native OpenTelemetry — a SERVER span per delivery continuing the sender’s trace, plus a child span per handler dispatch, no-op until an SDK is registered.
  • Tree-shakeable — validation and hook-running internals are standalone functions; unused exports are dropped by any modern bundler.

Quick Start

import { ConsoleLogger } from "@zap-studio/logger";
import { createWebhookRouter } from "@zap-studio/webhooks";
import { z } from "zod";

const logger = new ConsoleLogger({ minLevel: "debug" });
const router = createWebhookRouter({ prefix: "/webhooks", logger });

router.register("/payments/succeeded", {
  schema: z.object({ id: z.string(), amount: z.number().positive() }),
  handler: ({ payload }) => {
    // payload is inferred from schema
    return Response.json({ processed: payload.id });
  },
});

export default {
  fetch: (request: Request) => router.handle(request),
};

Learn More

  • Getting Started — install and build your first router step by step
  • Web API Native — mounting the router in Bun, Deno, Cloudflare Workers, Next.js, and Hono
  • Type-Safe Routing — how handler payload types are inferred from the route schema
  • Standard Schema — using Zod, Valibot, ArkType, or any compatible library
  • Verification — HMAC signature verification and the Web Crypto API
  • Lifecycle Hooksbefore, after, and onError hooks
  • Logging — observe delivery attempts, dispatch, verification failures, and unmatched routes
  • OpenTelemetry — native distributed tracing

Runtime Support

Runtime Minimum version
Node.js 18.0.0 (router), 19.0.0 (verification helper)
Bun 1.0.0
Deno 1.42
Cloudflare Workers Any current release
Browsers Latest evergreen (Chrome, Edge, Firefox, Safari)

The router only needs the standard Request/Response APIs, available globally since Node.js 18. The verification helper additionally needs globalThis.crypto.subtle, which is global by default from Node.js 19 (on Node.js 18, pass the --experimental-global-webcrypto flag). In browsers, Web Crypto requires a secure context (HTTPS). Deno 1.42 is the first release that can install packages from JSR (deno add jsr:@zap-studio/webhooks).

Last updated on September 15, 2026

Was this page helpful?