Skip to main content
Glama

slinghook CLI

Forwards webhooks captured by a SlingHook server to a server on your machine, such as localhost:3000. A hosted SlingHook instance can't reach your localhost, so the CLI makes the connection outbound, the same way stripe listen does.

slinghook listen forwarding Stripe webhooks to localhost:3000, retrying a 500

Requires Node 20.17+.

npm install -g slinghook

slinghook auth login --server https://slinghook.co.za
slinghook auth status          # who you're logged in as
slinghook endpoints            # list your endpoint UUIDs
slinghook mcp                  # MCP server for AI agents (see below)
slinghook listen <uuid> --forward http://localhost:3000/webhooks
# <uuid> can also be the catch URL you copied, e.g. https://slinghook.co.za/c/<uuid>

Every command also works with the short name shk, e.g. shk auth login or shk listen <uuid> --forward …. login, status and logout also work without auth, as in earlier versions.

● Listening on endpoint 3f1c…
  Forwarding to http://localhost:3000/webhooks

14:02:11 POST   #1234 → 200 37ms sig:valid
14:02:15 POST   #1235 → ✗ Connection refused (is your local server running?) 2ms

How it works

  1. Auth. slinghook login works like gh auth login. It asks how you want to log in:

    • Web browser. The CLI shows a one-time code (like BCDF-GHJK) and opens the dashboard. Sign in there however you normally do (password, Google, GitHub, SAML, two-factor) and approve the code. The CLI then receives a new API token named after your computer. The token works in the workspace you approved it from. --web skips the question. Codes expire after 15 minutes.

    • Personal access token. Create one under User Settings → API Tokens (/app/?settings=tokens) and paste it. In scripts and CI use slinghook login --with-token < token.txt, --token shk_…, or set SLINGHOOK_TOKEN.

    Only the token is saved, in ~/.config/slinghook/config.json (mode 0600). The server stores only a SHA-256 hash of it. You can see and revoke tokens under User Settings → API Tokens.

  2. Stream. listen opens GET /v1/events/<uuid> with Authorization: Bearer <token>. This is the same SSE stream the dashboard uses. On first connect the server sends recent history, which the CLI skips. It forwards only new log events.

  3. Reconnect. The server closes the stream every ~55s by design. The CLI reconnects with Last-Event-ID, so webhooks that arrive during the gap are delivered once and in order. Network errors back off from 1s up to 30s.

  4. Forward. Each webhook is re-sent with its original method, body, query string, and headers. Hop-by-hop headers such as Host and Content-Length are dropped. Signature headers are kept, so your app's verification runs for real. The CLI adds X-Webhook-Replay: true and X-SlingHook-Log-Id. Deliveries run one at a time with a 15s timeout. Payloads that were truncated at capture are skipped. If your server is down, times out, or answers 408, 425, 429 or 5xx, the CLI retries 3 more times (after 1s, 2s and 4s) before moving on. Later webhooks wait, so they still arrive in order. --retries N changes the count (0 to 10).

  5. Report. Each result is posted to POST /api/logs/<id>/replays, so it appears in the dashboard's replay history. Use --no-report to turn this off.

Related MCP server: Webhook Capture MCP

Team routing: one provider URL, many developers

On the Team plan, a whole team can share one endpoint (Stripe and Shopify only allow a few webhook URLs) and still each get their own events on their own machine. Claim the events that are yours, then listen with --mine:

# Events whose body has metadata.dev = "alice" go to Alice's localhost
slinghook listen <uuid> --forward http://localhost:3000/webhooks \
  --claim data.object.metadata.dev=alice

# Or claim by a header or query parameter
slinghook listen <uuid> --forward http://localhost:3000/webhooks --claim header:X-Dev=alice

--claim saves your claim on the endpoint (replacing your earlier one) and implies --mine. Repeat it to require several conditions. You can also edit claims under Endpoint Settings → Team routing in the dashboard, then run listen --mine without --claim.

With --mine, the CLI forwards only the events routed to you, and the open stream counts you as online. Events nobody claims stay in the shared feed for everyone to see, unless the endpoint is set to give them to whoever is online, in which case they go round-robin to the people running listen --mine. Viewers can watch but can't claim events.

Don't run the CLI and the dashboard's Auto-Relay toggle for the same endpoint at the same time, or each webhook will be delivered twice.

Chaos mode: is your handler idempotent?

On Pro and Team, slinghook chaos takes a saved scenario (or one captured request) and sends it to your handler the way providers really behave:

slinghook chaos <uuid> --forward http://localhost:3000/webhooks --scenario 12 \
  --check http://localhost:3000/debug/orders/count

Each event is first sent once (the baseline). Then, in order:

Test

What is sent

Pass

duplicates

every event again

2xx

concurrent

the same event 3 times at the same moment

2xx for all

out_of_order

the events again, newest first

2xx, or 409/425/429/503 to ask for a retry

malformed

the first body cut in half, empty, and garbage

4xx

late_retry

the first event again after --late-delay seconds

2xx

Deliveries are sent exactly as captured, signature included, without the X-Webhook-Replay header, so your handler treats them like the provider's own redeliveries. Status codes can't show double side effects, so pass --check with a GET on your app that reflects its state (an order count, a balance). It is read after the baseline and after each test; any change fails that test.

Pick tests with --only duplicates,concurrent. Run without --scenario to list the endpoint's scenarios. The report is saved to the dashboard (⌘K → "Chaos mode"), and the command exits with code 1 when a test fails, so it can run in CI.

MCP server: let your AI agent debug webhooks

slinghook mcp is a Model Context Protocol server. AI coding agents such as Claude Code, Cursor and VS Code start it in the background and call SlingHook as a set of tools, logged in as you. Ask your agent "my Stripe webhook is failing, find out why and fix it", and it can run the whole Catch. Debug. Replay loop:

Tool

What it does

Changes anything?

list_endpoints

Your catch URLs and where each one relays

No

list_events

Captured webhooks as short summaries (no bodies). The 50 newest on every plan; query and before_id search full history (Pro)

No

get_event

One webhook in full: headers, query, body (long bodies cut)

No

debug_signature

Why the signature failed, optionally against a candidate secret

No

replay_event

Re-sends the webhook from your machine to your handler, records it, and returns the verdict: fixed, regressed, still failing or still passing

Yes: a real delivery

get_replay_result

Replay history and fix verification verdict (both response bodies on Pro)

No

list_scenarios

Saved scenarios (ordered sets of events) on an endpoint

No

run_scenario

Replays every step of a scenario from your machine to your handler and reports each step (back to back, or recorded gaps capped at 5s with keep_timing; 3 runs a minute)

Yes: real deliveries

generate_handler

Types, a fixture and a test (TypeScript, Python, PHP or Go) from a real event, to build a handler around. Writes no files itself

No

compare_events

What differs between two webhooks, field by field (defaults to the previous event of the same type)

No

create_endpoint

A new catch URL (same name returns the existing one; at most 5 per session; no secrets through the chat)

Yes: adds an endpoint

Every event has a number within your account (#12), shown in the dashboard's feed. Name events to your agent however is natural: "event 12", "the latest event", "the latest invoice.paid", or the provider's own id such as Stripe's evt_1Qx.... The inspector's #12 menu also copies a ready-made prompt.

Add it once, after slinghook login:

# Claude Code (macOS, Linux)
claude mcp add slinghook -- slinghook mcp

# Claude Code on Windows: npm installs slinghook as a .cmd file, which needs cmd /c
claude mcp add slinghook -- cmd /c slinghook mcp

Other clients take the same command in their JSON config:

{ "mcpServers": { "slinghook": { "command": "slinghook", "args": ["mcp"] } } }

In Claude Code, /mcp shows whether it connected. The agent asks before running replay_event, because the tool is marked as one that changes things.

Safety rails:

  • Replays stay local. replay_event only sends to localhost and private networks (10.x, 172.16-31.x, 192.168.x, host.docker.internal). Webhook bodies are written by third parties, and a crafted one could try to talk your agent into sending stored payloads elsewhere. Start the server with slinghook mcp --allow-remote-targets to lift this.

  • Rate limits. One MCP session makes at most 60 tool calls and 10 replays a minute, so a looping agent stops quickly.

  • Your permissions. Every call uses your token, so the server's rules apply: your workspace, your role (viewers can't replay) and your plan.

The server talks JSON-RPC over stdin and stdout, so it prints nothing to stdout itself; its startup note goes to stderr. To see the protocol, pipe a request in:

echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | slinghook mcp

Known gaps

  • Bodies travel through the JSON event stream as text, so binary payloads aren't forwarded byte-for-byte.

  • There are no retries yet. A failed delivery is reported, and you can replay it from the dashboard.

Developing

Clone this repo, then npm install && npm link puts your working copy on your PATH, and npm test runs the tests.

Publishing

Bump version in package.json, then run npm publish from this folder. The tests run first (prepublishOnly), and only bin/, src/, this README, LICENSE and package.json are included in the package.

License

MIT. SlingHook is made by Fulcrum Software, South Africa.

Available Tools

11 tools
compare_eventsCompare eventsA
Read-onlyIdempotent

Shows what differs between two captured webhooks, field by field (JSON paths such as data.items[0].price), plus header differences. Use it for "this one worked and that one failed, what changed?" or to spot a provider changing its payload. Leave out b to compare with the previous event of the same type on the same endpoint. Changes always read from the older event to the newer one. Key order, formatting and per-delivery headers (signatures, request ids, dates) never count.

Inputs: a (required), b, include_headers.

create_endpointCreate endpointA

Creates a new catch URL (endpoint) in the current workspace and returns the URL to paste into the provider's webhook settings. If an endpoint with the same name already exists, returns that one instead of making a copy. Plan limits apply (Free has 3 endpoints). It does not take a signing secret: secrets are added in the dashboard so they never pass through the conversation.

Inputs: name (required), relay_to, signature_scheme.

debug_signatureDebug signatureA
Read-onlyIdempotent

Explains why a webhook's signature verified or failed: detected provider scheme (Stripe, GitHub, Shopify, Slack, Standard Webhooks, Twilio), wrong secret, stale timestamp, or a body that was modified (reformatted JSON, re-escaped slashes). Checks against the secret saved on the endpoint, or against secret to try a candidate without saving it.

Inputs: event_id (required), secret.

generate_handlerGenerate handler codeA
Read-onlyIdempotent

Turns a real captured webhook into code to build a handler around: typed models of its payload, a fixture file with the body, and a test that posts it to the handler. Languages: typescript (types + Jest/Vitest test), python (dataclasses + pytest), php (DTO + Laravel test), go (structs; no test). Returns file contents with suggested names; it writes nothing, so save them with your own file tools. Also says which signature scheme the endpoint checks, so the handler can verify it.

Inputs: event_id (required), language (required), parts, target_url.

get_eventGet eventA
Read-only

Reads one captured webhook in full: method, headers, query string, body and signature status. Long bodies are cut at max_body_chars.

Inputs: event_id (required), max_body_chars.

get_replay_resultGet replay resultA
Read-only

Shows the replay history of one event and the fix verification verdict for the latest replay (or replay_id): fixed, regressed, still_failing or still_passing, compared with the attempt before it to the same URL. Includes replays made from the dashboard and by slinghook listen. On Pro and above it also returns both response bodies to compare.

Inputs: event_id (required), replay_id.

list_endpointsList endpointsA
Read-only

Lists the catch URLs (endpoints) in the current SlingHook workspace, with where each one relays events. Start here to find the endpoint a webhook was sent to.

Inputs: no named parameters.

list_eventsList eventsA
Read-only

Lists webhooks captured on an endpoint, newest first, as short summaries (number, time, method, event type, signature status) without bodies. Use get_event for one event in full. Without query or before_id it reads the newest events (up to 50, every plan). query and before_id search the whole retained history, which needs the Pro plan.

Inputs: endpoint (required), limit, query, method, +2 more.

list_scenariosList scenariosA
Read-only

Lists the saved scenarios on an endpoint: ordered sets of captured events (for example subscription created, payment failed, canceled) that run_scenario replays in sequence. Scenarios are built in the dashboard.

Inputs: endpoint (required).

replay_eventReplay eventA
Destructive

Re-sends a captured webhook to a URL from this machine (e.g. the local handler at http://localhost:3000/webhooks), with its original method, headers and body, so signature checks run for real. Records the result in the dashboard's replay history and returns the verdict against the previous attempt to the same URL: fixed, regressed, still_failing or still_passing. For an event whose signature is invalid, the handler passes by rejecting it (4xx). It can change state in the receiving app (it is a real webhook delivery).

Inputs: event_id (required), target_url (required).

run_scenarioRun scenarioA
Destructive

Replays every event of a saved scenario, in order, from this machine to a URL (e.g. the local handler), and reports each step: status, pass or fail, and the verdict against that event's previous replay to the same URL. Use it after a fix to prove a whole flow works, not just one event. Steps go back to back unless keep_timing is set (gaps capped at 5 seconds). Each step is a real webhook delivery recorded in replay history, so it can change state in the receiving app.

Inputs: scenario (required), target_url (required), keep_timing, stop_on_failure.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.2/5.0

    Scored across 11 tools

    Disambiguation5/5

    Each tool pairs a distinct action with a distinct object: listing endpoints/scenarios/events, reading a single event, comparing events, debugging a signature, replaying one event, running a scenario, and fetching a replay result. The only cluster with any risk is replay_event vs run_scenario vs get_replay_result, and the descriptions sharply separate perform-one, perform-sequence, and read-history. An agent can select correctly without guessing.

    Naming Consistency5/5

    Every name follows the same snake_case verb_noun convention (list_endpoints, get_event, replay_event, debug_signature, generate_handler, compare_events, create_endpoint). The verbs map predictably to the action performed and resource names are reused consistently across list/get/create.

    Tool Count5/5

    Eleven tools map cleanly onto the workflow stages of capturing, inspecting, replaying, and debugging webhooks, with no filler tools. Each entry earns its place without inflating the surface.

    Completeness4/5

    Coverage is strong for the agent's core loop: discover endpoints, list/get/compare events, debug signatures, replay, verify fixes, and generate handler scaffolding. Gaps (no delete or rename endpoint, no event deletion, secrets intentionally dashboard-only) are deliberate and manageable from the dashboard rather than agent dead ends.

    Maintenance

    ActivityActive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      D
      maintenance
      Enables AI agents to create disposable webhook URLs, capture incoming HTTP requests, inspect headers and bodies, and replay them against local or remote endpoints, streamlining the webhook handler development loop.
      5
      10 npm
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables coding agents to receive and inspect real webhook payloads locally, send signature-valid test events for seven providers, and replay deliveries — all without leaving the machine.
      MIT