Hookshot
A self-hosted webhook relay service built with Rails 8. Receives webhooks, filters them based on configurable rules, and dispatches to multiple target endpoints.
Install / Use
/learn @mensfeld/HookshotREADME
Hookshot
A self-hosted webhook relay service built with Rails 8. Receives webhooks, filters them based on configurable rules, and dispatches to multiple target endpoints.

Quick Start
# Clone and install
git clone https://github.com/mensfeld/hookshot.git
cd hookshot
bundle install
npm install
# Setup database and assets
rails db:create db:migrate
rails tailwindcss:build
# Start everything (web + background jobs)
./bin/dev
# Or start separately:
# rails server # Web server on port 3000
# rails solid_queue:start # Background job processor
Then:
- Visit
http://localhost:3000/admin/targets(login:admin/changeme) - Create a target with your destination URL
- Send webhooks to
http://localhost:3000/webhooks/receive
Features
- Webhook Reception: Accepts POST requests at
/webhooks/receiveand stores headers, payload, and metadata - Multiple Targets: Configure multiple destination endpoints for webhook delivery
- Filtering: Route webhooks to specific targets based on header or payload content
- Background Processing: Reliable delivery with Solid Queue, including retries with exponential backoff
- Admin Dashboard: View webhooks, dispatches, and manage targets with a clean DaisyUI interface
- Replay: Re-dispatch any webhook to all active targets
- Health Check:
/healthendpoint for monitoring
Requirements
- Ruby 3.4+
- SQLite 3
- Node.js (for Tailwind CSS compilation)
Setup
# Install dependencies
bundle install
npm install
# Setup database
rails db:create db:migrate
# Compile assets
rails tailwindcss:build
# Start the server
rails server
Configuration
Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| TZ | UTC | Timezone for displaying timestamps (e.g., Europe/Warsaw, America/New_York) |
| HOOKSHOT_USER | admin | HTTP Basic Auth username for admin UI |
| HOOKSHOT_PASSWORD | changeme | HTTP Basic Auth password for admin UI |
| RETENTION_DAYS | 30 | Days to retain webhook data before cleanup |
Background Jobs
Start Solid Queue to process webhook deliveries:
rails solid_queue:start
Or run everything with Foreman/Overmind using the Procfile.
Usage
Receiving Webhooks
Send any POST request to /webhooks/receive:
curl -X POST http://localhost:3000/webhooks/receive \
-H "Content-Type: application/json" \
-d '{"event": "user.created", "data": {"id": 123}}'
Admin Dashboard
Access the admin UI at http://localhost:3000/admin/webhooks with HTTP Basic Auth.
- Webhooks: View received webhooks, inspect headers/payload, replay to targets
- Dispatches: Monitor delivery status, retry failed deliveries
- Targets: Configure destination endpoints with filters
- Jobs: Solid Queue dashboard at
/jobs
Configuring Targets
Each target has:
- Name: Identifier for the target
- URL: Destination endpoint (must be HTTPS in production)
- Timeout: Request timeout in seconds (1-300)
- Active: Toggle to enable/disable delivery
- Custom Headers: Additional headers to send with each request
- Filters: Rules to determine which webhooks to deliver
Filters
Filters allow routing webhooks to specific targets. All filters must match for delivery.
Filter Types:
Header: Match against request headersPayload: Match against JSON payload using dot notation (e.g.,$.event)
Operators:
Exists: Field is presentEquals: Field equals exact valueMatches: Field matches pattern (supports*wildcard)
Example: Only deliver webhooks where $.event equals user.created:
- Type:
Payload - Field:
$.event - Operator:
Equals - Value:
user.created
API Endpoints
| Method | Path | Auth | Description |
|--------|------|------|-------------|
| POST | /webhooks/receive | None | Receive incoming webhooks |
| GET | /health | None | Health check endpoint |
| GET | /admin/* | Basic | Admin dashboard |
| GET | /jobs | Basic | Solid Queue dashboard |
Delivery Headers
Each delivery includes these headers:
Content-Type: Original webhook content typeX-Hookshot-Webhook-Id: Internal webhook IDX-Hookshot-Delivery-Id: Internal delivery ID- Any custom headers configured on the target
Retry Behavior
Failed deliveries are retried with exponential backoff:
- Up to 5 attempts
- Increasing delay between retries
- Client errors (4xx) are not retried
- Server errors (5xx) and timeouts are retried
Docker Deployment
Single container runs both web server and background job processor:
# Build image
docker build -t hookshot .
# Run with docker-compose
SECRET_KEY_BASE=$(rails secret) HOOKSHOT_PASSWORD=your-password docker-compose up -d
# Or run directly
docker run -d \
-p 3000:3000 \
-v hookshot_data:/rails/storage \
-e SECRET_KEY_BASE=$(rails secret) \
-e HOOKSHOT_PASSWORD=your-password \
--name hookshot \
hookshot
Data is persisted in the hookshot_data volume.
License
MIT - see LICENSE.md for details.
