Skip to content

docs: add webhooks guide and event catalog - #165

Draft
Bccorb wants to merge 2 commits into
mainfrom
docs/webhooks-guide
Draft

Bccorb wants to merge 2 commits into
mainfrom
docs/webhooks-guide

Conversation

@Bccorb

@Bccorb Bccorb commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor

Closes #153. Adds build/webhooks.mdx, a guide and event catalog for receiving Seamless Auth webhooks.

Merge with the auth API v0.23.0 release, not before. Every route on the page needs API v0.23.0, which is held (fells-code/seamless-auth-api#566). The page opens with a caution saying so, and its versions table marks the server adapter helpers (fells-code/seamless-auth-server#279), the console page (fells-code/seamless-auth-admin-dashboard#343) and the CLI commands (fells-code/seamless-cli#359) as unreleased.

First of three stacked PRs: this one, then #166 (login hooks and custom claims, based on this branch), then #167 (SIEM streaming, based on that one). Each adds the cross-links to the pages before it, so every PR's links resolve on its own.

What it covers

  • Delivery model: built from the committed audit log past a cursor, no history replayed on first run, at least once, unordered, 2xx within 15 seconds, and what is not guaranteed (order, exactly once, events while an endpoint is disabled, the same webhook-id across two endpoints).
  • Envelope and catalog: every event type with its payload schema, from WebhookEventSchema in @seamless-auth/types 0.39.0 and webhookCatalog.ts, and an example of each. The examples were produced by running the API's webhookEventFor over sample audit rows and parsing each with WebhookEventSchema.
  • Setup: CALLOUT_SECRET_ENCRYPTION_KEY and CALLOUT_PRIVATE_HOSTS, the URL rules, and the console, CLI and admin API (route table and a curl example).
  • Verification: the rules, requireWebhook (Express), seamlessWebhook (Fastify), createWebhookHandler and verifyWebhookRequest (Next.js), verifyWebhook, and hand-written verifiers for Go, Python and Rust with handler examples, plus a published test vector.
  • Operations: idempotency on webhook-id, the exact retry schedule with jitter and Retry-After, the 410 and three day disable rules (deliveries held while off and released on re-enable, back 30 days), dead letters with the coarse failure reasons, redelivery, and rotation with two signatures for 24 hours.

How the snippets were proven

  • Test vector: two random 32-byte secrets and a user.signed_in body shaped by the schema, signed with openssl dgst -sha256 -mac HMAC (independent of every verifier). The same method reproduces the Standard Webhooks specification's example signature. The auth API's own signedCalloutHeaders (on feat/oidc-provider-claims) produced the identical two-signature header.
  • Go (go test, Go 1.27.1), Python (3.13.14) and Rust (cargo test, hmac 0.12.1, sha2 0.10.9, base64 0.22.1): each verifier on the page passes the vector with either secret alone and both, at +300 s and -300 s, and the specification example; and refuses a changed body, a wrong secret, a v1a-only header, +301 s, -301 s and a missing header. The Go handler and the Axum 0.8.9 handler compile.
  • Not run: the Express, Fastify and Next.js snippets. They come from the READMEs of seamless-auth-server#279, whose own tests cover them, and the packages are not published.

For review

  • Versions of the Node helpers: the table says "the next minor after" the current versions, since #279 carries a minor changeset for all four packages but the exact numbers depend on what else lands first.
  • Events while disabled: described as built in seamless-auth-api#580 (ba740fc, ADR 0005 E4): a disabled endpoint's deliveries are queued on hold, deliveries queued before it was disabled are held the same way, and turning it back on releases everything held within the 30 days deliveries are kept, whether an admin or the API (410, three days failing) turned it off. A dead delivery stays dead and redeliver sends it.
  • Two endpoints, one system: each endpoint's delivery of an event has its own webhook-id, so the page tells readers to subscribe one endpoint per system. Exposing a shared event id would be an API change.

Testing

  • npm run typecheck: 0 errors, 0 warnings, 0 hints.
  • npm run lint: exit 0.
  • npm run build: 75 pages built (re-run after the catch-up update in 281e419). The pre-commit hook ran the build again.
  • A script confirmed every internal link and anchor in the page resolves in dist. The page is in dist/llms.txt and the sitemap.
  • Not run: npm run check:matrix, and nothing against a live API (none can be until v0.23.0).

Covers how delivery works (from the committed audit log, at least once,
unordered), the envelope and every event type with its payload schema
and an example, setup through the console, CLI and admin API, signature
verification with verifyWebhook in Express, Fastify and Next.js and by
hand in Go, Python and Rust with a test vector, idempotency, the retry
schedule, the 410 and three day disable rules, dead letters, redelivery
and secret rotation.

Closes #153
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs: webhooks guide and event catalog

1 participant