Welcome
A polyglot library for sending and receiving webhooks reliably and securely. It does two halves — inbound and outbound — and you can use either alone.
Sending and receiving webhooks is easy. Doing it reliably and securely is hard — retries, replay, signature verification, key rotation, idempotency, raw-bytes preservation. That's where Postel comes in: a polyglot library that handles those for you. It runs inside your application against your existing relational database (Postgres, MySQL, SQLite, …) — no Redis, no broker, no separate dispatcher process.
Svix is for when webhooks are your product. Postel is for when webhooks are a feature of your product.
Two halves, one library
Postel has two independent halves. Use either alone, or both together.
| Half | What it does | Status |
|---|---|---|
| Inbound | Verify Standard Webhooks-signed requests other services send to you. Constant-time signature checks, multi-secret rotation windows, JWKS, idempotent dedup, raw-bytes preservation. | Available in @postel/core. |
| Outbound | Deliver Standard Webhooks to your customers' endpoints. Transactional outbox, retries, replay, fanout, key rotation, JWKS publication, circuit breaker, dead-letter. | Available in @postel/core, with durable Postgres, MySQL, and SQLite storage adapters. |
The Postel({ inbound, outbound }) factory composes both — but everywhere else in these docs they're separated. You shouldn't have to wade through outbound material to integrate the receiver, or vice versa.
Picking a starting point
Is Postel for me?
A six-line decision gate. Run it before you read more.
Quickstart
60 seconds — verify your first signed webhook with @postel/core.
Why Postel
The tradeoffs; comparison vs Svix, comparison vs hand-rolled.
Polyglot
For port authors — what conformance means and where the suite lives.
Where the project stands
Both halves are implemented and exercised end-to-end by the @postel/compliance suite. The receiver verifies any Standard Webhooks producer. The sender runs the transactional outbox, retries, replay, fanout, and signing against durable Postgres, MySQL, and SQLite adapters — or the in-process InMemoryStorage for tests and demos.
What's still ahead is tracked honestly, not hidden:
- No release is cut yet. Every
@postel/*package sits at0.0.0with no git tag, so nothing is on npm. Clone the repo to use it today; pin to a minor once releases ship. - Unwired config slots fail fast instead of lying. External job-queue workers (BullMQ, PgBoss), KMS-backed keys (
AwsKms/GcpKms/Vault), retention, ephemeral keys, and thehttp.tls/http.dnsknobs aren't wired yet — configuring any of them throwsNotImplementedErrorrather than silently no-opping.observability.loggeris wired and receives delivery / circuit events; full OpenTelemetry + Prometheus is deferred. Outbound marks each one. - Other languages are on the way. Go, Python, and Rust are on the roadmap; TypeScript ships first.
This site is the public surface of that work. If a page describes behavior the source doesn't have, open an issue.