Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Production: `https://webhooks.cc` (app) and `https://go.webhooks.cc` (webhook re
| `content/docs/` | MDX source for `/docs/*`, rendered by the catch-all route in `apps/web/app/docs/`. |
| `apps/receiver-rs/` | Rust (Axum, Tokio, sqlx) webhook receiver. Captures at `/w/{slug}`. Env vars are read in `src/config.rs`. |
| `apps/mx-rs/` | Rust (Tokio) receive-only SMTP host for email capture on `mailhooks.cc`. Env vars are read in `src/config.rs`. |
| `apps/cli-rs/` | Rust CLI `whk` (Clap, Ratatui). Subcommands live in `src/cli/`. |
| `apps/cli-rs/` | Rust CLI `whk` (Clap). Subcommands live in `src/cli/`; exit statuses and error codes in `src/error.rs`. |
| `apps/edge-rs/` | Rust (Tokio, hyper, yamux) tunnel edge: serves `whk share` previews on sharehooks.cc and relays `whk tunnel --live` captures. Env vars are read in `src/config.rs`. |
| `crates/tunnel/` | `whk-tunnel`, the tunnel protocol (WebSocket, yamux, splice) shared by the edge and the CLI. |
| `apps/parser-rs/` | Rust attachment parser `webhooks-parser` (CSV, TSV, XLSX, XLS, ODS, PDF text, text): a sandboxed child process of the web app's parse worker. |
Expand Down Expand Up @@ -86,6 +86,8 @@ Capture path: a sender POSTs to `go.webhooks.cc/w/{slug}/...`. The receiver vali

Decisions worth knowing, with the reasons:

- **Nobody needs the dashboard.** Every user-facing capability works from the API, the CLI, the SDKs and the MCP server, because people increasingly work through coding agents, and a step that needs a dashboard stops the agent. Signup and payment are the exceptions. Where a person has to decide (a sensitive change, a payment), the agent asks and the person approves through a link or a code, never by doing the work in the dashboard. The dashboard is a view, never the only way.
- **`whk` serves agents as well as people.** `--json` prints the API's own JSON (`Fetched` in `api/client.rs` keeps it beside the parsed value, so fields the CLI does not know still reach the caller), failures carry a code and a stable exit status (`src/error.rs`, listed in `whk --help` and `/docs/cli`), nothing reads stdin without a terminal (`cli/confirm.rs`: `--yes` instead), `whk wait` exits on the next arrival, and `whk api` reaches any route a command does not cover. There is no full-screen TUI: a bare `whk` opened one and hung any agent that ran it, so it was retired (November 2026) for one-line and NDJSON output from `listen` and `tunnel`.
- **The receiver talks to Postgres directly** (`DATABASE_URL`), not through the web app. One fewer hop on the hot path, and the stored procedure keeps quota and counters atomic. In production it connects to Postgres on the same Docker network rather than through Supavisor: on one host the pooler only costs CPU, and a load test sustained about twice the throughput without it.
- **DB failures are classified.** Transient errors (pool timeout, connection loss, SQLSTATE classes 08/40/53/57/58) return 503 with `Retry-After: 5` so senders retry; at-least-once delivery beats silent loss. Permanent errors fail open with 200 and are logged and counted in the receiver's once-a-minute `counts` log line (`capture_failed.<kind>`). NUL bytes in bodies and paths are sanitised (raw bytes kept in `body_raw`) instead of failing the insert.
- **RLS is deny-by-default for client roles.** Anonymous users cannot read endpoints, requests, or device codes, and may only read published blog posts. Guest dashboard reads and guest endpoint creation go through server routes using the service role. Client roles have no write access to `users`, `endpoints`, or `api_keys` (migrations 00037 and 00045; every write goes through a server route that validates, rate-limits, and audits it) and no EXECUTE on `public` functions unless a migration grants it (00037 revoked them and reset the default privileges). Team members can read shared endpoints through `can_view_team_endpoint()`, which also lets them join the endpoint's Realtime topic.
Expand Down
27 changes: 5 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ curl -X POST https://go.webhooks.cc/w/<slug> -d '{"test": true}'
- **Verify signatures**: check provider signatures (Stripe, GitHub, Shopify and more) on captured requests
- **Forward**: tunnel webhooks to localhost during development (with `--live`, the sender gets your local app's answer), or forward them to other URLs, chat and file drops
- **Share localhost**: put the site on your machine at a public link on sharehooks.cc with `whk share`
- **CLI with interactive TUI**: manage endpoints, tunnel and stream requests from your terminal
- **CLI for people and agents**: manage endpoints, tunnel, stream and wait for requests from your terminal, with JSON output and stable exit codes for scripts and coding agents
- **SDKs for TypeScript, Python and Go**: wait for and assert on webhooks in tests and CI, and share a local port from code
- **pytest plugin**: `pip install pytest-webhooks-cc` gives every test a capture URL and an email address as fixtures
- **GitHub Action**: [`setup-whk`](https://github.com/marketplace/actions/setup-whk) installs the CLI in a workflow
Expand Down Expand Up @@ -124,35 +124,18 @@ See [webhooks.cc/installation](https://webhooks.cc/installation) for all install

## CLI

Run `whk` to launch the interactive TUI:

```
$ whk

webhooks.cc

● Logged in as you@example.com

▸ Tunnel Forward webhooks to localhost
Listen Stream incoming requests
Create Create a new endpoint
Endpoints Manage your endpoints
Auth Login / logout
Update Check for updates
```

All commands also work directly from the command line:

```bash
whk tunnel 8080 # Forward webhooks to localhost:8080
whk share 3000 # Share localhost:3000 at https://<name>.sharehooks.cc
whk listen <slug> # Stream incoming requests
whk listen <slug> # Stream incoming requests, one line each
whk wait <slug> --json # Block until the next request arrives, print it, exit
whk create my-endpoint # Create a new endpoint
whk list # List your endpoints
whk replay <request-id> --to :3000 # Replay a captured request
whk api endpoints/<slug>/destinations # Call any API route with your credentials
```

Pass `--nogui` or set `WHK_NOGUI=1` to skip the TUI and print help.
Every command takes `--json` (the API's own answers, NDJSON for streams, failures as `{"error": {...}}` on stderr) and exits with a stable status that says what went wrong; see `whk --help`. Nothing waits for input without a terminal: destructive commands need `--yes` there.

## SDK

Expand Down
Loading
Loading