NewWacht Bench is live — AI-assisted development for Wacht
GuidesWebhook Apps

Webhook Apps

Customer-managed event delivery — endpoints, secrets, retries, replay.

A webhook app is the customer-facing control plane for outgoing event delivery. One app per deployment lets your customers register endpoint URLs, subscribe to event names, rotate signing secrets, and inspect and replay deliveries. Use it for integration events (invoice.paid, subscription.updated), workflow callbacks, and partner delivery contracts where the customer needs diagnostics and replay on their own.

There are two halves to keep straight. The management surface — endpoint CRUD, subscriptions, test sends, secret rotation, replay initiation — is what this app exposes to customers. The delivery side — your backend emitting events, Wacht attempting delivery, retrying, and recording status — runs underneath. The split matters because the management UI is yours to build, but the delivery behavior is fixed by Wacht; your customers operate the former and observe the latter.

Provision the app

import { WachtClient } from "@wacht/backend";

const client = new WachtClient({ apiKey: process.env.WACHT_BACKEND_API_KEY! });

await client.webhooks.createWebhookApp({
  name: "Billing Webhooks",
  app_slug: "wh_42",
  description: "Webhook app for deployment 42",
});

Use wh_<deploymentId> for the slug so it's derivable. The app holds the endpoint registry and signing secrets; emitting events and management access both reference it by slug.

How the frontend gets in

Same trust boundary as API Auth — your backend is the policy authority, the browser gets a short-lived app-scoped session. The webhook specifics: the ticket is ticket_type=webhook_app_access with webhook_app_slug set to this app (the request is rejected without the slug), and the session it exchanges into can reach /webhooks/* and the replay endpoints. Run your own RBAC and tenant-ownership check before issuing the ticket — Wacht doesn't decide who's allowed to manage a customer's endpoints. Tickets default to a 12-hour TTL; issue them on demand rather than minting long-lived ones.

Vanity surface or your own UI

Vanity pages give you a hosted management surface you hand the user into with a ticket — endpoint CRUD, test sends, secret rotation, and the delivery/replay screens without building them. Reach for this to ship now or while the workflow is still settling. See vanity pages implementation.

Custom hooks build the same management inside your own product IA when webhook config is a first-class workflow. See custom hook implementation.

Operating deliveries — filtered triage, bounded replay windows, success-rate and latency trends — is its own surface, covered in deliveries, replay, and observability.

What your customers' receivers must do

Two things are on the receiving end, not on Wacht, and both belong in the docs you hand customers:

  • Verify the signature. Every delivery carries a signature from the app's secret. A receiver that skips verification will accept spoofed events. Rotating the secret is a coordinated change — the receiver has to accept both old and new during the window.
  • Process idempotently. Retries and replay both re-deliver events. A receiver that isn't idempotent double-applies on every retry. This is the single most common cause of "the webhook charged me twice" reports.

Before go-live

  • Endpoint create / test / delete / rotate verified end to end on staging.
  • A runbook for failed deliveries and replay exists for whoever is on call.
  • Receiver docs published with signature verification and idempotency spelled out.
  • Alerting on sustained endpoint failure — a customer's endpoint going dark shouldn't surface first as a support ticket.
  • Ticket issuance gated by RBAC and tenant isolation, verified by trying to issue across tenants.
  1. Vanity pages implementation
  2. Custom hook flow implementation
  3. Deliveries, replay, and observability
  4. Backend JS SDK
  5. Backend API reference

On this page