Products / SaaS / Backend Infrastructure
HookQueue
HMAC webhooks → idempotent ingest → SKIP LOCKED worker
HMAC-verify inbound webhooks, store each event once on (provider, externalId), and process work in a Postgres FOR UPDATE SKIP LOCKED worker with pluggable handlers.
Value
Problem. Every SaaS eventually receives provider webhooks. Retries re-deliver the same event; naive handlers double-charge, double-email, or race across workers.
How it helps. HMAC-verify inbound webhooks, store each event once on (provider, externalId), and process work in a Postgres FOR UPDATE SKIP LOCKED worker with pluggable handlers.
Why buy. Own a readable Node/TS/Postgres webhook spine instead of bolting Redis queues or rewriting signature + dedupe glue again.
- Timing-safe HMAC-SHA256 (X-HookQueue-Signature: sha256=<hex>)
- Idempotent ingest via unique (provider, externalId) — duplicates do not re-enqueue
- SKIP LOCKED worker with pluggable per-provider handlers
How it works
flowchart LR
Provider[Webhook Provider] -->|POST /webhooks/:provider| API[Express API]
API -->|HMAC verify| API
API -->|unique provider+externalId| DB[(PostgreSQL)]
Worker[Worker SKIP LOCKED] -->|claim pending| DB
Worker -->|handler| Handler[Pluggable Handler]
Handler -->|done / failed| DB
Mermaid flowchart (render in GitHub / VS Code / mermaid.live).
Use case
Stripe invoice.paid (or GitHub push) hits your API; HookQueue verifies the signature, stores the event once, and a worker marks it done after your handler runs — retries return duplicate without a second enqueue.
What you get
- Express API + worker entrypoints
- Prisma schema + migrations (WebhookEvent)
- docker-compose.yml (Postgres 16)
- Vitest unit tests (HMAC, ingest dedupe, claim/process)
- scripts/sign-webhook.mjs
- MIT license + README with Mermaid architecture
Project structure
hookqueue/
src/
app.ts, index.ts
lib/ config, hmac, logger, prisma
routes/ health, webhooks
services/ ingest, handlers
worker/ claim, process, index
prisma/ schema + migrations
tests/ hmac, ingest, claim, process, config
scripts/ sign-webhook.mjs
docker-compose.yml
Quick start
docker compose up -d
cp .env.example .env # set WEBHOOK_SECRET
npm install && npm run prisma:generate && npm run prisma:migrate
npm run dev
npm run worker
Example
From src/lib/hmac.ts
import { createHmac, timingSafeEqual } from "node:crypto";
export function signPayload(rawBody: string | Buffer, secret: string): string {
return createHmac("sha256", secret).update(rawBody).digest("hex");
}
// Header: X-HookQueue-Signature: sha256=<hex>
// Verify with timingSafeEqual against the raw request body.
Tested
22 Vitest tests across 5 files — HMAC sign/verify, Zod + idempotent ingest (P2002 → duplicate), claim exclusivity, process done/failed.
npm test
2026-09-20 — 22 passed; npm run build OK
Design decisions
- Postgres-native dedupe + SKIP LOCKED instead of Redis so one database serves the SaaS spine
- Raw-body HMAC with timingSafeEqual; header format documented for providers
- Handlers registered per provider so ingest stays stable while business logic forks
Limitations
- Not a full message bus or managed webhook platform
- Unit tests mock Prisma — full multi-worker integration needs your Postgres
- Provider adapters (Stripe/Mailgun/GitHub) are stubs you customize
- Does not claim broker-grade exactly-once delivery; dedupe is at ingest + SKIP LOCKED claim
Who it’s for
Indie SaaS founders and backend engineers who need reliable Stripe/GitHub/custom webhook ingest on Node + Postgres.
Not for: Teams that need a hosted webhook SaaS, Redis-first queues with dashboards, or non-Postgres stacks.
What you own
Full MIT-licensed TypeScript source via Gumroad ZIP. Fork it, ship it commercially, keep the license notice. You are responsible for secrets, hardening, and production ops.
Related
TenantScope · CronLock · IdemKey · RateGuard
Demo