Webhook Relay and Forwarding: Proxy One Webhook to Several Destinations

A webhook relay, or webhook proxy, receives each delivery at one public URL and forwards a copy to one or more destinations, such as production, staging or localhost. Solo on webhooks.sh forwards to up to 3 HTTPS URLs for $12 a month; Hookdeck and provider CLIs cover other cases.

A webhook relay (also called a webhook proxy or forwarder) is a public URL you register with the sender that receives each delivery and passes a copy on to one or more destinations, so one event can reach production, staging, and a laptop on localhost. Because the relay answers the sender itself, it changes who handles retries and how signatures are checked. This guide covers both of those pieces and compares the tools you can use.

What a webhook relay does

  • It handles webhook fan out, sending a single incoming event to several services or environments at once.
  • You can get live webhooks on localhost while the public URL stays on the relay.
  • You can swap out destination URLs whenever you want without touching the sender's settings.
  • It keeps a copy of every request so you can inspect or replay it later.

There is a trade-off to putting a relay in the middle. The sender only sees the relay's HTTP reply, not your server's response, which means a failure at your destination won't trigger the sender's built-in retry logic, and the relay has to retry for you instead. The relay also sees every payload that passes through it, so pick one you trust with that data.

Webhook forwarding tools compared

The right tool depends on whether you need copies in several places or just events on your own machine.

Provider CLIs only carry their own provider's events, while a relay URL works with any sender.

ToolForwards toWorks withNotes
webhooks.sh SoloUp to 3 verified HTTPS URLs; localhost with wsh listenAny senderUp to 3 attempts within an hour; $12 a month
HookdeckEvery connection on a source; localhost with hookdeck listenAny senderUp to 50 automatic retries; free up to 10,000 events, Team from $39 a month
Stripe CLIA local URL with stripe listen --forward-toStripe eventsSigning secret stays the same between restarts
GitHub CLIA URL with gh webhook forwardRepository and organization webhooksTesting and development only
smee.ioYour local app with smee-clientAny senderBuilt for local development

Fan out one webhook to several destinations

  1. Register the relay URL once in the webhook sender's settings.
  2. The relay stores each incoming request and sends an independent copy to each of your configured destinations.
  3. Each destination succeeds or fails on its own, so a down staging server doesn't block production from getting the event.

On Solo, a named endpoint on webhooks.host forwards every request to up to 3 verified HTTPS URLs while keeping the original method, body, and headers, and failed sends get up to 3 attempts within an hour. Hookdeck works by routing a copy of the incoming request over every connection attached to a source, and it allows up to 50 automatic retries. If you need more than 3 destinations or retries that run past an hour, a gateway like Hookdeck or your own queue is the better fit.

Signatures on forwarded webhooks

When you forward webhooks, there are two signature layers to think about: the original provider's signature and the relay's signature. A good relay forwards the body byte for byte along with the original headers, as Solo does, so a GitHub or Shopify signature (which covers only the body) still verifies cleanly at your destination. Signatures that bake a timestamp into the payload are different, because Stripe's libraries allow 5 minutes by default, and Slack's and Svix's checks reject timestamps more than five minutes away, so a copy that arrives late after a relay retry can fail the check even though the bytes are identical.

That's where the relay's own signature comes in. Solo adds an X-Webhooks-Signature header you can check, and Hookdeck adds x-hookdeck-signature (plus x-hookdeck-signature-2 while a previous secret is still active), which proves the copy came from your relay. Check both: the relay's signature shows the copy came through your relay, and the provider's signature shows the event came from the provider. If a late copy fails only the provider's timestamp check, fetch the current state from the provider's API instead of trusting the copy; see our webhook security guide for the details.

Relay webhooks to localhost with the wsh CLI

On Solo, the wsh CLI connects your machine to a named endpoint to forward webhooks to localhost live as deliveries arrive, and it can also replay captured requests to your local server later on. The sender gets its 200 reply straight from webhooks.sh rather than your local server's response, so the CLI is built for developing your handler, not for testing how the sender reacts to your replies (see our guide to testing webhooks locally).

Before paying for anything, you can spin up a free bin to see what the sender posts: no signup, live in the browser, kept for 48 hours with up to 100 requests a day, and you can claim it with a free Google sign-in to keep the URL and get 30-day rolling history. Just keep in mind that free bins capture and display only. They don't forward requests, and a free URL on webhooks.page doesn't carry over to a Solo endpoint on webhooks.host.

npm install -g https://webhooks.sh/cli/wsh.tgz
wsh auth login
wsh listen <endpoint> --to localhost:3000

Provider CLIs for single-provider forwarding

If you only need one provider's events on your laptop, its own CLI may be enough. For Stripe, stripe listen --forward-to forwards events to a local URL and prints a signing secret that stays the same between restarts, with no Dashboard endpoint needed.

GitHub has gh webhook forward for repository and organization webhooks, though GitHub notes it's only meant for testing and development, not production. And if you already use Hookdeck, the Hookdeck CLI (hookdeck listen) forwards a Hookdeck source straight to a local port.

stripe listen --forward-to localhost:3000/webhooks
gh webhook forward --repo=<owner>/<repo> --events=push \
  --url=http://localhost:3000/webhooks
hookdeck listen 3000 <source>

FAQ

What is a webhook relay?

A webhook relay is a public URL that receives webhook deliveries and forwards copies to other destinations like your production server, staging, or localhost. The sender only ever knows the relay URL.

Is a webhook proxy the same as a webhook relay?

In practice, yes; both receive webhooks at a public URL and pass the requests on to your endpoints. Forwarder is just a third name for the same idea.

How do I forward a webhook to multiple URLs?

Put a relay with fan-out in front of your endpoints. Solo on webhooks.sh forwards each request to up to 3 verified HTTPS URLs, while Hookdeck sends a copy over every connection attached to a source.

Does forwarding a webhook break the signature?

Not if the relay forwards the body byte for byte with its original headers. However, timestamped signatures like Stripe's and Slack's can fail verification when a retry copy arrives more than 5 minutes after the original send.

How do I forward webhooks to localhost without ngrok?

You can use wsh listen on Solo, stripe listen --forward-to for Stripe, gh webhook forward for GitHub, the Hookdeck CLI, or smee-client from smee.io.

Can a free webhooks.sh bin forward webhooks?

No, free bins only capture and show requests, for 48 hours or 30 days rolling once claimed. Webhook forwarding and the wsh CLI are part of the Solo plan at $12 a month.

What happens if the forwarding destination is down?

Because the relay already answered the sender, the relay handles retries itself. Solo makes up to 3 attempts within an hour, and Hookdeck runs up to 50 automatic retries.

Last updated

Try it in 10 seconds.

Create a free bin at view.webhooks.page — no signup, no install. Point your sender at the URL and watch requests land live. Bins expire after 48 hours.