Single-binary webhook inbox

Accept HTTP.
Store it. Show it.

One binary, zero dependencies. No Postgres, no Redis, no Docker Compose. scp it to a box, run it, done.

Get Started
134tests
0dependencies
1binary
< 10MBfootprint
scroll

Features

Everything you need. Nothing you don't.

Built with the TigerBeetle philosophy: deterministic resource usage, pre-allocated bounds, no surprise OOM.

One binary, zero deps

No Postgres, no Redis, no Docker Compose. scp it to a box, run it, done.

Embedded SQLite

WAL mode, crash-safe, deterministic resource bounds. Data lives in a single directory.

Live dashboard

Built-in SPA with live polling, syntax-highlighted JSON, and full request inspector.

134 tests

Every handler, every edge case, every error path. cargo test is the only gate.

Tiny footprint

Optimized release build with LTO, stripped symbols, and panic = abort.

Bounded resources

Pre-allocated limits on hooks, payloads, and requests. Nothing grows without limit.


Quick Start

Up and running in 60 seconds

terminal
1.Build
cargo build --release

# Build the optimized binary

2.Run
./target/release/hookbin serve --port 8080

# Start the server

3.Create a hook
curl -s http://localhost:8080/api/hooks -X POST | jq .

# => { "id": "abc123xyz", "url": "/h/abc123xyz", ... }

4.Send a webhook
curl -X POST http://localhost:8080/h/abc123xyz \
  -H "Content-Type: application/json" \
  -d '{"event": "deploy", "status": "success"}'

# => 200 OK

5.Inspect
open http://localhost:8080

# View it in the dashboard


API

Clean, predictable endpoints

All endpoints return structured JSON with error suggestions.

MethodPath
POST/h/{hook_id}
GET/api/hooks
POST/api/hooks
GET/api/hooks/{id}
DELETE/api/hooks/{id}
GET/api/hooks/{id}/requests
GET/api/hooks/{id}/requests/{rid}
GET/health
GET/

Structured error responses:

{
  "error": "not found: hook abc123xyz",
  "suggestion": "Check the hook ID and try again"
}

Configuration

Three-layer config

Defaults -> TOML file -> CLI flags. CLI always wins.

hookbin.toml
# hookbin.toml
port = 8080
data = "/var/lib/hookbin"
max_hooks = 50
max_payload = 2097152
max_requests = 500
retention = 43200     # 12 hours
rate_limit = 30       # requests per minute
Resource Limits
Max hooks--max-hooks
100
Max payload size--max-payload
1 MB
Max requests per hook--max-requests
1,000
Request retention--retention
24 hours
Rate limit per hook--rate-limit
60 req/min
SQLite WAL mode-
Always on
Rust
Axum 0.8
SQLite (WAL)
Tokio
rust-embed