Local-first Webhook Toolkit

Stop fightingwebhooks.

The local-first toolkit for capturing, replaying, and shipping type-safe webhook handlers in TypeScript.

Quick Install

$ brew install --cask endalk200/tap/better-webhook
View on GitHub
5
Providers
5
Adapters
100%
Type-safe
TYPE-SAFE LOCAL-FIRST OPEN SOURCE SECURE TYPESCRIPT ZERO BOILERPLATE FAST EXTENSIBLE TYPE-SAFE LOCAL-FIRST OPEN SOURCE SECURE TYPESCRIPT ZERO BOILERPLATE FAST EXTENSIBLE
Quick Start

Get started in 60s

Build type-safe webhook handlers with automatic signature verification in your framework of choice.

1

Install packages

$ npm install @better-webhook/github @better-webhook/nextjs
2

Create webhook handler

app/api/webhooks/github/route.ts
import { github } from "@better-webhook/github";
import { push, pull_request } from "@better-webhook/github/events";
import { toNextJS } from "@better-webhook/nextjs";

const webhook = github()
  .event(push, async (payload) => {
    console.log(`Push to ${payload.repository.name}`);
  })
  .event(pull_request, async (payload) => {
    if (payload.action === "opened") {
      console.log(`New PR: ${payload.pull_request.title}`);
    }
  });

export const POST = toNextJS(webhook);
3

Set webhook secret

# .env
GITHUB_WEBHOOK_SECRET=your_webhook_secret

Done! Your webhook endpoint has automatic signature verification and full TypeScript support.

Features

Everything you need for webhook dev

A focused SDK for production webhook handlers, provider events, and framework adapters.

SDK

Type-Safe Handlers

Full TypeScript support with Zod schemas. Get autocomplete for every event payload property.

SDK

Signature Verification

Automatic signature verification for GitHub, Stripe, Ragie, Recall.ai, and Resend with timing-safe comparison.

SDK

Framework Adapters

First-class integrations for Next.js, Hono, Express, NestJS, and GCP Cloud Functions.

SDK

Replay Protection

Optional duplicate detection with provider replay keys and configurable duplicate handling.

SDK

Typed Event Catalogs

Provider packages expose curated event definitions so handlers stay precise and discoverable.

SDK

Custom Providers

Define your own providers with schemas, signature verification, and event matching.

SDK Packages

Type-safe. Verified. Simple.

Build webhook handlers with full TypeScript support, automatic signature verification, and Zod schema validation.

Signature Verification

Automatic HMAC verification for all providers. Timing-safe comparison prevents attacks.

Type-Safe Handlers

Full TypeScript support with Zod schemas. Autocomplete for every payload property.

Framework Adapters

First-class support for Next.js, Hono, Express, NestJS, and GCP Functions.

$ npm install @better-webhook/github @better-webhook/nextjs
app/api/webhooks/github/route.ts
import { github } from "@better-webhook/github";
import { push, pull_request } from "@better-webhook/github/events";
import { toNextJS } from "@better-webhook/nextjs";

const webhook = github()
  .event(push, async (payload) => {
    console.log(`Push to ${payload.repository.name}`);
    console.log(`${payload.commits.length} commits`);
  })
  .event(pull_request, async (payload) => {
    if (payload.action === "opened") {
      console.log(`New PR: ${payload.pull_request.title}`);
    }
  })
  .onError((error, context) => {
    console.error(`Error in ${context.eventType}`, error);
  });

export const POST = toNextJS(webhook);

Available Providers

G

GitHub

@better-webhook/github
pushpull_requestissuesinstallation+1 more
R

Ragie

@better-webhook/ragie
document_status_updateddocument_deletedentity_extractedconnection_sync_started+4 more
S

Stripe

@better-webhook/stripe
charge.failedcheckout.session.completedpayment_intent.succeeded
R

Recall.ai

@better-webhook/recall
participant_events.joinparticipant_events.leaveparticipant_events.chat_messagetranscript.data+21 more
R

Resend

@better-webhook/resend
email.deliveredemail.bouncedemail.receiveddomain.updated+13 more

See the difference

Compare traditional webhook handling with better-webhook. Less boilerplate, more safety.

route.tsbetter-webhook
1// The better-webhook way - type-safe and secure
2
3import { github } from "@better-webhook/github";
4import { push } from "@better-webhook/github/events";
5import { toExpress } from "@better-webhook/express";
6
7const webhook = github()
8 .event(push, async (payload) => {
9 // Full autocomplete and type safety!
10 console.log(payload.repository.name);
11 console.log(payload.commits.length);
12
13 for (const commit of payload.commits) {
14 console.log(commit.message);
15 }
16 })
17 .onError((error, context) => {
18 logger.error(`Failed: ${context.eventType}`, error);
19 });
20
21app.post('/webhooks/github',
22 express.raw({ type: 'application/json' }),
23 toExpress(webhook)
24);

What changes

Automatic signature verification
Full type inference with Zod
Schema-validated payloads
Built-in error hooks
Less boilerplate with adapters
~20%
Less boilerplate
Providers

Webhook Providers

Pre-built providers with automatic signature verification and fully typed payloads. Create custom providers for any webhook source.

G

GitHub

R

Ragie

S

Stripe

R

Recall.ai

R

Resend

+

Custom

G

GitHub

@better-webhook/github

Example Events

pushpull_requestissuesinstallationinstallation_repositories
R

Ragie

@better-webhook/ragie

Example Events

document_status_updateddocument_deletedentity_extractedconnection_sync_startedconnection_sync_progressconnection_sync_finished
S

Stripe

@better-webhook/stripe

Example Events

charge.failedcheckout.session.completedpayment_intent.succeeded
R

Recall.ai

@better-webhook/recall

Example Events

participant_events.joinparticipant_events.leaveparticipant_events.chat_messagetranscript.datatranscript.partial_databot.joining_callbot.donebot.fatal
R

Resend

@better-webhook/resend

Example Events

email.deliveredemail.bouncedemail.receiveddomain.updatedcontact.created

Need a different provider? Create custom webhooks with the core package.