Receive a webhook once. Send it everywhere.

A unique subdomain captures the exact request a provider sends, answers 202 immediately, then fans it out to every URL you register — with retries, full response capture and one-click replay.

Quick start
█   █ ████ ███  █  █  ██   ██  █  █
█   █ █    █  █ █  █ █  █ █  █ █ █
█ █ █ ███  ███  ████ █  █ █  █ ██
██ ██ █    █  █ █  █ █  █ █  █ █ █
█   █ ████ ███  █  █  ██   ██  █  █
████  ██  █  █  ██  █  █ ████
█    █  █ ██ █ █  █ █  █   █
███  ████ █ ██ █  █ █  █   █
█    █  █ █  █ █  █ █  █   █
█    █  █ █  █  ██   ██    █
  POST /  ─┐
           │   ┌──────────────────┐      ┌─ https://staging.api/hooks   [ok]  200
  stripe ──┼──▶│  abc.webhook-    │──┬──▶├─ https://team.ngrok.io/in    [ok]  204
           │   │  fanout.com      │  │   └─ https://old.internal/hook   [x]   500 ×4
  github ──┘   └──────────────────┘  │
                  202 Accepted       └─ every byte, header and query preserved
curl -X POST https://abc.webhook-fanout.com -d '{"hi":1}' → 202
3 retries per endpoint · exact bytes stored · replay any request

Quick start

1. Mint a token (this is your only credential)
curl -X POST 'https://webhook-fanout.com/api/tokens'
2. Create a webhook
curl -X POST 'https://webhook-fanout.com/api/v1/webhooks' \
  -H "Authorization: Bearer $WHF_TOKEN" \
  -H 'content-type: application/json' \
  -d '{"name":"stripe-test"}'
3. Register where it should fan out to
curl -X POST 'https://webhook-fanout.com/api/v1/webhooks/$WEBHOOK_ID/endpoints' \
  -H "Authorization: Bearer $WHF_TOKEN" \
  -H 'content-type: application/json' \
  -d '{"url":"https://staging.example.com/hooks"}'
4. Send something at it
curl -X POST 'https://<slug>.webhook-fanout.com' -d '{"hello":"world"}'
1. Install
curl -fsSL https://webhook-fanout.com/install | sh          # macOS / Linux
irm https://webhook-fanout.com/install.ps1 | iex             # Windows
2. Sign in with your token
whf login
3. Create a webhook and a target
whf webhooks new --name stripe-test
whf endpoints add <slug> https://staging.example.com/hooks
4. Or deliver straight to this machine
whf listen --webhook <slug> --forward-to http://localhost:3000

Full reference and more examples in the docs.

What it does

[+]Byte-exact capture the raw body is stored untouched, so Stripe-Signature and X-Hub-Signature-256 still verify downstream
[+]Fan-out with retries each endpoint gets its own budget of 3 retries — one dead target never starves the others
[+]Per-endpoint results response status, response body, duration and attempt count for every target
[+]Replay re-send any captured request to all endpoints or just one, after you fix the handler
[+]Deliver to localhost a small client forwards to your own machine — no tunnel, no public port
[+]Inspect and clear full request history per webhook, cleared with one call when it gets noisy
[x]No accounts no email, no password — one bearer token is the API credential and the dashboard login

Deliver to your machine

localhost cannot be an endpoint — this server cannot reach a laptop behind NAT. The whf client connects outbound instead, so nothing of yours is exposed.

macOS / Linux
curl -fsSL https://webhook-fanout.com/install | sh
Windows (PowerShell)
irm https://webhook-fanout.com/install.ps1 | iex
then
whf listen --webhook <slug> --forward-to http://localhost:3000

Good to know

[-]Retries 2xx/3xx succeed · 408, 429, 5xx, timeouts retry · other 4xx stop immediately
[-]Limits 10 MiB request bodies, 7-day retention, first 64 KiB of each endpoint response kept
[-]Your token shown once and never recoverable — losing it means minting a new one