Skip to content

Getting Started

This guide walks you through installing Hookaido and running your first webhook ingress queue.

Install

Pre-built binary (no Go required):

Download the latest binary for your platform from GitHub Releases.

Build from source (requires Go 1.26+):

go build -o hookaido ./cmd/hookaido

Docker:

See Docker Quickstart for a full Docker / Docker Compose guide.

docker build -t hookaido .

Verify:

./hookaido version

Minimal Pull-Mode Setup

Pull mode is the recommended default: Hookaido receives webhooks in the DMZ, and your internal workers pull messages via outbound-only connections.

1. Create a Hookaidofile

ingress {
  listen :8080
}

pull_api {
  auth token env:HOOKAIDO_PULL_TOKEN
}

/webhooks/github {
  auth hmac {
    provider github
    secret env:HOOKAIDO_INGRESS_SECRET
  }
  pull { path /pull/github }
}

This config:

  • Listens for incoming webhooks on :8080
  • Exposes a Pull API on :9443 (default) with token authentication
  • Routes POST /webhooks/github through GitHub signature verification (X-Hub-Signature-256), then enqueues

2. Set Environment Variables

export HOOKAIDO_PULL_TOKEN="your-pull-secret"
export HOOKAIDO_INGRESS_SECRET="your-hmac-secret"   # the "Secret" set on the GitHub webhook

For local development, use a dotenv file instead:

# .env
HOOKAIDO_PULL_TOKEN=devtoken
HOOKAIDO_INGRESS_SECRET=devsecret

3. Start Hookaido

./hookaido run --config ./Hookaidofile --db ./.data/hookaido.db

With dotenv:

./hookaido run --config ./Hookaidofile --db ./.data/hookaido.db --dotenv ./.env

Hookaido starts three listeners:

  • Ingress on :8080 — receives webhooks
  • Pull API on :9443 — workers consume from here
  • Admin API on 127.0.0.1:2019 — health checks, DLQ management

4. Send a Test Webhook

Sign the body the way GitHub does (sha256= + hex HMAC-SHA256 of the raw body):

BODY='{"action": "push", "ref": "refs/heads/main"}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$HOOKAIDO_INGRESS_SECRET" | awk '{print $NF}')

curl -X POST http://localhost:8080/webhooks/github \
  -H "Content-Type: application/json" \
  -H "X-GitHub-Event: push" \
  -H "X-Hub-Signature-256: sha256=$SIG" \
  -d "$BODY"

Hookaido answers 202 Accepted once the event is queued. A missing or wrong signature gets 401. Once a real GitHub webhook points at this URL with the same secret, its deliveries verify the same way.

5. Consume Messages

Your worker polls the Pull API:

# Dequeue a batch
curl -X POST http://localhost:9443/pull/github/dequeue \
  -H "Authorization: Bearer devtoken" \
  -H "Content-Type: application/json" \
  -d '{"batch": 10, "lease_ttl": "30s"}'

Response:

{
  "items": [
    {
      "id": "evt_abc123",
      "lease_id": "lease_xyz",
      "route": "/webhooks/github",
      "target": "pull",
      "payload_b64": "eyJhY3Rpb24iOiAicHVzaCJ9",
      "headers": { "Content-Type": "application/json" },
      "received_at": "2026-02-09T10:00:00Z",
      "attempt": 1
    }
  ]
}

After processing, acknowledge:

curl -X POST http://localhost:9443/pull/github/ack \
  -H "Authorization: Bearer devtoken" \
  -H "Content-Type: application/json" \
  -d '{"lease_id": "lease_xyz"}'

Or reject (requeue with delay):

curl -X POST http://localhost:9443/pull/github/nack \
  -H "Authorization: Bearer devtoken" \
  -H "Content-Type: application/json" \
  -d '{"lease_id": "lease_xyz", "delay": "5s"}'

Minimal Push-Mode Setup

In push mode, Hookaido delivers webhooks directly to your internal endpoints:

/webhooks/github {
  deliver https://ci.internal/build {}
}

No Pull API is needed — Hookaido handles retry, backoff, and (optional) outbound signing. See Delivery (Push) for details.

Minimal Exec-Mode Setup

Exec mode runs a local script for each webhook — no HTTP server needed on the receiving end:

/webhooks/github {
  auth hmac {
    provider github
    secret env:GITHUB_WEBHOOK_SECRET
  }

  deliver exec "./handle-webhook.sh" {
    timeout 30s
  }
}

Create a handler script:

#!/usr/bin/env bash
# handle-webhook.sh — payload arrives on stdin
PAYLOAD=$(cat)
echo "Received: $(echo "$PAYLOAD" | jq -r '.action // .ref')" >&2
# Exit 0 = ack, non-zero = retry

Start Hookaido:

export GITHUB_WEBHOOK_SECRET="your-github-secret"
chmod +x handle-webhook.sh
./hookaido run --config ./Hookaidofile --db ./.data/hookaido.db

The script runs once per webhook event. Exit code 0 acknowledges the message; any other exit code triggers a retry. See Subprocess Execution for exit code details and environment variables.

Validate Your Config

Before starting:

./hookaido config validate --config ./Hookaidofile

Format (canonical style, idempotent):

./hookaido config fmt --config ./Hookaidofile

Check Health

curl http://127.0.0.1:2019/healthz
# Detailed diagnostics:
curl http://127.0.0.1:2019/healthz?details=1

CLI Reference

Command Description
hookaido run Start the server
hookaido config fmt Format the Hookaidofile
hookaido config validate Validate config (exit code 0/1)
hookaido mcp serve Start MCP server (AI tooling)
hookaido config diff Show differences between two config files
hookaido verify-release Verify release artifact checksums and signatures
hookaido version Print version

hookaido run Flags

Flag Default Description
--config ./Hookaidofile Path to config file
--db ./hookaido.db Path to SQLite database. The container image overrides this with /app/.data/hookaido.db, which is the declared volume
--postgres-dsn — PostgreSQL DSN (when queue.backend is postgres)
--pid-file — Write PID file (enables SIGHUP reload)
--watch false Hot-reload on config file changes
--watch-interval — With --watch, also poll the config for content changes at this interval (min 1s). Needed when the config is a single-file bind mount — see Hot Reload
--log-level info Runtime log level
--dotenv — Load environment variables from file

Next Steps


← Documentation Index