Create a webhook
On success the CLI prints the hook URL and — exactly once — the secret. Store it immediately.
Sending events
X-Webhook-Secret: <secret>— the plain secret as a header, orX-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 anIdempotency-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-Keyheader on the request (wins over the path).
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):
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.
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
accepted, duplicate, ignored, rejected_route, rejected_rate, or rejected_budget, plus the dispatched run ID.