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.
█ █ ████ ███ █ █ ██ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ███ ███ ████ █ █ █ █ ██ ██ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ ████ ███ █ █ ██ ██ █ █ ████ ██ █ █ ██ █ █ ████ █ █ █ ██ █ █ █ █ █ █ ███ ████ █ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ██ █
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