The open-source CLI for HookSwing
Forward webhooks to localhost without ngrok. Replay payloads on demand. No tunnels. No config files.
| ngrok | HookSwing CLI | |
|---|---|---|
| Setup | Download, auth token, config file | npm install -g hookswing-cli |
| Connection | TCP tunnel (breaks on sleep) | WebSocket (survives sleep/wake) |
| History | None | Full feed in your dashboard |
| Replay | Manual curl | Built-in hookswing replay |
| Team sharing | Paste URLs in Slack | One project, whole team sees everything |
| Path preservation | ✗ | ✓ — routes preserved (/api/webhook stays intact) |
| Webhook tester | ✗ | ✓ — send realistic payloads from 16+ providers |
| URL shorthand | ✗ | ✓ — type 3000 → http://localhost:3000 automatically |
| GitHub login | ✗ | ✓ — one-click OAuth, no typing |
- No tunnels — Uses WebSockets, not TCP tunnels. Your laptop can sleep and wake up without breaking the connection.
- Zero config — One command, no YAML files, no port forwarding.
- Replay built-in — Re-send any past webhook from the terminal.
- Webhook tester — Send realistic test payloads from Stripe, GitHub, Shopify, and 13+ more providers to any URL.
- Path preservation — Webhooks sent to
/hook/abc123/api/webhookforward tohttp://localhost:3000/api/webhookautomatically. - URL shorthand — Type just the port (
3000),localhost:3000, or the full URL. Any port works. - GitHub OAuth — Log in with
--githuband skip typing credentials entirely. - Open source & free — MIT-licensed. Free forever.
npm install -g hookswingRequires Node.js 16 or higher.
# 1. Authenticate with your HookSwing account
hookswing login
# Or log in via GitHub (opens browser automatically)
hookswing login --github
# 2. Forward webhooks from your project to localhost
# Just type the port — any port works (3000, 8080, 1337, etc.)
hookswing forward abc123 3000
# 3. List your projects
hookswing list
# 4. Send a test payload (port shorthand works here too)
hookswing test stripe invoice.payment_succeeded 3000
# 5. Replay a webhook (Pro/Team plans)
hookswing replay wh_123abc 3000You can also use your custom slug instead of the random string:
hookswing forward my-company 3000Interactive login. Stores your API token in ~/.hookswing/config.json.
hookswing login
# ? Email: dev@example.com
# ? Password: ********
# ✓ Authenticated as dev@example.comLog in with GitHub OAuth (no password typing):
hookswing login --github
# → Opens browser to GitHub authorization
# → Returns to terminal automatically
# ✓ Authenticated as githubuserThe --github flag starts a temporary local callback server on a random port. Your browser redirects back to the CLI automatically after GitHub authorization — no copy-paste needed.
Removes stored credentials.
hookswing logout
# ✓ Logged out. Credentials removed.Forwards webhooks from your HookSwing project to a local server.
# Port shorthand — 3000 becomes http://localhost:3000
hookswing forward abc123 3000
# Or localhost:port
hookswing forward abc123 localhost:3000
# Or the full URL
hookswing forward abc123 http://localhost:3000URL shorthand: Type just the port number (3000), localhost:3000, 127.0.0.1:3000, or the full URL. Any port works — 8080, 1337, 9999, etc. The CLI automatically prepends http:// when needed.
Path preservation: If a webhook is sent to /hook/abc123/api/webhook, it forwards to http://localhost:3000/api/webhook automatically. The original path after the slug is preserved.
How it works:
- Opens a WebSocket connection to HookSwing
- Subscribes to your project's slug
- When a webhook hits your public URL, the server pushes it via WebSocket
- The CLI forwards the HTTP request to your local server (with original path intact)
- Prints colored status code, response time, and payload size
- Auto-refreshes auth tokens when they expire (no manual re-login)
Output:
🪝 HookSwing Forwarder
Target: http://localhost:3000 Project: My SaaS (abc123)
Session: 00:12:34 | Requests: 8 / 100 ████████░░
[Press Ctrl+C to stop]
[03:17:42] POST /api/stripe/webhook 200 (stripe:charge.succeeded) [03:18:15] POST /api/paypal/webhook 200 (paypal:PAYMENT.CAPTURE.COMPLETED) [03:20:01] GET /health 200 (custom) [03:21:09] PUT /api/users/42 204 (github:pull_request.opened)
Requests: 4 │ Success: 3 │ Failed: 1
**Method colors:**
- `GET` — Sky blue
- `POST` — Emerald green
- `PUT` — Amber
- `PATCH` — Purple
- `DELETE` — Red
**Status code colors:**
- `2xx` — Green
- `3xx` — Purple
- `4xx` — Amber
- `5xx` — Red
**Flags:**
| Flag | Alias | Description |
|------|-------|-------------|
| `--verbose` | `-v` | Print full JSON body for every webhook |
| `--no-color` | | Disable colored output |
| `--quiet` | `-q` | Only print errors |
### `list`
Lists your HookSwing projects.
```bash
hookswing list
# Your Projects:
# abc123 My SaaS 12 webhooks today
# def456 Telegram Bot 3 webhooks today
Replays a past webhook against a local URL. Requires Pro or Team plan.
# Port shorthand works here too
hookswing replay wh_123abc456 3000
# ↻ Replaying webhook wh_123abc456
# Original: 2026-05-05 03:17:42
# POST http://localhost:3000/webhook
#
# Response: 200 OK in 34ms
# Body: {"status": "processed"}Send a realistic test payload from a well-known provider to any URL. Great for testing your webhook handler without setting up the actual integration.
# Port shorthand — test against localhost easily
hookswing test stripe invoice.payment_succeeded 3000
# → 200 OK in 245ms — source: stripe (normalized from "3000")
hookswing test github push localhost:3000/webhook
# → 200 OK in 12ms — source: github
hookswing test shopify orders/create https://your-app.com/webhook
# → 201 Created in 89ms — source: shopifySupported providers: stripe, github, paypal, shopify, twilio, slack, discord, microsoft_teams, sendgrid, mailgun, zoom, calendly, typeform, google, square, generic
The CLI stores a single config file at:
~/.hookswing/config.json
Example:
{
"apiUrl": "https://hookswing.com",
"accessToken": "eyJhbGciOiJIUzI1NiIs...",
"refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}| Variable | Description |
|---|---|
HOOKSWING_API_URL |
Override the default API URL |
NO_COLOR |
Disable colored output |
Don't want to install Node.js? Use the Web CLI built into your dashboard at https://hookswing.com/dashboard/cli. Same commands, zero setup.
hookswing logout
hookswing loginMake sure your email is verified. If you changed your password, re-login.
If using GitHub OAuth and the callback hangs, try again or use email/password login instead.
Your local server isn't running on the specified URL:
# Verify
curl http://localhost:3000
# If using Docker, use host.docker.internal instead of localhost
hookswing forward abc123 http://host.docker.internal:3000
# Port shorthand also works with Docker
hookswing forward abc123 host.docker.internal:3000- Check that the slug is correct:
hookswing list - Test with curl directly:
curl -X POST https://hookswing.com/hook/YOUR_SLUG/api/test -d '{"test": true}' - Check your project usage in the web dashboard — you may have hit your plan limit.
The CLI automatically refreshes your token using the refresh token. No action needed — you'll see a brief Re-authenticating... message and the connection continues.
┌──────────────┐ WebSocket ┌─────────────────┐
│ Your Local │ ◄────────────────► │ HookSwing │
│ Server │ (persistent) │ API Server │
└──────────────┘ └─────────────────┘
▲ ▲
│ HTTP forward │
│ (path preserved) │
│ │
└──────────────────────────────────────┘
Any webhook sender
(Stripe, GitHub, etc.)
Unlike ngrok, which opens a public TCP tunnel to your machine, HookSwing CLI uses a WebSocket connection to the API server. Webhooks hit the public URL, the server stores them, and pushes them to your CLI over the WebSocket. The CLI then makes a local HTTP request to your dev server, preserving the original path. This means:
- No public ports exposed on your machine
- Connection survives laptop sleep/wake
- No "tunnel expired" messages
- Original request paths forwarded exactly as sent
- URL shorthand — Type just the port number (
3000) orlocalhost:3000and the CLI auto-expands it tohttp://localhost:3000. Works withforward,replay, andtestcommands. Any port works.
- Webhook tester —
hookswing testsends realistic payloads from 16+ providers (Stripe, GitHub, Shopify, Twilio, Slack, Discord, etc.) to any URL - Source identification — Provider headers are recognized so CLI/Web CLI show
stripe,github, etc. instead ofcustom
- GitHub OAuth login —
hookswing login --githubopens browser automatically, no copy-paste needed - Auto token refresh — Connection stays alive when access tokens expire (uses 30-day refresh token)
- Path preservation — Webhooks sent to sub-paths like
/hook/abc123/api/webhookforward correctly - Visual enhancements — ASCII logo, colored method/status output, aligned columns, session timer, live usage bar
- Custom slug support in
forwardcommand - Improved header sanitization for signature verification
- Better error messages for auth failures
- Initial release
login,logout,forward,list,replaycommands- WebSocket-based forwarding
- Colored terminal output
Issues and PRs welcome! This CLI is open source.
- Fork the repository
- Create your feature branch:
git checkout -b feature/amazing-feature - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
Built by the team at HookSwing. Part of Nuyvo LLC.
MIT © HookSwing