kortecxdocs

Trigger runs

Make a run start itself on a clock, or start it yourself when you choose, and rehearse a trigger before it goes live.

Most of the time you start a run yourself. A trigger removes you from that step. It binds a clock, or a fire you ask for, to something you have already built, so when it comes due Kortecx starts a fresh run on its own.

A trigger is the run's origin, not a different kind of run. The event takes the same path a manual start does, so approvals, the record you read afterwards and everything else behave identically. Whether a schedule fired it or you did, you get the same run, recorded the same way, and you can inspect it later.

The two kinds

KindWhat starts the runWho has to authenticate
crona clock — an interval in secondsnobody; the schedule runs inside the runtime
manualonly a fire you start yourselfyou, as an authenticated caller

Either kind can also be fired on demand by an authenticated caller, without opening anything new.

Every trigger points at exactly one target: a saved app.

The app runs unattended with the tools it names, the same way it runs when you start it by hand; an app that declares connections or a secret scope is refused, as a pressed run is. See Apps for what a saved app is, and Scheduled apps for the app-shaped version of this page.

Check that your target exists before you enable anything

A trigger binds to its target when it fires, not when you register it, so a misspelt app name or a connection that was never registered shows up as a failure at 09:00 on a Monday rather than at your keyboard.

A trigger on a clock

The clock is the simplest kind. There is no inbound network surface at all, so there is nothing to authenticate.

A clock's schedule is an interval in seconds — 3600 means "every hour".

It must be at least 30 seconds and at most 30 days, and it is counted in UTC. A 5-field crontab expression such as "0 9 * * 1-5" is refused by name, and there is no time-zone setting.

A scheduled tick carries no payload

When the clock fires a trigger, the runtime sends an empty payload ({}). There is no stored argument template. A saved app carries its own instructions, so it runs fine on an empty payload — which is why a clock points at an app. If your target needs an argument on every fire, put that instruction in the app rather than expecting the tick to supply it.

You can see your triggers in the console — which ones exist, what each points at, whether it is enabled, and the runs it has started.

A bad interval — under 30 seconds, over 30 days, or not a number — is rejected at the moment you register it, with an error naming the problem. You will not find out three days later that a typo meant nothing ever ran.

A trigger fires on the first tick after it comes due — the scheduler wakes every 30 seconds, and a fire that must start a connector first can take up to three minutes — so treat the schedule as "about then", not an exact moment. If a fire fails, that tick is missed and the next scheduled time is tried — a missed tick is not made up afterwards. After three scheduled fires in a row are refused, the trigger stops, and says why, until you save it again.

The idempotency key

Code that fires a trigger retries. If the network drops the response, your code assumes failure and fires the same event again. Without protection, one real-world event becomes two runs — and if the run sends a message or writes to a system of record, that is a duplicate that matters.

Every fire carries an idempotency key: a short string that identifies the event, not the request. The runtime remembers which run a key produced. A second event with the same key starts nothing and returns the first run's instance_id with "deduped": true.

A key comes from one of these:

  • Fresh, when you supply no key: each fire gets a new one, so two fires without a key are two runs.
  • From the schedule, for a cron trigger: the key is bound to the scheduled tick that made it due, so a retried or raced tick never fires twice.

This is what makes a retrying sender safe to point at something with real effects: one event is acted on exactly once, and sending it again is safe.

One caveat, honestly

Two fires with the same key arriving at the same instant can race, and both can start a run; the record keeps only one of them. It is a narrow window, but worth knowing about if your sender fans retries out in parallel.

Holding irreversible actions for a person

An unattended run has nobody watching it. A trigger can hold its runs for approval: read-only steps proceed on their own, and anything irreversible waits for an operator to grant it.

Turn this on for any scheduled app that can post, send, delete or pay. Approval works on an app with one tool-using step; with approval on, an app with more than one is refused when it fires. See Approvals for how a pending grant reaches you and how you answer it, and what you can rely on for the promise underneath it.

A trigger runs under the identity of whoever registered it — the same party that saved the app and registered its connections. Firing it can therefore never reach past what the registrant could do themselves. The trigger proposes; the runtime decides.

What cannot be a schedule target

An app you open in a browser carries no runnable plan of its own. It is served to a person, not scheduled. A trigger on one is refused by name when it fires.

Schedule an app that has a workflow to run instead — see Apps for the difference.

The same is true of an app whose connections were never registered: the trigger has nothing to resolve when it fires.

When it does not fire

What you seeThe usual cause
Nothing ever runsthe trigger is not enabled
Registration rejected the schedulean interval under 30 seconds or over 30 days, or a crontab expression
A fire fails every timethe app, one of its connections, or a secret it needs cannot be resolved