Listen & forward
Claim a public name over one WebSocket and replay every delivery to a local port.
beam webhook listen <name> is the core command. It opens a WebSocket to the
beam server, presents your token, and claims the name — from then on every
request to https://<server>/webhook/<name> is pushed down the socket and
replayed to your forward target.
beam webhook listen myhook --forward http://localhost:3000Forwarding
Each incoming request is replayed to --forward with everything preserved:
- the HTTP method — GET/POST/PUT/PATCH/DELETE/HEAD all pass through with the original verb,
- the sub-path — anything after
/webhook/<name>is appended to the forward target, - the query string — carried verbatim,
- the headers — forwarded as received (so you can verify provider signatures locally),
- the body — rides inside the WebSocket frame as base64, so binary payloads survive and are replayed byte-for-byte.
…/webhook/myhook/github/callback?x=1 → http://localhost:3000/github/callback?x=1Because all headers are forwarded, signature verification (GitHub's
X-Hub-Signature-256, Stripe's Stripe-Signature, …) happens in your
local app, exactly as it would in production.
beam is fire-and-forget in v1: the sender gets an immediate 202 and the
response from your local server is not relayed back. Most providers only
care about a 2xx. See the FAQ.
Resilient by default
The listener is built to survive flaky networks and DO evictions:
- Auto-reconnect with exponential backoff if the socket drops,
- ping/pong keepalive — the Durable Object's hibernation API auto-responds, so idle tunnels survive eviction and reconnect cleanly,
- clean SIGINT shutdown —
Ctrl-Ccloses the socket and exits.
CLI flags
| flag | env | default | meaning |
|---|---|---|---|
--forward | BEAM_FORWARD | http://localhost:3000 | local URL to replay requests to |
--server | BEAM_SERVER | — (required) | your beam deployment's base URL |
--token | BEAM_TOKEN | — | API token (required) |
--key | BEAM_KEY | — | optional per-webhook delivery secret (?key=…) |
--tail | false | print requests to stdout instead of forwarding | |
--body-only | false | with --tail, print only the request body | |
--insecure | false | skip TLS verify (local dev) |
All of --forward, --server, --token, and --key fall back to the
config file and the listed env vars, so in
practice the name is usually the only argument you type.
Locking the delivery side
Pass --key <secret> and deliveries must arrive with a matching ?key=<secret>
or get 401. The param is stripped before forwarding, so it never reaches your
local app's logs. See the Security model for
the full story.
Just watching?
--tail swaps replaying for printing each request to stdout — see
Tail mode.