Skip to content

wait for

wait for

Suspend machine execution until an external event arrives. A wait for step pauses the current machine, serializes its state to the database, and resumes when a matching event or callback is received. This is the foundation for human-in-the-loop workflows, webhook callbacks, payment confirmations, approval gates, and any operation where the machine must yield control and resume later.

When to use

Use wait for when you need to:

  • Wait for a webhook callback (payment confirmation, CI result)
  • Implement human approval gates
  • Suspend for an external system to complete an async operation
  • Wait for a named event from another machine or system

Use ask ... from for synchronous calls that return immediately. Use launch to start async work you do not need to wait for. Use subscribes for event-driven reactive machines that process a continuous stream of events (rather than suspending mid-flow).

Syntax

wait for <name>
event: "<event_name>"
timeout: "<duration>"
on_timeout: flow(<flow_name>)
schema
<field> as <type>, <modifiers>

Callback variant

wait for <name>
callback: true
timeout: "<duration>"
on_timeout: flow(<flow_name>)
schema
<field> as <type>, <modifiers>

Configuration

ConfigRequiredDescription
eventYes (unless callback: true)The named event to wait for. Matched against incoming events.
callbackNoIf true, generates a unique resume URL. External systems POST to this URL to resume the machine.
timeoutNoMaximum wait duration (e.g., "24h", "7d", "30m"). If exceeded, the on_timeout flow runs.
on_timeoutNoFlow to execute if the timeout expires. Typically handles cancellation or cleanup.
schemaNoValidates the resume data structure before the machine continues. If validation fails, the resume is rejected.
channelNoSource channel for the event: "webhook", "chat", "api", etc.

Resume data access

After the machine resumes, the data from the event or callback is available as steps.<name>.<field>:

wait for approval
event: "approval_decision"
schema
approved as boolean, is required
reviewer as text
// After resume, access the data:
compute handle_decision
{
was_approved: steps.approval.approved,
who_approved: steps.approval.reviewer
}

Callback metadata

When using callback: true, the step exposes a resume URL before suspension:

FieldDescription
steps.<name>._resume_urlUnique URL for the external system to POST resume data
steps.<name>._resume_tokenThe token portion of the resume URL

Pass _resume_url to the external system so it knows where to send the callback.

Examples

Payment callback workflow

machine payment_workflow
accepts
order_id as text, is required
amount as number, is required
responds with
payment_status as text
payment_id as text
implements
action request_payment http
method: "POST"
url: "https://payments.example.com/charge"
body: {
order_id: input.order_id,
amount: input.amount,
callback_url: steps.wait_for_payment._resume_url
}
wait for wait_for_payment
callback: true
timeout: "24h"
on_timeout: flow(cancel_order)
schema
payment_id as text, is required
status as text, is required
compute result
{
payment_status: steps.wait_for_payment.status,
payment_id: steps.wait_for_payment.payment_id
}
flows
flow cancel_order
action notify call
machine: "@mashin/actions/notifications/send"
message: "Payment timed out for order " + input.order_id
compute result
{payment_status: "timed_out", payment_id: null}

Human approval gate

machine content_review
accepts
content as text, is required
author as text, is required
implements
ask pre_screen, using: "anthropic:claude-haiku-4"
with task "Check this content for policy violations.\n\nContent: ${input.content}"
returns
flags as list
auto_approve as boolean
assuming
flags: []
auto_approve: true
decide needs_review
when steps.pre_screen.auto_approve
compute auto_result
{approved: true, reviewer: "auto"}
otherwise
wait for human_review
channel: "chat"
timeout: "72h"
on_timeout: flow(escalate)
schema
approved as boolean, is required
reviewer as text, is required
notes as text
flows
flow escalate
launch notify_admin
machine: "@myorg/alerts/send"
message: "Content review timed out for " + input.author

Wait for named event

wait for ci_result
event: "ci.pipeline.complete"
timeout: "1h"
schema
passed as boolean, is required
build_id as text
test_count as number
failures as list

How suspension works

Machine Database External System
| | |
|-- wait for (suspend) ----->| |
| (serialize state) |-- store run state -------->|
| | (steps, context, position)|
| | |
| |<--- POST /resume/:token ---|
| | (validate schema) |
|<-- resume (deserialize) ---| |
| (continue next step) | |

The machine process shuts down during suspension. State is fully serialized to the database. When the resume event arrives, a new process is started with the deserialized state, and execution continues from the step after wait for.

Governance

Every wait for step is governed:

  1. Permission check: suspension and resumption are governed operations
  2. Behavioral ledger: the suspension event (including timeout, channel, and schema) is recorded
  3. Resume validation: the schema block validates incoming resume data before the machine continues. Invalid data is rejected.
  4. Timeout enforcement: if a timeout is configured, the runtime schedules a timeout check. When the timeout fires, the on_timeout flow runs under normal governance.

Suspended machines consume no runtime resources (no process, no memory). They exist only as serialized state in the database until resumed.

Translations

LanguageKeyword
Englishwait for
Spanishespera
Frenchattend
Germanwartet auf
Japanese待つ
Chinese等待
Korean기다리다

See also

  • launch - Start async work without waiting
  • decide - Branch on whether to suspend or continue
  • implements - The section where wait for steps live
  • subscribes - Continuous event processing (vs. one-shot suspension)