Skip to content

Webhook Notifications#

oxo-flow includes a webhook client (oxo_flow_core::webhook, behind the webhook cargo feature — enabled by default) that can send JSON notifications about workflow and rule execution events to external services like Slack, Microsoft Teams, Discord, or any custom HTTP endpoint.

Status note: the webhook module provides the configuration model, the HTTP client (with retries and HMAC signing), and the payload types. It is not yet wired into the executor — the engine does not currently dispatch webhook notifications during workflow execution.

Configuration#

A webhook is described by the WebhookConfig struct:

Field Type Default Description
url String — (required) Webhook endpoint URL.
method String "post" HTTP method: post, put, or get.
headers Map {} Custom HTTP headers to include in the request.
events Array of String ["workflow_completed"] Events to subscribe to (see below). If omitted, only workflow_completed is used.
secret String none Secret key for HMAC-SHA256 signature.
timeout_secs Integer 30 Request timeout in seconds.
max_retries Integer 3 Maximum retries on failure (with exponential backoff: 1s, 2s, 4s...).

Example Configuration#

url = "https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
events = ["workflow_started", "workflow_completed", "workflow_failed"]
method = "post"
headers = { "X-Custom" = "value" }
secret = "my-shared-secret"  # Used for HMAC-SHA256 signature
timeout_secs = 30
max_retries = 3

Supported Events#

Events are serialized in snake_case. You can subscribe by listing them in the events array:

Event Name Description
workflow_started Fired when the workflow execution begins.
workflow_completed Fired when the workflow finishes (success or failure).
workflow_failed Fired when the workflow fails.
rule_completed Fired when an individual rule completes.
rule_failed Fired when an individual rule fails.

There is no WorkflowCancelled, RuleStarted, or RuleSkipped event in the webhook module.

If the events array is omitted, the default subscription is ["workflow_completed"] only.

Payload#

The json payload is a standard HTTP POST request with Content-Type: application/json. The body is a WebhookPayload:

{
  "event": "rule_failed",
  "workflow_name": "variant-calling",
  "timestamp": "2026-05-18T12:00:00Z",
  "data": {
    "total_rules": 12,
    "succeeded": 10,
    "failed": 1,
    "skipped": 1,
    "duration_ms": 45210,
    "rule": "align_reads",
    "exit_code": 1,
    "error": "bwa: command not found"
  },
  "version": "0.15.0"
}

Field details:

  • event — the event name in snake_case.
  • workflow_name — the workflow name.
  • timestamp — ISO 8601 timestamp.
  • data — event-specific fields; only the fields relevant to the event are present (total_rules, succeeded, failed, skipped, duration_ms, rule, exit_code, error).
  • version — the oxo-flow version that sent the notification.

Slack format#

For Slack-compatible endpoints, WebhookPayload::to_slack_payload() converts the payload to a {"text": "...", "blocks": [...]} message with per-event status emoji (green success, red failure), directly compatible with Slack Incoming Webhooks.

Security (HMAC Signatures)#

If you set the secret field, oxo-flow computes an RFC-2104 HMAC-SHA256 signature over the payload body and includes it in the X-OxoFlow-Signature HTTP header (verified against the published RFC 4231 test vectors):

POST /alerts HTTP/1.1
Host: api.my-monitoring.com
Content-Type: application/json
X-OxoFlow-Signature: hmac-sha256=abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890

{"event": "rule_failed", ...}

Your receiving endpoint can use this signature to verify that the webhook request genuinely originated from your oxo-flow execution and that the payload was not tampered with in transit.

Legacy scheme. The original implementation signed with a non-standard keyed SHA-256 (sha256=hex(sha256(secret‖body))), which is not HMAC-SHA256 despite the header name. It remains available via signature_scheme = "sha256-keyed" for existing consumers and is frozen: emit a warning, switch your verifier to hmac-sha256, and it will be removed in a future major version. The default is "hmac-sha256".