Configuration

whook is configured entirely through environment variables, so it drops cleanly into containers and 12-factor setups. Every value has a sensible default; you can run it with no configuration at all for local use.

Reference

VariableDefaultPurpose
WHOOK_ADDR:8080HTTP listen address
WHOOK_DATABASE_URLfile:whook.db?...Storage DSN. A postgres:// URL selects Postgres; anything else is SQLite
WHOOK_ADMIN_TOKENemptyBearer token for the management API and dashboard. Empty disables auth (local only)
WHOOK_SECRET_KEYemptyPassphrase used to encrypt provider signing secrets at rest
WHOOK_MAX_BODY_BYTES1048576Max inbound body size; larger requests are rejected with 413
WHOOK_WORKERS4Concurrent delivery workers
WHOOK_POLL_INTERVAL1sHow often workers poll the queue
WHOOK_RETENTION_AGEemptyDelete received events older than this (e.g. 720h). Empty disables pruning
WHOOK_FAILED_RETENTION_AGE= retentionKeep rejected and dead-lettered events longer
WHOOK_PRUNE_INTERVAL1hHow often the retention pruner runs
WHOOK_INGEST_RATE0Max ingest requests per second per source. 0 disables limiting
WHOOK_INGEST_BURST= rateToken-bucket burst size for ingest limiting

Authentication

POST /ingest/{source} and GET /healthz are always public. Everything else (the management API, the dashboard, /metrics) requires the admin token once WHOOK_ADMIN_TOKEN is set. Pass it as Authorization: Bearer <token>, or as a ?token= query parameter for the browser dashboard. Leaving the token empty disables the check and is only appropriate for local development.

Signing secrets at rest

When a source configures a signing secret, it is encrypted with AES-256-GCM using a key derived from WHOOK_SECRET_KEY. The API never returns a stored secret; it only reports whether one is set. Keep WHOOK_SECRET_KEY stable, since rotating it invalidates existing encrypted secrets.

Retention

Captured events are kept forever unless WHOOK_RETENTION_AGE is set. When it is, a background pruner deletes received events past that age, along with their attempts and queue rows. Rejected and dead-lettered events are kept until the longer WHOOK_FAILED_RETENTION_AGE so failures stay around for debugging.

Rate limiting

WHOOK_INGEST_RATE caps how many webhooks a single source can send per second, with an independent token bucket per source. Over-limit requests are shed early with a 429 and a Retry-After header, before the body is read.