Skip to content
The Whenever SDK is open source.Explore the SDK on GitHub
On this page

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.

BuilderShape 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.

Ready to deploy?