# examples/filters.yaml## Reference config demonstrating webhook filtering. A filter chain is a list of# conditions combined with AND — every condition must pass. Filters attach as# nodes in a flow:## flow-level (a filter node after envelope, before every publish)# Evaluated first, after auth and body parsing. If the chain fails,# nothing is published. The response is controlled by on_no_match# (default: silent drop / 202 ack with no destinations). Set# on_no_match: reject to return 422.## branch-level (a filter node on only some edges after envelope)# Evaluated per destination. A branch whose chain fails is dropped from# delivery; other branches still receive the payload. Branch filtering# always acks with 202 when on_no_match is the default drop.## Condition fields:# source header | body# path header name, or dotted body path (e.g. repository.private)# operator eq ne gt gte lt lte contains prefix suffix regex exists not_exists# value comparison value; its type selects the mode for eq/ne. Omit for# exists / not_exists.## Header values are always strings, so numeric/bool operators parse them# ("42" matches eq: 42; "true"/"1" match eq: true). A missing or type-mismatched# value fails the condition (never errors), including ne. A non-JSON body fails# every body condition except not_exists.server: addr: ":8080" max_body_bytes: 1048576destinations: primary: type: "rabbitmq" rabbitmq: url: "${RABBITMQ_URL}" exchange: "hookway.webhooks" exchange_type: "direct" durable: true publish_timeout: "5s" declare_queues: trueflows: # Flow-level filtering: only GitHub "push" events on public repos are # accepted. Anything else is dropped with a silent 202 ack (the default), so # GitHub does not retry filtered-out deliveries. github_push_public: nodes: - {id: in, type: http_trigger, description: "GitHub posts webhook deliveries here.", path: /webhooks/github, methods: [POST]} - {id: body, type: read_body, description: "Reads the raw body, rejecting anything over 1 MiB.", max_bytes: 1048576} # No idempotency_header field; replay_guard is a separate node. - {id: auth, type: auth, description: "Verifies the GitHub HMAC signature over the raw body.", scheme: hmac_sha256_hex, secret: "${GITHUB_WEBHOOK_SECRET}", signature_header: X-Hub-Signature-256} - {id: env, type: envelope, description: "Builds the JSON envelope the filter reads fields from.", body_format: json} - id: filt type: filter description: "Keeps only pushes to public repositories; drops the rest." conditions: - source: header path: X-GitHub-Event operator: eq value: "push" - source: body path: repository.private operator: eq value: false - {id: out, type: publish, description: "Receives only the events that cleared the filter.", destination: primary, target: github-public-pushes, create: true} edges: [in>body, body>auth, auth>env, env>filt, filt>out] # Branch-level filtering: every accepted event fans out selectively. Main-branch # pushes go to one queue, all pushes to another. A branch whose filter fails is # simply skipped — it is never counted as a delivery failure — so this flow # always returns 202. github_branch_router: nodes: - {id: in, type: http_trigger, description: "Router endpoint that fans one event out two ways.", path: /webhooks/github-router, methods: [POST]} - {id: body, type: read_body, description: "Reads the raw body, rejecting anything over 1 MiB.", max_bytes: 1048576} - {id: auth, type: auth, description: "Verifies the GitHub HMAC signature over the raw body.", scheme: hmac_sha256_hex, secret: "${GITHUB_WEBHOOK_SECRET}", signature_header: X-Hub-Signature-256} - {id: env, type: envelope, description: "Builds the JSON envelope both branches receive.", body_format: json} - id: main_filt type: filter description: "Gates the main-branch branch only; a drop here is not a failure." conditions: - source: body path: ref operator: eq value: "refs/heads/main" - {id: main_out, type: publish, description: "Main-branch pushes only.", destination: primary, target: github-main-pushes, create: true} # No filters: receives every event this flow accepts. - {id: all_out, type: publish, description: "Every event the flow accepts, unfiltered.", destination: primary, target: github-all-pushes, create: true} edges: [in>body, body>auth, auth>env, env>main_filt, env>all_out, main_filt>main_out] # Flow filtering that rejects non-matching payloads with 422 instead of a # silent ack. Shows numeric (gte), regex, and exists operators. orders_high_value: nodes: - {id: in, type: http_trigger, description: "Order events from the commerce platform.", path: /webhooks/orders, methods: [POST]} - {id: body, type: read_body, description: "Reads the raw body, rejecting anything over 1 MiB.", max_bytes: 1048576} - {id: auth, type: auth, description: "Verifies the timestamped HMAC within a 5 minute window.", scheme: hmac_sha256_ts_colon, secret: "${ORDERS_WEBHOOK_SECRET}", signature_header: X-Order-Signature, timestamp_tolerance: "5m"} - {id: env, type: envelope, description: "Builds the JSON envelope the filter reads fields from.", body_format: json} - id: filt type: filter description: "Requires a large order in a known currency; rejects with 422." on_no_match: reject conditions: - source: body path: order.total operator: gte value: 100 - source: body path: order.currency operator: regex value: "^(USD|EUR|GBP)$" - source: body path: customer.id operator: exists - {id: out, type: publish, description: "Receives only high-value orders.", destination: primary, target: high-value-orders, create: true} edges: [in>body, body>auth, auth>env, env>filt, filt>out]