Ingress¶
The ingress is Hookaido's inbound HTTP listener that receives webhooks, authenticates them, and enqueues them into the durable queue.
Overview¶
When a webhook arrives:
- Path matching — find the first route whose path matches the request URL.
- Matcher evaluation — check additional match criteria (method, host, headers, etc.).
- Rate limit check — enforce global or per-route rate limits.
- Authentication — verify HMAC signature, basic credentials, or forward auth.
- Enqueue — durably persist the payload and headers into the queue.
- ACK — return
200 OKto the webhook provider only after successful enqueue.
Route Matching¶
Routes are evaluated top-down, first match wins.
/webhooks/github { ... } # matches /webhooks/github and /webhooks/github/foo
/webhooks/stripe { ... } # matches /webhooks/stripe and /webhooks/stripe/events
Path matching rules:
- Matches the URL path only (query string is ignored).
"/path"matches/pathand/path/...at segment boundaries."/path"does not match/path-foo(segment boundary enforced).- Route paths must start with
/and must be unique.
Additional Matchers¶
Matchers further narrow which requests a route accepts. All matchers within a route are ANDed:
/webhooks/github {
match {
method POST # HTTP method (case-insensitive; defaults to POST)
host "hooks.example.com" # exact host, "*", or "*.example.com"
header "X-GitHub-Event" "push" # exact header value match
header_exists "X-GitHub-Delivery" # header presence check
query "env" "production" # exact query parameter match
query_exists "token" # query parameter presence check
remote_ip "203.0.113.0/24" # source IP or CIDR
}
pull { path /pull/github }
}
| Matcher | Description |
|---|---|
method |
HTTP method (case-insensitive). Default: POST |
host |
Request host. Supports exact, * (any), *.example.com (subdomains only) |
header |
Exact header value (name is case-insensitive) |
header_exists |
Header must be present (any value) |
query |
Exact query parameter value |
query_exists |
Query parameter key must be present |
remote_ip |
Source IP or CIDR (from RemoteAddr). IPv4 and IPv6 supported |
Named Matchers¶
Define reusable matchers at the top level:
@stripe-invoice {
method POST
header "Stripe-Event-Type" "invoice.paid"
}
/webhooks/stripe {
match @stripe-invoice
pull { path /pull/stripe }
}
Authentication¶
Each route can use one authentication method. Authentication runs before enqueue — rejected requests never enter the queue.
HMAC Verification¶
Verifies webhook signatures with replay protection (timestamp + nonce + tolerance).
Shorthand:
With secret rotation:
Block form (full control):
/webhooks/github {
auth hmac {
secret env:HOOKAIDO_GITHUB_SECRET
# or: secret_ref "S1"
signature_header "X-Hub-Signature-256"
timestamp_header "X-Timestamp"
nonce_header "X-Nonce"
tolerance 5m
}
pull { path /pull/github }
}
String-to-sign: TIMESTAMP + "\n" + METHOD + "\n" + PATH + "\n" + hex(sha256(body))
Verification tries all secrets valid at the request timestamp (from the timestamp header), not just wall-clock time. This allows safe key rotation with overlapping validity windows.
Basic Auth¶
Forward Auth¶
Delegates authentication to an external service:
With options:
/webhooks/custom {
auth forward "https://auth.example.com/check" {
timeout 5s
copy_headers "X-User-ID"
copy_headers "X-Org-ID"
body_limit 64kb
}
pull { path /pull/custom }
}
Behavior:
2xx→ allow, enqueue401or403→ deny- All other outcomes (transport errors, timeouts, 5xx) → fail closed with
503
Response headers specified in copy_headers are copied from the auth response into the stored envelope headers.
auth forwardis mutually exclusive withauth basicandauth hmac.
Rate Limiting¶
Token-bucket rate limiting with global and per-route scopes.
Global (applies to all routes unless overridden):
Per-route override:
Over-limit requests receive 429 Too Many Requests.
Body and Header Limits¶
Ingress enforces size limits from defaults or per-route config:
max_body(default2mb) — payload size limit. Oversized →413.max_headers(default64kb) — total header size limit (including copied forward-auth headers). Oversized →413.
Enqueue Behavior¶
- Ingress ACKs the webhook provider (
200 OK) only after durable queue persistence. - If the queue is full (
queue_limits.max_depth), ingress returns429(withdrop_policy "reject") or silently drops the oldest item. - Queue key is the route path — all webhooks matching a route share the same queue.
Response Codes¶
| Status | Meaning |
|---|---|
200 |
Webhook received and enqueued |
400 |
Invalid request |
401 |
Authentication failed |
403 |
Forbidden (forward auth denied) |
404 |
No route matches the path |
413 |
Body or headers exceed size limits |
429 |
Rate limit exceeded or queue full |
503 |
Queue overload or forward auth failure |