Introduction
Good Webhooks is a TypeScript library that adds outbound webhooks to your application, using your PostgreSQL database.
Good Webhooks lets your application send webhooks to your customers. You publish an event; it handles the rest: who should receive it, signing, retries, history, and replay. It runs inside your app and stores everything in your PostgreSQL database. There is no extra service to host.
- your appPublish
publish()validates the payload and finds subscribed endpoints. - PostgreSQLStore
The event and one delivery per endpoint commit with your data.
- workerDeliver
A worker signs each request, sends it, and retries failures.
- receiverVerify
The receiver checks the signature and gets a typed event.
In code
import { createWebhooks } from 'good-webhooks'
import { Pool } from 'pg'
import { z } from 'zod'
export const webhooks = createWebhooks({
database: new Pool({ connectionString: process.env.DATABASE_URL }),
encryptionKey: process.env.WEBHOOK_ENCRYPTION_KEY!,
events: {
'invoice.paid': z.object({ invoiceId: z.string(), amount: z.number().int() }),
},
})
await webhooks.publish({
type: 'invoice.paid',
data: { invoiceId: 'inv_123', amount: 4200 }, // type-checked against the schema
})What it handles for you
Most teams start with a fetch() in a request handler. Then a customer's server goes down and events are lost, a deploy sends duplicates, or a URL points at an internal service. Good Webhooks covers those cases:
| Good Webhooks handles | You decide |
|---|---|
| Endpoint storage, encrypted secrets, URL safety checks | Who may manage which endpoints |
| Payload validation, idempotency, recipient selection | When to publish, and in which transaction |
| Signing, retries, attempt history, replay | Where the worker runs and how it's supervised |
| Migration SQL and schema checks | When migrations run |
| Signature verification and typed parsing for receivers | What the receiver does with the event |
Nothing starts on its own: creating the client opens no connections, runs no migrations, and starts no workers.
Beta
The public API is frozen except for correctness and security fixes. Pin the exact version and read the stability policy and the release notes before upgrading.