Skip to main content
Every task in a flow definition has an execution_type that controls when it runs once its step is reached. There are four models — and because runs are durable, a task can safely wait hours or days without losing progress. Every type except immediate requires an execution_config — omitting it is a validation error.

Immediate

The default. The task executes as soon as its step starts. You can omit execution_type entirely.

Scheduled

Delays execution using one of three schedule_type variants:
A delay variant looks like {"schedule_type": "delay", "delay": "30m"}; a fixed variant looks like {"schedule_type": "fixed", "run_at": "2026-08-01T09:00:00Z"}.
A cron scheduled task fires once, at the next occurrence within its execution. To run an entire definition on a repeating cadence, use a schedule instead.

Windowed

Restricts execution to a recurring time window — for example, only calling prospects during business hours. The config takes a timezone, a window with allowed days plus start_time/end_time (24-hour "HH:MM"), and an outside_window policy:

The window’s clock can follow the record

timezone takes either of two forms: A literal is checked when you save the definition: a name no runtime knows is refused with a 422 rather than surfacing hours later. An expression is not checked, because the value it produces does not exist yet.
A record whose zone will not resolve is neither failed nor quietly given the flow’s zone. If the expression resolves to nothing, or to something that is not a time-zone name, the task runs only during hours that are inside the window in every US time zone.That is a real window and the task really runs — just later in the day, because the overlap of every US zone is a few hours narrower than any one of them. Falling back to the flow’s own zone was the obvious alternative and is the wrong one: it would confidently apply a Denver window to somebody in Boston, which is exactly the mistake a per-record zone exists to prevent.
This is your own scheduling policy, and it is separate from the legal restriction on text messages — that one is enforced on the message itself when it is about to be sent, whether or not the task is windowed. Use windowed when you want to confine work to particular hours; quiet hours applies regardless.

Signaled

Pauses the task until an external signal arrives — a webhook callback or a polled condition — or a timeout elapses:
Timeout behavior in detail:
  • continue — the task resolves with on_timeout_output and the flow proceeds; downstream expressions can branch on it (e.g., an exit condition checking {{approval.wait_for_approval.output.approved}} == false).
  • abort_step — the task resolves with an error result, subject to its on_failure policy.
  • abort_execution — the whole execution fails.
To send a message and wait for a person to answer it, you do not compose a send step with a signaled step by hand. One task does both, with the correlation wiring done for you — see human in the loop. It runs on this same signaled wait and inherits every timeout policy above unchanged.

While a task is parked

Two of the four models above genuinely stop and wait: a windowed task with outside_window: schedule_next, and a signaled task waiting for its signal. While either is parked, its execution reports a distinct status rather than pretending to be busy: That matters because these waits are long by design. Before this status existed, a task parked for two days reported running the entire time — identical to one that was actually working — and there was no way to tell a slow run from a patient one. Two details worth knowing:
  • started_at is not re-stamped on resume. A two-day wait reads as a two-day run, with the real start preserved.
  • The job document stays started. Job statuses mirror only terminal execution states, and a pause is not an outcome. Read the execution to find out whether a run is parked.
Watching the stream shows the same transitions live: an execution.waiting frame on the way in and an execution.resumed frame on the way out. Neither is terminal, so a park never closes an open stream.
Execution models compose with the rest of the task surface: a windowed task can still be batched, and any model’s outcome can drive step exit conditions.