Workflow triggers
Choose manual runs, schedules, one-time runs and managed events with stable trigger keys.
Trigger builders
These go in the manifest, under triggers. Every one takes a required key: the trigger's stable identity, unique within the workflow, and what a run reads back as ctx.trigger.key.
| Builder | Shape and constraints |
|---|---|
manual({ key }) | Run on demand, with no automatic trigger. |
schedule(cron, { key, tz? }) | Five whitespace-separated cron fields, or @hourly / @daily / @weekly / @monthly. Six-field, seconds-granular cron is rejected. |
once(iso, { key }) | One absolute ISO 8601 instant, such as "2026-08-01T09:00:00Z". A bare time of day is rejected; the runtime enforces "still ahead". |
hourly({ key, minute?, tz? }) | minute is 0–59, default 0. |
daily({ key, at?, tz? }) | at is "HH:MM" on a 24-hour clock, default "00:00". Seconds are not accepted. |
weekly({ key, day?, at?, tz? }) | day is a lowercase weekday name, default "monday". |
monthly({ key, dayOfMonth?, at?, tz? }) | dayOfMonth is 1–31, default 1. A day past the end of a short month does not fire that month. |
every("<n>m" | "<n>h", { key, tz? }) | The interval has to divide its field evenly: minutes divide 60, hours divide 24. |
webhook({ key, name? }) | Unverified inbound HTTP: any request to the endpoint starts a run. The URL is bound to the key; name is display text only. |
event({ key, source, config? }) | A managed provider event, with source and config taken from Whenever's catalogue. |
A manual run carries the trigger the person chose, so a workflow with several triggers can tell every path apart by ctx.trigger.key. A managed event looks like event({ key: 'new-mail', source: 'gmail.new-gmail-message', config: { labels: ['INBOX'] } }), and its source and every config field come from the catalogue.
Choosing how a run starts
A scheduled poll starts a run even when the provider has no new records. An inbound webhook or managed event starts an execution when a qualifying delivery arrives. Neither approach implies a universal message-to-run conversion or polling cadence.
Use a stable key for each trigger and branch on ctx.trigger.type or ctx.trigger.key when different triggers need different logic. A schedule supplies no delivery body; do not assume ctx.input contains webhook data on that path.