Skip to main content
Inbound webhooks (called triggers in the CLI) turn external events into agent runs: Stripe fires on a new order, GitHub on a new issue, your monitoring on an alert — and an agent picks it up with the event payload as context. In the dashboard they live under Automations → Webhooks.

Create a webhook

On success the CLI prints the hook URL and — exactly once — the secret. Store it immediately.

Sending events

Authenticate each delivery either way:
  • X-Webhook-Secret: <secret> — the plain secret as a header, or
  • X-Webhook-Signature: sha256=<hex> — HMAC-SHA256 of the raw body with the secret.

Provider webhooks

Most providers can’t send custom headers — they sign with their own fixed header instead. ZWRM recognizes those directly, so you can paste the trigger secret into the provider’s webhook settings and it just works: For GitHub, paste the secret into the webhook’s Secret field and set the content type to application/json. Verification is accept-if-any: an unmatched header never vetoes one that verifies. Providers whose signatures cover a timestamped string (Stripe, Slack, Svix-based) or that require a validation handshake (Microsoft Graph, Event Grid, Zoom) are not supported by header aliasing. Bodies are parsed as JSON (up to 1 MiB). The agent’s prompt is built from the trigger’s instruction plus the rendered body (via --message-template, or the raw body if no template is set).

Idempotency

Send an Idempotency-Key header to make retries safe: a key that was already accepted returns {"status":"duplicate"} without dispatching a second run.

Session continuity

Deliveries can share a workspace (conversation + files) with either:
  • --session-key-path data.customer.id — extract the key from the payload, or
  • an X-Session-Key header on the request (wins over the path).
Blank = every delivery is a one-shot run on a fresh workspace.

Matching and routing

Match conditions (--match) gate the trigger — every condition must hold or the delivery is ignored (with a 200 ignored response, so providers stop retrying):
Operators: exists, not_exists, equals (default), not_equals, in. Paths are dot-descent into JSON objects (no array indexing). Routes (--routes) pick the agent: the first route whose when conditions all match wins; a route with no when is a catch-all. If no route matches, the --default-agent handles it; with neither, the delivery is dropped.
The dashboard has a visual editor for conditions and routes.

Responses

ZWRM does not retry inbound deliveries itself — the status codes are chosen so the sender’s retry logic does the right thing.

Inspect and manage

The delivery log records every delivery with its disposition: accepted, duplicate, ignored, rejected_route, rejected_rate, or rejected_budget, plus the dispatched run ID.