Skip to content
Start free
Start free

Webhooker CLI: forward webhooks to localhost

whk is the official command-line client for Webhooker. Most people install it to get webhooks onto their laptop: whk listen takes each webhook that reaches your ingest URL and replays it against http://localhost:3000, or any local URL, with the original method, headers and body. The CLI connects out to Webhooker, so nothing on your machine is exposed and you don’t need ngrok or another tunnel.

It also manages the workspace. Sources, destinations, connections, the event log, replays, the dead-letter queue and delivery stats all have commands, so the things you would click through in the dashboard also work in a shell script or a CI job. Add --json and you get the raw API response.

Run whk with no arguments and it opens an interactive terminal UI instead.

whk is a single static binary written in Rust, published under the MIT license at github.com/webhooker-eu/webhooker-cli. You need a Webhooker account and an API key to use it.

The same one-line install, with a copy button for each platform, is on the Webhooker CLI page on webhooker.eu.

On Linux and macOS:

Terminal window
curl -fsSL https://webhooker.eu/install.sh | sh

On Windows, in PowerShell:

Terminal window
irm https://webhooker.eu/install.ps1 | iex

The script picks the build for your OS and CPU, checks it against the SHA-256 checksum published with the release and puts whk in ~/.local/bin (%LOCALAPPDATA%\Programs\whk on Windows). It needs no root. To pin a release or choose the directory:

Terminal window
curl -fsSL https://webhooker.eu/install.sh | sh -s -- --version v0.1.1 --dir /usr/local/bin

In PowerShell, set $env:WHK_VERSION or $env:WHK_INSTALL_DIR before running it.

Or download the archive for your platform from the releases page, unpack it and put whk on your PATH:

Terminal window
tar -xzf whk-x86_64-unknown-linux-musl.tar.gz
sudo mv whk /usr/local/bin/
whk --version
PlatformArchive
Linux x86_64whk-x86_64-unknown-linux-musl
Linux ARM64whk-aarch64-unknown-linux-musl
macOS Intelwhk-x86_64-apple-darwin
macOS Apple Siliconwhk-aarch64-apple-darwin
Windows x86_64whk-x86_64-pc-windows-msvc

The Linux builds are statically linked against musl. They run on any distribution, Alpine included, with nothing else to install.

With a recent stable Rust toolchain:

Terminal window
cargo install --git https://github.com/webhooker-eu/webhooker-cli

Create an API key in the dashboard, then run:

Terminal window
whk login

The key is read without echo, checked against the API and saved to your user config directory. whk whoami prints the workspace the key belongs to, which is the quickest way to confirm it works.

Terminal running whk login, then whk whoami showing the Acme workspace on the pro planTerminal running whk login, then whk whoami showing the Acme workspace on the pro plan
whk login saves the key; whk whoami shows which workspace it acts in.

A key belongs to exactly one workspace. To switch workspaces, log in again with a key from the other one. whk logout deletes the saved file.

Four commands take you from nothing to a webhook hitting your local handler.

Pass --verify stripe, github or shopify to check signatures on arrival. You will be asked for the signing secret.

Terminal window
whk sources create stripe-test --verify stripe

whk sources url prints only the URL, so it pipes cleanly into other commands:

Terminal window
whk sources url stripe-test
Terminal running whk sources ls with four sources and their ingest URLs, then whk sources urlTerminal running whk sources ls with four sources and their ingest URLs, then whk sources url
whk sources ls lists every source with its event count and ingest URL.
Terminal window
whk listen stripe-test --forward http://localhost:3000/webhooks/stripe

Trigger one from the provider’s dashboard, or post to the ingest URL yourself:

Terminal window
curl -X POST "$(whk sources url stripe-test)" \
-H 'Content-Type: application/json' -d '{"hello": "world"}'

Each event shows up in the listen output with your handler’s status code and response time:

Terminal running whk listen forwarding three Stripe events to localhost:3000, each answered with 200Terminal running whk listen forwarding three Stripe events to localhost:3000, each answered with 200
whk listen replays each webhook against your local URL and prints how your handler answered.

The Test webhooks locally tutorial walks through the same flow with test-mode and production setups side by side.

whk login writes the server and the API key to a TOML file:

OSPath
Linux~/.config/webhooker/config.toml
macOS~/Library/Application Support/webhooker/config.toml
Windows%APPDATA%\webhooker\config.toml

On Unix the file is created with mode 0600, readable only by your user.

Flags and environment variables take precedence over the saved file:

FlagVariableEffect
--api-keyWEBHOOKER_API_KEYAPI key, whk_....
--serverWEBHOOKER_SERVERAPI base URL. Defaults to https://app.webhooker.eu.
--jsonPrint the API’s JSON response instead of a table.

--verify and --auth hmac ask for a signing secret. On a terminal the prompt hides what you type. Without one, whk reads the secret from WHK_SECRET or from the first line of stdin, so it never hangs waiting for input in a script.

In a pipeline, set the key from your secret store and skip whk login:

Terminal window
export WEBHOOKER_API_KEY="$WEBHOOKER_API_KEY_FROM_SECRETS"
whk events replay-bulk --connection "$CONNECTION_ID" --since "$OUTAGE_START"

Add --json when a script reads the output. jq handles the rest:

Terminal window
whk sources ls --json | jq -r '.items[] | "\(.name) \(.event_count)"'
  • An API key has full access to its workspace. Keep it in a secret store or the saved config, not in scripts or shell history. whk login prompts without echo for this reason.
  • whk listen only opens outbound connections: one to Webhooker and one to the URL you pass to --forward. It never listens on a port.
  • Revoke keys you no longer use. The API keys page shows when each key was last used.

How do I receive webhooks on localhost without ngrok?

Section titled “How do I receive webhooks on localhost without ngrok?”

Create a Webhooker source, give its ingest URL to the provider, and run whk listen <source> --forward http://localhost:3000/your/path. The provider sends to Webhooker’s public URL, and whk replays each request against your local URL over an outbound connection. No port is opened on your machine and no tunnel is involved. For a comparison with the tunnel tools, see ngrok alternatives for webhooks.

Will my handler’s signature check pass on a forwarded webhook?

Section titled “Will my handler’s signature check pass on a forwarded webhook?”

Yes. The body is forwarded byte for byte and the provider’s signature headers, such as Stripe-Signature, X-Hub-Signature-256 and X-Shopify-Hmac-Sha256, are passed through unchanged. Only transport headers like Host and Content-Length are recomputed. Stripe signs a timestamp, so a request replayed hours later fails Stripe’s tolerance check; forward live events while you develop.

Do I miss events while whk listen is not running?

Section titled “Do I miss events while whk listen is not running?”

No. Webhooker stores every event whether anyone is listening or not. Find the one you need with whk events ls and replay it with whk events replay, or resend it from the event log in the dashboard.

Yes. Set WEBHOOKER_API_KEY from your CI secret store and skip whk login. Every command accepts --json, so scripts get the raw API response instead of a table.

How do I send signed test webhooks without the provider?

Section titled “How do I send signed test webhooks without the provider?”

The webhook mock sender signs Stripe, GitHub and Shopify payloads with your secret and sends them to any URL, your ingest URL included.