# Steps

URL: /workflows/steps · Id: `page:workflows/steps`

> A step calls one Verb as one Role; it names its id, what it waits for, and what happens when it fails, and the Verb decides the rest.

A step is one [Verb](/business/nouns/verb) called as one [Role](/business/nouns/role), inside a [Workflow](/business/nouns/workflow). It declares its id, its wait and its failure rule; the Verb decides its [Permission](/business/nouns/permission), its [Event](/business/nouns/event) and its approval.

## Fields
| Field | Holds | Default |
| --- | --- | --- |
| `id` | A stable slug, so an [Action](/business/nouns/action) resumes on the right step after a deploy | Required |
| `text` | The one sentence the [Process](/business/nouns/process) page prints | Required |
| `does` | The Verb it calls, such as `Invoice.collect` | None: a read or a branch |
| `by` | The Role whose Permissions and [Limits](/business/nouns/limit) the call runs under | The accountable Role |
| `approval` | Who says yes first: `none`, `ask` or `mandate` | Computed from the Verb |
| `waitsFor` | An Event to wait for before the step runs, with an optional `where` | None |
| `timeout` | How long it waits before its failure rule applies: `30m`, `4h`, `7d`, `2w` | None |
| `onFail` | `retry`, `escalate`, `compensate` or `fail` | `retry` |
| `compensate` | The Verb that undoes or remedies it; required by `onFail: compensate` | None |
| `exceptions` | Named outcomes that leave the happy path, each with `when` and an optional `continueAt` | None |
| `why` | Why the step exists, for the runbook | None |

## What a step can do
Every step is a Verb call, so the closed set of step kinds is the set of Verbs.

| To | Call | It waits as |
| --- | --- | --- |
| Write a record | Any Verb, such as [`Invoice.collect`](/business/nouns/invoice/collect) | Nothing, or its delay window when one-way |
| Ask a person and wait for the answer | [`Action.ask`](/business/nouns/action/ask), answered by [`Action.answer`](/business/nouns/action/answer) in any [Interface](/business/nouns/interface) | `pending`, `awaitingInput` |
| Get a yes past a Limit | [`Approval.create`](/business/nouns/approval/create) | `pending`, `awaitingInput` |
| Hand work to another Role | [`Task.delegate`](/business/nouns/task/delegate) | `pending`, `awaitingWorker` |
| Hand a problem up | [`Task.escalate`](/business/nouns/task/escalate) | `pending`, `awaitingWorker` |
| Send a message | [`Message.create`](/business/nouns/message/create) | Its delay window |
| Wait for something to happen | `waitsFor` an Event, capped by `timeout` | `pending`, `awaitingAction` |

A waiting step costs nothing, survives deploys, and shows its reason on the Action. In a [Workflow file](/code/file-conventions/workflows), `$.step`, `$.sleep` and `$.waitForEvent` write the same steps in code.

## Branches and failure
A step leaves the happy path in two ways. An exception is a known outcome: it names when it applies and the step to continue at, or ends the Action when it names none. A failure is anything else: the step retries with backoff, then follows its `onFail`.

[Dunning](/workflows/processes/billing/dunning) shows both. When the card on file has expired, the retry step's `cardExpired` exception skips ahead to telling the [Customer](/business/nouns/customer). When a retry fails for any other reason, the step tries again on the next day of the schedule.

| `onFail` | When retries run out |
| --- | --- |
| `retry` | Keeps retrying with backoff until `timeout`, then goes to the accountable Role |
| `escalate` | Becomes a [Task](/business/nouns/task) for the accountable Role, with the step's inputs |
| `compensate` | Calls the `compensate` Verb, such as [`Order.refund`](/business/nouns/order/refund) after a failed redo |
| `fail` | Ends the Action `failed`, with the reason on record |

## Three steps, one wait
A Workflow on `Quote.sent` waits a week for the buyer to accept, then wins the [Deal](/business/nouns/deal) and starts onboarding. If the week passes, the [Sales Lead](/agents/sales/sales-lead) gets the Deal as a Task.

```ts
import { $ } from 'startup-builder'

await $.Workflow.create({
  steps: [
    { id: 'accepted', text: 'Wait up to seven days for the buyer to accept.', waitsFor: { event: 'Quote.accepted' }, timeout: '7d', onFail: 'escalate', by: 'sales-lead' },
    { id: 'win', text: 'Mark the Deal won.', does: 'Deal.win', by: 'sales-lead' },
    { id: 'welcome', text: 'Send the buyer the onboarding link.', does: 'Message.create', by: 'onboarding-specialist' },
  ],
})
```

[How a Workflow runs](/workflows/how-workflows-run) covers approvals, service levels and turning a Process on or off. A [Trigger](/business/nouns/trigger) starts the first step, and [Triggers](/workflows/triggers) lists every kind.