wicket#
A webhook-to-SSE gateway. Receives webhook POSTs, delivers them to subscribers as Server-Sent Events.
How it works#
The entire HTTP API is two verbs on the same path:
POST /<path> → publish an event
GET /<path> Accept: text/event-stream → subscribe (SSE stream)
The path is an arbitrary topic name. Path separators create a hierarchy — subscribing to a prefix gets you all events underneath it:
GET /github.com/chrisguidry/docketeer → just docketeer events
GET /github.com/chrisguidry/ → all chrisguidry repo events
GET /github.com/ → all GitHub events
GET / → everything
A POST to /github.com/chrisguidry/docketeer delivers to all four
subscribers above.
Zero configuration by default#
wicket works out of the box with no configuration — any path accepts POSTs and SSE connections. A YAML configuration file layers in authentication only where needed:
paths:
github.com/chrisguidry/docketeer:
verify: hmac-sha256
secret: "the-github-webhook-secret"
signature_header: X-Hub-Signature-256
subscribe_secret: "token-for-docketeer-subscribers"
Values support environment variable interpolation via $VAR or ${VAR}
syntax, so secrets can come from the environment rather than being hardcoded:
paths:
github.com/chrisguidry/docketeer:
verify: hmac-sha256
secret: "${WEBHOOK_SECRET}"
signature_header: X-Hub-Signature-256
subscribe_secret: "${SUBSCRIBE_TOKEN}"
- Unconfigured paths accept POSTs without verification
- Configured paths verify webhook signatures and reject invalid ones
- Subscribe secrets require
Authorization: Bearer <token>for SSE connections - Configuration is hot-reloaded on file change or SIGHUP
Browser support#
CORS headers are sent on all responses, so browser apps can POST events
and subscribe via EventSource. One limitation: the browser's
EventSource API doesn't support custom headers, so browser clients
can only subscribe to paths without a subscribe_secret. Protected
paths are for server-to-server use.
Event format#
Every event is wrapped in an envelope and delivered as SSE:
id: unique-event-id
data: {"id":"...","timestamp":"...","path":"github.com/chrisguidry/docketeer","headers":{...},"payload":{...}}
Subscribers can reconnect with Last-Event-ID to replay missed events
from an in-memory ring buffer (default 1000 events).
Filtering#
Optional query params filter events on the subscribe side:
GET /github.com/chrisguidry/docketeer?filter=payload.ref:refs/heads/main
Simple dot-path equality matching. Multiple filters are AND'd.
Usage#
wicket # listen on :8080, no configuration
wicket -address :9090 # custom listen address
wicket -configuration wicket.yaml # with webhook verification
wicket -buffer-size 5000 # larger replay buffer
Building#
go build -o wicket .
Or with Docker:
docker build -t wicket .
Why the name "wicket"?#
A "wicket" is a small door or gate next to a larger one.