Most webhooks: describe it in plain language
For a trigger on a built-in source (GitHub, Jira, Linear, Zendesk, Fathom), the trigger sheet has a Run only when (optional) field. Describe the condition in plain English, for example “Pull requests by John on dust repository”, and Dust generates the filter for you. Leave it blank and the trigger runs on every event the source sends.Custom webhooks: write a filter expression
A custom webhook has no provider, so Dust doesn’t know the shape of its payload and can’t offer the plain-language option. Instead, the trigger sheet has a Filter expression (optional) field. Leave it blank and every request runs the agent; write an expression and only matching requests do.How it works
An expression is a small rule written as(operator "field.path" value). Field paths use dot notation into the JSON payload the webhook sends, for example "issue.state" or "pull_request.head.ref". For an array of objects, pull one field out of each item with a single wildcard level: "tags.*.name" reads name from every object in tags (deeper paths like "tags.*.sub.name" aren’t supported).
Combine rules with and, or, and not:
Operators
Examples
- Only opened issues:
(eq "action" "opened") - Opened by a specific person:
(and (eq "action" "opened") (eq "sender.login" "alice")) - Has a “bug” or “urgent” label:
(has-any "issue.labels" ("bug" "urgent")) - Not closed (combine
notandeq):(not (eq "issue.state" "closed")) - Large pull requests:
(and (eq "action" "opened") (gt "pull_request.changed_files" 20))
Test before you save
Click Compute stats next to the filter field. Dust looks at the last 24 hours of events this source received and reports how many would have matched your filter. You need at least 10 events in that window for an estimate; with fewer, it shows “not enough data” instead. Use it to confirm your filter catches what you expect before turning the trigger on.Common mistakes
- Case matters.
"issue.State"is a different field from"issue.state", and(eq "action" "Opened")won’t match a payload whereactionis"opened". - Numeric operators need real numbers.
(gt "issue.comments" "10")always returnsfalseif"10"is written as a quoted string;gt,gte,lt, andlteonly work when both sides are JSON numbers. - Wildcards go one level deep.
"tags.*.name"works;"tags.*.sub.name"does not. - An empty expression always runs. Leave Filter expression blank and the trigger fires on every event from that source.
- A missing field just means “false”, not an error. Any check on a field the payload doesn’t have returns
false, except(not (exists "field")), which returnstrue. - An empty list in
has-allis trivially true.(has-all "issue.labels" ())returnstrue, there are no required values left to fail on.has-anywith an empty list behaves as you’d expect and returnsfalse.