Triggers
A trigger is what starts a Helix run — the product calls this the automation’s stimulus. Every automation has one, and you can change it at any time. There are three ways to start a run today.
On demand
Run the automation by hand whenever you need it — from its page in the app, or as part of testing. On-demand is the default while you’re building, and stays useful for automations you run occasionally or want to kick off yourself.
On a schedule
Run the automation on a recurring timetable using standard cron syntax. Nightly, hourly, “weekdays at 9 AM” (0 9 * * 1-5), the first of the month — whatever cadence the job needs. A built-in helper offers common presets so you don’t have to memorize cron. This is how you drive recurring processes like monthly reporting or first-of-the-month billing runs.
For simple time-based agent runs outside of Helix, see Schedules.
From a webhook
Start a run when an external system calls in. Helix gives the automation a secure webhook URL; when a request arrives, the run begins and the incoming payload is available to your steps. Use this to react to events from other tools — a GitHub push or pull request, a form backend, a payment processor, or any service that can send an HTTP request.
Filtering which requests start a run
Not every request to the webhook URL should necessarily start a run — a GitHub webhook fires for every push and PR event, but you might only want to react to pushes to your main branch, or PRs being opened. A filter lets you say which requests actually trigger a run; everything else is received and discarded.
A filter is a simple condition checked against the payload:
<path> <operator> <value>pathis a field in the incoming payload —action,ref,repository.full_name, and so on.operatoris one of a small set of comparisons:exists,contains,==, and similar.valuemust be a literal — a fixed string, number, or boolean you write into the filter. It can’t be a reference to another field in the payload; you’re comparing the field against a fixed value, not two fields against each other.
Two things trip people up when writing a filter:
Paths are not prefixed with
payload.. The filter evaluates directly against the payload’s own top-level fields, so writeaction == "opened"— notpayload.action == "opened". A path with apayload.prefix simply won’t match anything.
The right-hand side is always a literal.
ref == "refs/heads/main"is a valid filter; you can’t write something likeref == repository.default_branchto compare two fields against each other.
A GitHub PR-opened filter, for example, is just action == "opened"; a push-to-main filter is ref == "refs/heads/main".
Passing data into a run
However a run starts, its stimulus — the incoming payload, or the values you provide on demand — is available to your steps. A step can read fields straight from the stimulus, so a webhook body or a form submission flows directly into the pipeline.
Note: a
waitstep can also pause for an “event” mid-run — that’s a different thing from the stimulus that starts a run in the first place. See Wait steps for that distinction.
Coming soon: connector-event triggers, which start a run automatically when something happens in one of your connected tools — a new record, an inbound message, a completed signature. Until then, use a webhook to bridge external events into an automation.
See also: Building an Automation, Step Types, Schedules, Triggers