Local development

Updated May 02, 2026

The problem with local webhook development

Your local server isn't reachable from the public internet. The usual workarounds all have friction:

Splithook tunnels solve all three: the endpoint URL is permanent, the CLI connects in seconds, and you receive the exact bytes the provider sent — headers, signature, and all.

How the tunnel works

Provider → splithook.com/e/{slug} → (Mercure channel) → splithook CLI → localhost:3000
  1. The provider POSTs to your Splithook endpoint as normal.
  2. Splithook captures the request and broadcasts it over a private Mercure event stream authenticated by a tunnel token.
  3. The CLI subscribes to that stream, receives the event, and replays it to your local port.
  4. Your handler's response (status, headers, body) is sent back to Splithook via an ACK endpoint and recorded in the ReplayLog.

The connection is outbound-only from the CLI — no port forwarding, no firewall changes.

Install the CLI

# macOS (Homebrew)
brew install splithook/tap/splithook

# Linux — curl installer
curl -fsSL https://splithook.com/install.sh | sh

# Or download the Phar directly
curl -Lo splithook https://splithook.com/cli/latest/splithook.phar
chmod +x splithook && sudo mv splithook /usr/local/bin/

Verify the install:

splithook --version
# splithook 1.0.0 (php 8.4)

Authenticate

splithook auth

This opens a browser window where you log in. The CLI stores a token in ~/.splithook/credentials.json.

You can also authenticate non-interactively using a tunnel token generated from the dashboard (Settings → Tunnel tokens → New):

splithook auth --token sht_xxxxxxxxxxxxxxxx

Start a tunnel

splithook tunnel --endpoint ab3dkf7z --to localhost:3000

Options:

Flag Default Description
--endpoint Your endpoint slug (required)
--to Local address to forward to (required)
--path-prefix (none) Prepend a path to forwarded requests, e.g. /webhooks
--timeout 30s Max wait for local handler response

The CLI prints a status line on each forwarded event:

→  POST  charge.failed     200  142ms
→  POST  customer.created  200   88ms
→  POST  invoice.payment_failed  503  5001ms  [retry scheduled]

Replay to tunnel

You can replay any captured webhook directly to your tunnel from the dashboard inspector. The payload is re-signed if you've configured a signing secret on the destination, so your local HMAC verifier keeps passing.

Multiple developers

Each developer creates their own tunnel destination on the same endpoint. Fan-out ensures everyone receives every webhook simultaneously — no coordination required.

Endpoint ab3dkf7z
  ├── Destination: alice-tunnel  →  alice's laptop:3001
  └── Destination: bob-tunnel    →  bob's laptop:3002

Add a filter (event_type == 'payment_intent.succeeded') to each destination if you only care about specific events.