๐Ÿจ kowari

offline-first ยท tui ยท go

catch webhooks
locally.

A terminal webhook receiver that never phones home. Captures every request, replays any of them, and forgets about the internet entirely.

$ go install github.com/iamkorun/kowari@latest
copied โœ“
kowari ยท :8080 โ†’ localhost:3000
$ kowari --target http://localhost:3000
listening on :8080 ยท replaying to localhost:3000
REQUESTS (4)
โ–ธ POST /stripe 201 12ms
POST /github 200 08ms
POST /slack 200 05ms
POST /stripe 500 22ms
BODY ยท POST /stripe
{
  "id": "evt_1PzQ...",
  "type": "charge.succeeded",
  "data": {
    "object": {
      "amount": 4200,
      "currency": "usd"
    }
  }
}
[โ†‘/โ†“] navigate ยท [r] replay ยท [c] clear ยท [q] quit
01 โ€” offline

no cloud, no account

Every webhook stays on your machine. Your Stripe test events don't need to round-trip through someone else's SaaS to land in your dev server.

02 โ€” fast

one binary, one flag

A single static Go binary. Point it at a target URL and start catching. No config files, no projects, no accounts.

03 โ€” honest

replay with one key

Hit r and kowari re-sends the selected request to your local server. Perfect for "just reproduce the bug one more time".

in action

three flags you'll actually use

capture + replay
kowari \
  --port 8080 \
  --target \
  http://localhost:3000

Listens on :8080, shows the TUI, replays on r.

persist to disk
kowari \
  --save hooks.jsonl

Every captured request appended as JSONL. Diff fixtures against prod.

headless for ci
kowari \
  --headless \
  --save hooks.jsonl

No TUI, just capture. Useful in integration tests and automated runs.

compared

vs. the usual suspects

thing kowari webhook.site ngrok inspect
requires accountnoyesyes
works offlineyesnono
your bodies leave your boxneveralwaysalways
one-key replayyesmanualmanual
binary size~8MBโ€”~30MB