> For the complete documentation index, see [llms.txt](https://docs.notionapps.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.notionapps.com/automation/workflow-foundation-user-guide.md).

# 🧱 Workflow Foundation User Guide

## Workflow Foundation User Guide

### Workflow Foundation User Guide

> Current state: Workflow Foundation is now documented as the workflow engine inside **Automation (Beta Testing)**. Use this guide for workflow mechanics, and use the NotionApps Automation Current State Guide for current packaging, entitlement, template, and live demo behavior.

![Workflow lifecycle concept](https://firebasestorage.googleapis.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5ZqDXcVVffWUqEIZVhmn%2Fuploads%2F4urhODnnDM3dMRty9kOg%2Fautomation-screen-workflow-status-builder-20260705.png?alt=media\&token=eaad7a58-d7af-4184-9a12-6e8044d4c354)

> Support visual: this image shows a workflow from trigger through steps, branches, waits, delivery, and activity history. Use it when explaining that Workflow is the runtime engine behind guided automation recipes.

This guide explains how to use the new Workflow Foundation features in both the app builder and the admin operations console. Makers own their workflows from the builder: they create, configure, publish, pause, resume, enable, disable, retry, and cancel their own app-scoped workflows. The admin console is a global support and operations tool for internal operators who need cross-app visibility, queue/worker health, entitlement support, and intervention when helping a maker.

For the complete cross-tool explanation, examples, support playbooks, and entitlement model, see the Automation, Workflow, and Messaging Support Handbook.

#### Table of Contents

1. [What Workflow Foundation Does](#what-workflow-foundation-does)
2. [Core Concepts](#core-concepts)
3. [Runtime Behavior](#runtime-behavior)
4. [Ownership Model](#ownership-model)
5. [Builder Guide](#builder-guide)
6. [Step Configuration Reference](#step-configuration-reference)
7. [Runs and Troubleshooting in the Builder](#runs-and-troubleshooting-in-the-builder)
8. [Admin Operations Guide](#admin-operations-guide)
9. [Admin Permissions and Audit Trail](#admin-permissions-and-audit-trail)
10. [Operational Playbooks](#operational-playbooks)
11. [Glossary](#glossary)

#### What Workflow Foundation Does

Workflow Foundation lets a maker define automations that react to app events, run a sequence of steps, and record operational state for every execution.

At a high level, a workflow answers four questions:

1. What starts the workflow?
2. Which app object should it listen to?
3. What steps should run?
4. How should the maker monitor and control runs?

The builder is the workflow control surface for a maker's own app. The admin feature focuses on cross-app support operations: global run inspection, queue health, worker heartbeats, entitlement support, and intervention when a maker needs help.

#### Core Concepts

**Entitlement**

An entitlement controls whether Workflow Foundation is available in the builder and whether workflow events can be ingested and executed for an application.

The effective entitlement is resolved in this order:

1. Application override.
2. Account override.
3. Subscription plan policy.
4. Legacy billing/default fallback.

An application override affects one application. An account override affects all applications owned by the selected account. A subscription plan policy defines the default Workflow Foundation policy for accounts on that billing tier.

In the builder, the `Workflows` menu item appears only when the effective entitlement allows builder access. If the menu is hidden, the app is not currently allowed to use the workflow builder. An admin or support operator should check the subscription policy, account override, or application override in Workflow Operations.

If a builder reaches the Workflow Foundation screen but builder access is blocked, the screen shows a disabled-state panel with the entitlement status, source, and scope. Admin Workflow Operations remains available for global support and inspection even when the builder is blocked.

When the builder is available, entitlement appears in the left workflow rail. It shows:

* Current status, such as `enabled`, `disabled`, `paused`, or `removed`.
* Source, such as `subscription`, `account`, `admin`, `request`, or `system`.
* Scope, such as subscription, account, or application.
* Workflow limit when one is present.

If entitlement is not enabled, saving, publishing, event ingestion, and workflow execution are blocked by the backend. This entitlement step is the product/billing gate; it is not where ordinary workflow control lives.

In admin, entitlement can be configured at subscription, account, or application level by an operator with manage permission when support, billing, or operations needs to intervene. Disabling entitlement sets a removal policy and retention window. Active workflow execution is stopped by entitlement checks.

Approval Management is a separate entitlement. Workflow Foundation can run normal process logic, record updates, waits, notifications, and messaging handoffs, but approval-specific setup requires Approval Management when the workflow uses:

* Decision screens.
* Work Queue screens.
* Approval recipes or guided workflow approval setup.
* Approval admin operations.

If a workflow route validates but an approval screen or approval setup is blocked, check **Admin -> Approval Management -> Access** before changing the workflow definition.

**Workflow**

A workflow is the named automation owned by one application. It has lifecycle states:

* `draft`: created or edited but not currently active.
* `active`: published and eligible to run.
* `paused`: intentionally stopped without being removed.
* `disabled`: disabled from the builder or by operations.
* `archived`: retained for historical state.

**Draft and Published Versions**

Workflow edits happen against a draft version. Publishing creates an immutable published version used by future runs.

This distinction matters:

* Editing a draft does not mutate queued or running executions.
* Publishing saves the current draft first, validates it, then creates the execution snapshot.
* A workflow can have a draft and a published version at the same time.

**Trigger**

The trigger defines the event that starts a workflow.

Visible trigger types in the builder are:

* `form_submitted`: starts when an end user submits a form in the app.
* `button_clicked`: starts from a configured app button action.
* `manual_start`: reserved for controlled starts through API/internal orchestration. Builders can also use `Test workflow` from the Activity screen to create a controlled test run for the selected active workflow.
* `record_created`: starts when a connected Notion record is created.
* `record_updated`: starts when a connected Notion record changes.
* `status_changed`: starts when a status field changes to a monitored value.
* `scheduled`: starts from a configured schedule.
* `webhook_received`: starts when an external service sends a webhook event.

**Target Type and Target**

The target type says what kind of app object the workflow is listening to. The target narrows the trigger to one specific object of that type.

In the builder, scoped targets are chosen with a searchable picker where possible. Makers can search by screen name, button label, data source name, or field name. The builder saves the object id and shows it as secondary reference detail for troubleshooting, support, and power-user JSON. Advanced users can paste a raw id when they are integrating with an object the picker cannot discover.

Examples:

* Target type `application`: listen across the app. Leave the target blank.
* Target type `screen`: listen to actions that happen on one screen. Search for and choose the screen; the builder saves the screen id and displays it as reference detail.
* Target type `button`: listen to one button click. Search for and choose the button; the builder saves the button component id and displays it as reference detail.
* Target type `form`: reserved for form-like events when a form id is available.
* Target type `data_source`: listen to one sheet/database source. Search for and choose the connected source; the builder saves the source id.
* Target type `record`: listen to one record id.

Publishing requires a concrete target for every scoped target type. If the target type is `screen`, `button`, `form`, `data_source`, or `record`, choose a target from the picker or paste an intentional advanced id before publishing. A scoped workflow without a target has nothing reliable to match when an app event arrives.

Button-click events also include the current screen id, so a workflow targeted to a screen can react to button clicks on that screen. Use a button target when only one button should trigger the workflow. Use a screen target when several actions on the same screen should share workflow behavior.

For the current live form-submission integration, use target type `screen` and choose the screen that owns the form. The builder may show a `form` target type for API/future form-specific events, but today's app form submissions are matched through the screen target.

**Context-Aware Pickers**

The workflow builder now tries to replace raw-id entry with app-aware pickers.

Picker behavior:

* Target picker suggestions change when the target type changes.
* Screen suggestions show app screen names and save the screen id.
* Button suggestions show button labels, the screen they live on, and save the button component id.
* Data source suggestions show connected sheets/databases and save the source id.
* Create record and Update record steps use a Data source picker, then narrow Field mapping suggestions to fields from that selected data source.
* Open screen, Show or hide control, and Refresh data steps use screen, control, and data-source pickers where the builder has enough app context.
* After a picker value is selected, the builder shows the friendly label plus the saved id as secondary reference detail.
* If an object is not discoverable yet, advanced users can paste a custom id. The picker marks that value as `Custom id`.
* Native automation screen configuration uses the same approach for source binding, action routing, and simulation fields.
* Hidden/internal screens are included when they are valid workflow or messaging destinations.

Normal makers should search and choose named objects. Raw ids are a fallback for advanced API, runtime, or support cases.

**Application Builder ID References**

Makers can also see the saved object ids directly in the application builder before they open Workflow Foundation.

Where to find them:

* Screen editor title bar: shows the current `Screen ID` as a copyable reference chip.
* Screen navigation/settings accordion: expand a screen to see `Screen ID` and `Data source ID` in the Workflow references panel.
* Component/control list: expand a control to see `Control ID`, the parent `Screen ID`, and `Field ID` when that control is tied to a data field.

Use these chips when support asks for a saved reference, when an advanced workflow value requires an id, or when you want to confirm that a workflow target points at the exact screen or control you intended.

**Native Automation Screens**

The application builder can add native automation screens that display Workflow and Messaging runtime state inside the app.

Available native screens:

| Screen               | Workflow use case                                                                    |
| -------------------- | ------------------------------------------------------------------------------------ |
| Work Queue           | Show tasks and follow-up work created by workflows.                                  |
| Decision             | Let a user approve, reject, or request changes when a workflow waits for a decision. |
| Workflow Status      | Show run state, steps, waits, retries, and outcomes.                                 |
| Conversation         | Show workflow-aware messages and replies.                                            |
| Exception Resolution | Let a person resolve failed steps or missing data.                                   |
| Notification Center  | Show notices and acknowledgements generated by workflows or messages.                |
| Automation Launcher  | Let a user manually start controlled workflows.                                      |
| Linked App Exchange  | Show app-to-app handoff requests and replies.                                        |
| Operator Console     | Show operational run, queue, failure, and audit summaries.                           |

For detailed screen-by-screen usage, configuration examples, and troubleshooting, see the Native Automation And Operational Screen Guides.

Conversation screens deserve one extra rule: use one conversation or correlation value for the business object under discussion. A timecard, support ticket, approval request, linked-app exchange, or workflow run should have a stable conversation identity. Workflow can create the item, Messaging can carry the request/reply events, and the Conversation screen can show a private readable discussion to the assigned participants.

Broadcasts are different. Use Messaging announcements or Notification Center when the message should go to every app user.

Decision and Work Queue screens are governed by Approval Management entitlement. A maker may have Workflow Foundation access and still be unable to add or run those approval screens until an admin enables the matching Approval Management flags.

Native screen setup has three important areas:

1. **Source binding**: choose whether the screen listens to the entire app, one screen/form, one workflow, one conversation/message route, or one linked application.
2. **Available actions**: choose after-action screens and target workflows from context-aware pickers.
3. **Empty state and simulation**: choose sample items and workflow runs so the builder can preview behavior before live traffic exists.

The screen picker uses distinct icons for every native screen type. The configuration page aligns labels, controls, and help text in form-style rows so builders can scan it like the rest of the builder.

Use Entire app only for broad surfaces such as Work Queue, Notification Center, Workflow Status, or Operator Console. Use specific source binding when the screen belongs to one form, workflow, channel/topic, conversation, or linked app exchange.

**Step**

A step is one action inside a workflow. The builder currently exposes these step types:

* Create record
* Update record
* Notify
* Open screen
* Show or hide control
* Refresh data
* Show message
* Stop action
* Condition
* Wait
* End

Steps run in order. The builder recalculates the `next_step_id` links when you add, remove, or drag steps in a linear workflow.

**Payload Path**

A payload path reads data from the event that started the run.

Payload paths use dot notation:

```
payload.record_id
payload.status
payload.email
context.account_id
context.application_id
```

The builder creates dynamic values for you when you choose `Event data` in a field mapping row. Behind the scenes, that saved configuration looks like this:

```json
{
  "value_type": "dynamic",
  "path": "payload.record_id"
}
```

**Power-User JSON**

Power-user JSON is the raw configuration for the selected step. Most builders should not need to type it for normal workflows because the guided controls create these structures automatically.

The guided fields are the source of truth for normal workflow creation. Use power-user JSON only for values not shown in the guided form, especially:

* Custom dynamic subjects and bodies.
* Advanced branch configuration through API-created workflow definitions.
* Unusual values that are not yet exposed in the guided builder.

The builder validates that power-user JSON is valid before saving.

**Dehydrate and Rehydrate**

Dehydrate means the workflow saves everything it needs to continue later. A Wait step uses this when the workflow needs to pause. The run stores the current context, the wait step that parked it, the normal next step, the timer wake-up time, and any timer escalation step.

Rehydrate means the workflow resumes from that saved context. Builders do not need to rebuild the payload or type JSON to rehydrate a run. When a run is in `waiting` status, the builder Activity screen shows a `Rehydrate` action for that selected run.

There are two rehydrate paths:

* Builder rehydrate: the maker clicks `Rehydrate` in Activity. The run immediately moves back to `queued` and resumes the normal next step.
* Timer rehydrate: the queue wakes the run when the Wait timer expires. If the Wait step has a timer escalation step, the run resumes at that escalation step. If there is no escalation step, it resumes the normal next step.

Use this pattern when work may need human intervention before a deadline. For example, a workflow can wait two hours for a reviewer to act. If the reviewer finishes early, the builder can rehydrate the run from Activity. If no one acts before the timer expires, the timer can escalate the run to a manager notification step.

#### Runtime Behavior

Workflow Foundation has two execution paths that work together.

The first path is the background worker path. When a matching event arrives, the backend creates a workflow run and queue work. Steps such as Create record, Update record, Notify, and Wait are handled by the worker because they may write data, call external systems, retry, or pause.

The second path is the live app interaction path. For form submissions and button clicks, the app can receive immediate UI actions while the background run is also created. The engine safely walks the early part of the workflow and returns UI actions for steps such as Open screen, Show or hide control, Refresh data, Show message, and Stop action.

Important ordering rule:

* Put Condition and UI response steps before heavy background steps when the app should react immediately.
* Once the inline path reaches Create record, Update record, Notify, Wait, or another background-only step, remaining work continues through the queue.
* For form submissions, the record save happens before workflow UI actions are applied. Stop action can suppress the app's default post-submit behavior, such as redirecting or clearing, but it does not undo the saved submission.

Wait steps create a durable pause in the background worker path. While the run waits, Activity shows the run as `waiting`, the timeline shows that the run was dehydrated, and the selected run can be cancelled or rehydrated by the builder. Rehydrating a run does not create a new run; it resumes the same run with the saved context.

#### Ownership Model

Workflow Foundation has two separate control surfaces.

**Builder: App-Scoped Owner Control**

The builder is where makers fully own workflows for their own app.

A builder can:

* Create workflows.
* Edit workflow names, triggers, target types, picker-selected targets, steps, guided configuration, and power-user JSON.
* Add, remove, and reorder steps.
* Save drafts.
* Publish active versions.
* Pause active workflows.
* Resume paused workflows.
* Enable disabled workflows.
* Disable workflows.
* Delete workflows from the builder when they should no longer be available.
* View recent runs for the selected workflow.
* Start a controlled test run for the selected active workflow.
* Inspect the selected run timeline step by step.
* Retry failed runs for the selected workflow.
* Rehydrate waiting runs for the selected workflow when the saved context should resume before the timer expires.
* Cancel active or waiting runs for the selected workflow.

The builder does not require access to the admin console for normal workflow ownership. Once the app is entitled to use Workflow Foundation, the maker should be able to build and operate their own workflows inside the builder.

**Admin: Global Support and Intervention**

The admin tool is not the maker's normal workflow editor.

Admin is used when internal operators need to:

* Look across all apps and accounts.
* Find a workflow run globally.
* Inspect queue depth and dead letters.
* Inspect worker/container heartbeats.
* Rehydrate a waiting run globally while helping a maker resume saved workflow state.
* Retry or cancel a run while helping a maker.
* Configure subscription plan policies, account overrides, and application overrides for support, billing, or operational reasons.
* Review running lists of explicit account overrides and application overrides.
* Record audited support actions.

Admin intervention should be the exception. Day-to-day workflow control belongs in the builder.

#### Builder Guide

**Opening Workflow Foundation**

1. Open an app in the builder.
2. Select `Workflows` from the builder sidebar.
3. If `Workflows` is not visible, the app does not currently have builder access. Ask an admin or support operator to review the subscription policy, account override, and application override in Workflow Operations.
4. The Workflow Foundation screen opens with a left workflow rail and seven workflow screens:

* `Overview`: start or continue workflow work through the progressive outcome-first home. New work begins with Outcome Builder; existing work shows setup, testing, validation, activity, or management.
* `Build`: create, configure, reorder, validate, and visually map workflow steps.
* `Data`: browse payload paths, context paths, step output paths, active screens, controls, data sources, and fields.
* `Simulate`: preview the workflow path with sample payload JSON before publishing or running a live test.
* `Activity`: monitor state, start a test run, inspect run timelines, retry failed runs, rehydrate waiting runs, and cancel active/waiting work.
* `Settings`: edit workflow details and control save, publish, pause, resume, enable, disable, and delete actions.
* `Help`: read workflow state definitions, run state definitions, step definitions, and action explanations.

**Automation Readiness Overlay**

Workflow Foundation can be opened directly, but non-technical makers should usually start in `Automation` when they only know the desired outcome.

Automation provides a progressive readiness path before the maker reaches advanced Workflow details:

* `Outcome Builder`: asks for the business outcome first.
* `What NotionApps will build`: appears after an outcome exists and explains the generated workflow, messaging, approval, screen, and test plan.
* `Plain-language setup`: appears when the route needs trigger, destination, action, audience/fallback, data requirements, or payload mapping without raw IDs.
* `Guided testing`: appears when setup is ready to prove with preview, real-user testing, and Activity.
* `Repair`: appears ahead of the normal path when access, validation, provisioning, approval setup, or generated object health is blocked.

Use this relationship this way:

| Builder need                                                   | Start in                           |
| -------------------------------------------------------------- | ---------------------------------- |
| "When this form is submitted, notify this person."             | Automation                         |
| "Create the common approval workflow for this button."         | Automation                         |
| "Edit the exact steps, conditions, waits, and field mappings." | Workflow Foundation                |
| "Inspect a run, retry, cancel, or rehydrate."                  | Workflow Foundation Activity       |
| "Explain why a generated route is blocked."                    | Automation Route map and Preflight |

Automation does not hide Workflow. It gives makers a safer first path and then opens Workflow for detailed tuning.

**Understanding the Builder Layout**

The builder page has these areas:

* `Workflows` rail: the left-side workflow control area. It contains the `New` action, entitlement status, a compact `Sections` toolbar, and a bounded `Your workflows` list.
* `Sections` toolbar: switches between `Overview`, `Build`, `Data`, `Simulate`, `Activity`, `Settings`, and `Help`. These buttons change the current workspace screen; they do not create or run workflows by themselves.
* `Your workflows` list: shows workflows for the current app only. The list has its own vertical scrollbar so many workflows do not make the whole builder page grow. Select a workflow row to make it the active workflow. Each row shows the workflow name, status, last update, and recipient preview when available.
* Top app bar: still shows the app identity and save state, but the app-level publish/share controls are hidden inside Workflow Foundation. Use the workflow `Publish` action in `Build` or `Settings`when you want the selected workflow to listen for events.
* Overview screen: shows the current required workflow step. It starts with Outcome Builder for new work, then reveals build-plan review, setup, testing, repair, or management. Detailed workflow state, validation, templates, and activity tools remain available after there is workflow work to manage.
* Build toolbar: workflow name and app-scoped lifecycle actions, including delete.
* Trigger bar: trigger type, target type, and context-aware target picker.
* Workflow guide: definitions for the selected trigger, selected step, payload path, and power-user JSON.
* Step palette: add available step types.
* Canvas: reorder and select workflow steps.
* Workflow data panel: shows saved workflow details for the selected workflow, including version, workflow id, trigger, target, target id, selected step id, notification recipients, record field mappings, condition count, step count, and screen/control actions.
* Inspector: configure the selected step.
* Validation panel: shows local or backend validation issues.
* Data screen: shows available `payload.*`, `context.*`, field-derived payload paths, previous-step output paths, active screens, controls, buttons, data sources, fields, and their saved ids. Click a path or id chip to copy it for advanced use or support reference.
* Simulate screen: accepts sample payload JSON and previews which steps would run. It evaluates simple condition rules locally, but it does not send email, call webhooks, write records, or create a real run.
* Activity screen: shows workflow state, active run state, run history, selected run details, step timeline, test run, retry, cancel, pause, resume, and disable controls.
* Settings screen: edits name and description, shows trigger/target/version metadata, and keeps lifecycle actions separate from the build canvas.
* Help screen: explains workflow states, run states, and builder actions without requiring admin access.

Only selectable or actionable items visually react when hovered, focused, dragged, or pressed. Examples include workflow rows, section buttons, step tiles, draggable steps, path-copy buttons, templates, and lifecycle action buttons. Passive information cards, definitions, metrics, timelines, and validation explanations use color grouping without hover feedback so they do not look clickable.

**Overview Screen**

Use Overview when you need orientation before editing. It is the safest first stop for a builder who is not sure what the workflow should do or what needs attention next.

Overview follows this progression:

1. **Outcome Builder** for brand-new workflow work.
2. **What NotionApps will build** after the maker describes the outcome.
3. **Finish the setup workspace** when the workflow draft still needs trigger, destination, data, recipient, timing, approval, or message details.
4. **Generate and test** when setup is ready to prove through simulation or Activity.
5. **No required action right now** when generated objects or recent workflow activity already exist.

Secondary tools such as Continue work, Guided path, and Manage / monitor appear only after there is workflow work to manage. Repair-first diagnostics can override the normal order when something must be fixed before the workflow can be trusted.

**Data Screen**

Use Data when a builder is unsure what can be used in a mapping, condition, record id field, or UI action.

Data includes:

* Common payload paths such as `payload.record_id`, `payload.email`, and `payload.status`.
* Payload paths derived from known fields in the selected app data sources.
* Workflow context paths such as rehydration metadata.
* Previous-step output paths such as `context.step_create_record.record_id`.
* Active screens only; removed screens are filtered out. Screen ids are visible as reference chips.
* Controls and buttons with friendly labels, screen names, control ids, and related screen ids.
* Data sources and fields with friendly names plus data-source and field ids.

The Data screen separates suggestions by category: payload, payload fields, workflow context, and workflow step output. Use those categories to understand where a value comes from before copying it into a mapping, condition, record id path, screen action, or power-user JSON.

Typing `payload` or `context` in guided path fields opens the same suggestion model inline. The Data screen is the larger browser for the same information.

**Simulate Screen**

Use Simulate before publishing when a workflow depends on payload values.

To simulate:

1. Open `Simulate`.
2. Paste sample event data into the payload editor.
3. Use a plain payload object, such as `{ "status": "approved" }`, or an object with explicit `payload` and `context` keys.
4. Review the previewed run path.
5. If a Condition step does not match, adjust either the sample payload or the rule in Build.

The simulator is intentionally local. It does not send notifications, call webhooks, write Notion records, or create a persistent workflow run. Use `Run live test` for an active workflow when you want a real run in Activity.

**Settings Screen**

Use Settings for workflow-level details and lifecycle actions.

Settings includes:

* Workflow name.
* Description.
* Version, trigger, target, and last-updated metadata.
* Save draft.
* Publish.
* Pause/resume or enable.
* Disable.
* Delete.
* Publish checklist with guided fixes.

**Entitlement Panel**

The entitlement panel is in the left rail after the builder has access to Workflow Foundation.

Use it to understand why the app can save and publish workflows.

If the `Workflows` menu item is missing, the builder has no workflow access for the current app. That usually means the effective subscription, account, or application entitlement is not enabled. The maker should contact the account owner, support team, or admin operator.

If the Workflow Foundation screen opens in a disabled state, review the blocked panel. It shows the entitlement status, source, and scope so an admin can tell whether the block came from a plan policy, account override, or application override.

If entitlement is enabled:

* New workflows can be created.
* Drafts can be saved.
* Workflows can be published.
* Active workflows can be paused.
* Paused workflows can be resumed.
* Disabled workflows can be enabled again.
* Workflows can be disabled.
* Workflows can be deleted from the builder.
* Runs can be created by event ingestion.
* Builders can start a controlled test run for an active published workflow.
* Failed runs can be retried from the builder.
* Waiting runs can be rehydrated from the builder.
* Active or waiting runs can be cancelled from the builder.

If the workflow uses approval-specific screens or approval setup, also confirm Approval Management is enabled for the app. The Workflow entitlement panel explains Workflow access; Approval Management access is shown from Automation Access and from the Admin Approval Management tool.

**Creating a New Workflow**

1. Click `New` in the workflow rail.
2. Find the new workflow in the `Your workflows` list and select it if it is not already selected.
3. Enter a workflow name.
4. Choose a trigger.
5. Choose a target type.
6. Search and choose a target when the target type is not `application`.
7. Add, remove, or reorder steps.
8. Configure each step in the inspector.
9. Fix validation issues.
10. Click `Save draft`.
11. Click `Publish` when ready.

No admin console access is needed for this normal maker flow.

The starter workflow contains:

* A notification step named `Notify reviewer`.
* An end step named `End workflow`.

This gives makers a safe initial shape: one action followed by completion.

**Naming a Workflow**

Use a short operational name that describes the event and outcome.

Good examples:

* `New lead notification`
* `Submitted intake follow-up`
* `Order status escalation`
* `Support request assignment`

Avoid names like `Test`, `Workflow 1`, or `Automation`, because they are hard to recognize in admin run lists.

Because the `Your workflows` list is compact, put the most distinguishing words first. For example, `Support escalation - overdue` is easier to scan than `Workflow for overdue support escalation`.

**Choosing a Trigger**

The trigger determines when a workflow starts.

Use this decision guide:

* Use `Form or screen submitted` when the workflow should start after a user saves, submits, updates, or deletes data from a screen.
* Use `Button or screen action` when the workflow should start from a workflow-aware button or a screen-level action selected by the builder. A workflow attached to a screen can now respond to the normal screen action path without the builder knowing backend event names.
* Use `Manual start` for controlled workflows that should not run automatically. Use `Test workflow` in Activity when you want to create a controlled test run for the selected active workflow.
* Use `Record created` when a new Notion record should start automation.
* Use `Record updated` when any change to a record should start automation.
* Use `Status changed` when only a status transition should matter.
* Use `Scheduled` for recurring or time-based workflows.
* Use `Webhook received` for external systems.

**Setting Target Type and Target**

Use target type and target together.

The Target field is searchable when the builder can discover matching app objects:

* Screen targets show app screens by name.
* Button targets show button controls by label and screen.
* Data source targets show connected sheets/databases by name.
* Form targets are advanced/API-only in the current builder runtime.
* Record targets still require a pasted id because record ids are runtime data.

Choose `application` when:

* The workflow is app-wide.
* You want one workflow to respond to many matching sources.
* You are still drafting and do not want to scope the workflow yet.

Leave the target blank for `application`.

Choose `screen` when:

* The workflow should react to form submissions from one screen.
* The workflow should react to button clicks or other interactions on one screen.
* Several controls on the same screen should share the same workflow behavior.

Search for and choose the screen. The builder saves the screen id and shows it as reference detail after selection. In the current runtime, form submissions are scoped to the screen that owns the form, not to a separate form id.

Choose `button` when:

* One specific button should start the workflow.

Search for and choose the button. The builder saves the button component id and shows it as reference detail after selection.

Choose `form` only when:

* You have a workflow event source that explicitly sends a form id.
* You are integrating through an API/future form-specific event path.

For normal app form submissions in the current runtime, choose `screen` instead.

Choose `data_source` when:

* A record-created, record-updated, or status-changed workflow should listen to one connected sheet or database.

Search for and choose the sheet/database. The builder saves the data source id and shows it as reference detail after selection.

Choose `record` only when:

* The workflow should be tied to one specific record id.

**Adding Steps**

The step palette appears above the canvas. Each tile describes what the step does.

To add a step:

1. Click the step tile.
2. The step is inserted before the terminal `End` step when possible.
3. The new step is selected in the inspector.
4. Configure required fields.

**Reordering Steps**

Drag a step on the canvas to reorder it.

When steps are reordered:

* The visual order changes immediately.
* The builder updates linear `next_step_id` links.
* The `then` and `done` indicators update based on whether another step follows.

**Selecting and Editing a Step**

Click a step on the canvas to open it in the inspector.

Above the step inspector, the builder shows `Workflow data` for the selected workflow. Use this summary to confirm saved configuration without opening every step:

* Version, trigger, target, and last updated time.
* Notification recipients, including the step and channel they came from.
* Record field mappings across Create record and Update record steps.
* Condition rule count and total step count.
* Screen and control actions such as Open screen, Show or hide control, and Refresh data.

This panel is especially useful when reopening an existing workflow because it exposes previous recipient, mapping, and UI-action data in one place.

The inspector shows:

* Step name.
* Step type.
* Guided config fields for supported common options.
* Visual mapping, recipient, rule, and wait controls where relevant.
* Collapsed power-user JSON for advanced extensions.
* Remove action.

**Removing a Step**

1. Select the step.
2. Click `Remove` in the inspector header.
3. The builder removes it from the draft.
4. Linear next-step links are recalculated.

Be careful removing an `End` step. A workflow can complete without an explicit end step if the final step has no next step, but an explicit end step is easier for makers and admins to read.

**Save Draft**

Click `Save draft` to persist the current workflow draft.

Saving requires:

* Workflow Foundation entitlement enabled for the app.
* Valid JSON in the selected step's power-user JSON panel, if it has been edited.
* A workflow name.

Saving does not activate the workflow. It only stores the draft.

**Publish**

Click `Publish` to make the workflow active.

Publishing does three things:

1. Saves the current draft.
2. Validates the workflow definition.
3. Creates an immutable published version for execution.

If validation fails, the workflow remains unpublished and the validation panel shows issues.

**Pause**

Click `Pause` to stop an active workflow without disabling or deleting it.

Paused workflows:

* Stay visible in the builder.
* Keep historical runs.
* Do not start new executions.
* Can be resumed later.

**Resume or Enable**

Click `Resume` when a workflow is paused. Click `Enable` when a workflow is disabled and should become active again.

Resume and Enable both move the workflow back to active status. New matching events can start runs again.

**Disable**

Click `Disable` to stop the workflow.

Disabled workflows:

* Stay visible.
* Retain historical state.
* Do not start new runs.
* Can be enabled again from the builder if the effective entitlement is still active.

**Delete**

Click `Delete` when a workflow should be removed from the builder instead of merely paused or disabled.

Delete asks for confirmation before it runs. After confirmation:

* The workflow is archived and no longer appears as an editable builder workflow.
* Workflow attachments are disabled so future matching events do not start it.
* Queued or retrying jobs for the workflow are cancelled.
* Queued, waiting, retrying, or paused runs are cancelled.
* Historical run records remain available for support and audit context.

Use Disable when the workflow may be needed again soon. Use Delete when the workflow should be retired from normal maker control.

#### Step Configuration Reference

This section is the builder-facing reference for every task step. Each step explains what the maker chooses in the guided UI, which saved ids are shown as reference details, what runtime parameters the step can read, what output is available to later steps, and a real example.

**How Steps Read Runtime Data**

Most builders should use the guided fields and pickers. Advanced builders can use dynamic values when a step needs data from the trigger event or from an earlier step.

Dynamic values have this shape:

```json
{
  "value_type": "dynamic",
  "path": "payload.email"
}
```

The `path` can start with:

* `payload`: data from the event that started the workflow.
* `context`: saved workflow context, including outputs from earlier successful steps.

Common trigger payload paths:

| Path                   | Meaning                                                                |
| ---------------------- | ---------------------------------------------------------------------- |
| `payload.record_id`    | Current record id when the event is tied to a row or submitted record. |
| `payload.screen_id`    | Screen where the app event happened.                                   |
| `payload.component_id` | Button or control that started the event, when present.                |
| `payload.action_id`    | Action identifier from the app event, when present.                    |
| `payload.user_email`   | Acting user's email, when the app provides it.                         |
| `payload.email`        | Submitted email field, when the form or event sends one.               |
| `payload.name`         | Submitted name field, when the form or event sends one.                |
| `payload.status`       | Submitted or changed status value, when the event sends one.           |
| `payload.priority`     | Submitted priority value, when the event sends one.                    |

The exact payload depends on the trigger source. The Activity screen is the best place to confirm what happened to a run. When a step uses a missing path, the resolved value is empty.

Every successful step that returns output is saved under `context.<step_id>`. Use the step id from the workflow definition or from the advanced JSON view.

Examples:

```
context.step_create_task.record_id
context.step_create_task.sheet_id
context.step_update_request.updated_count
context.step_notify_reviewer.delivery_status
context.step_wait_for_review.wait_until
context.step_priority_check.matched
```

This means a workflow can create a record in one step, then use that new record id in a later step:

```json
{
  "value_type": "dynamic",
  "path": "context.step_create_task.record_id"
}
```

If a waiting run is rehydrated from the builder, the builder also stores a small rehydrate payload under workflow context. Advanced users can inspect it through Activity and reference it as:

```
context.__workflow_rehydration.payload.source
context.__workflow_rehydration.payload.resumed_at
```

**Create Record**

Use Create record when the workflow should add a new row to a connected Notion database or app data source.

Builder fields:

* `Data source`: search by friendly data source name. The builder saves the `sheet_id` and displays it as reference detail.
* `Field mappings`: choose destination fields by name. For each row, choose `Event data` for a dynamic path or `Fixed value` for a literal value.

Parameters this step reads:

* `sheet_id`: the destination data source id selected by the picker.
* `fields`: destination field ids mapped to fixed values or dynamic values.
* Any `payload.*` or `context.*` paths used in the mapped values.

Output available to later steps:

| Context path                  | Meaning                                       |
| ----------------------------- | --------------------------------------------- |
| `context.<step_id>.record_id` | The new record id that was created.           |
| `context.<step_id>.sheet_id`  | The data source where the record was created. |

Example goal:

When a client intake form is submitted, create a follow-up task.

Guided setup:

1. Add `Create record`.
2. Choose the `Tasks` data source.
3. Add mappings:

| Destination field | Value source | Value/path      |
| ----------------- | ------------ | --------------- |
| `Task title`      | Event data   | `payload.name`  |
| `Client email`    | Event data   | `payload.email` |
| `Status`          | Fixed value  | `Open`          |

Power-user view:

```json
{
  "sheet_id": "64f000000000000000000101",
  "fields": {
    "fld_task_title": {
      "value_type": "dynamic",
      "path": "payload.name"
    },
    "fld_client_email": {
      "value_type": "dynamic",
      "path": "payload.email"
    },
    "fld_status": "Open"
  }
}
```

How to use the output:

If the next step should open the new task record, set that later step's record path to:

```
context.step_create_follow_up_task.record_id
```

**Update Record**

Use Update record when the workflow should change fields on an existing record.

Builder fields:

* `Data source`: search by friendly data source name. The builder saves the `sheet_id` and displays it as reference detail.
* `Record id path`: path to the record that should be updated. The most common value is `payload.record_id`.
* `Field mappings`: choose destination fields by name. Values can come from event data, earlier step output, or fixed values.

Parameters this step reads:

* `sheet_id`: selected data source id.
* `record_id`: dynamic value that points to the record id. If omitted, the executor falls back to `payload.record_id`.
* `fields`: destination field ids mapped to fixed values or dynamic values.

Output available to later steps:

| Context path                      | Meaning                           |
| --------------------------------- | --------------------------------- |
| `context.<step_id>.record_id`     | Record id that was updated.       |
| `context.<step_id>.sheet_id`      | Data source where the update ran. |
| `context.<step_id>.updated_count` | Number of records updated.        |

Example goal:

When a reviewer clicks `Mark reviewed`, update the current request.

Guided setup:

1. Add `Update record`.
2. Choose the `Requests` data source.
3. Set `Record id path` to `payload.record_id`.
4. Add mappings:

| Destination field | Value source | Value/path           |
| ----------------- | ------------ | -------------------- |
| `Status`          | Fixed value  | `Reviewed`           |
| `Reviewed by`     | Event data   | `payload.user_email` |

Power-user view:

```json
{
  "sheet_id": "64f000000000000000000202",
  "record_id": {
    "value_type": "dynamic",
    "path": "payload.record_id"
  },
  "fields": {
    "fld_status": "Reviewed",
    "fld_reviewed_by": {
      "value_type": "dynamic",
      "path": "payload.user_email"
    }
  }
}
```

Important notes:

* Missing record id fails the run because the executor cannot safely guess which row to update.
* Use the Activity timeline to confirm `updated_count`. A completed run with `updated_count: 0`means the step ran but did not update a matching row.

**Notify**

Use Notify when the workflow should send an email or call a webhook endpoint.

Builder fields:

* `Channel`: choose `Email` or `Webhook`.
* `Recipients` or `Endpoints`: for email, enter email addresses. For webhook, enter HTTP or HTTPS endpoint URLs.
* `Subject`: short message subject.
* `Body`: message body. For webhook, this becomes the `body` field inside the posted JSON payload.

Parameters this step reads:

* `channel`: `email` or `webhook`.
* `recipients`: email addresses or webhook endpoint URLs.
* `subject`: fixed text or advanced dynamic value.
* `body`: fixed text or advanced dynamic value.

Default behavior:

* Email is the default Notify channel.
* If an older, cloned, or template-provisioned Notify step does not explicitly store `channel`, Workflow Foundation treats it as `email`.
* When the maker saves or publishes from the builder, the Email default is written into the workflow so the dropdown and saved JSON agree.

Output available to later steps:

| Context path                         | Meaning                                                 |
| ------------------------------------ | ------------------------------------------------------- |
| `context.<step_id>.channel`          | Delivery channel used.                                  |
| `context.<step_id>.recipient_count`  | Number of recipients or endpoints.                      |
| `context.<step_id>.sent`             | `true` when the provider or webhook was called.         |
| `context.<step_id>.simulated`        | `true` when local development simulated email delivery. |
| `context.<step_id>.delivery_status`  | `sent` or `simulated`.                                  |
| `context.<step_id>.delivery_message` | Safe delivery summary shown in Activity.                |

Email example:

```json
{
  "channel": "email",
  "recipients": ["reviewer@example.com"],
  "subject": "New intake received",
  "body": "A new intake form was submitted. Please review it."
}
```

Dynamic subject/body example:

```json
{
  "channel": "email",
  "recipients": ["reviewer@example.com"],
  "subject": {
    "value_type": "dynamic",
    "path": "payload.title"
  },
  "body": {
    "value_type": "dynamic",
    "path": "payload.summary"
  }
}
```

Webhook example:

```json
{
  "channel": "webhook",
  "recipients": ["https://example.com/workflow-webhook"],
  "subject": "Workflow event",
  "body": "A request changed status."
}
```

Webhook request body:

When `channel` is `webhook`, Workflow Foundation sends a POST request to each endpoint. The payload includes:

```json
{
  "workflow_id": "workflow_id_here",
  "workflow_version_id": "version_id_here",
  "run_id": "run_id_here",
  "application_id": "application_id_here",
  "account_id": "account_id_here",
  "subject": "Workflow event",
  "body": "A request changed status.",
  "trigger_payload": {},
  "context": {}
}
```

Important notes:

* SMS is stubbed for the first version. Existing SMS configs fail validation and execution with `sms_notification_stubbed`. Choose Email or Webhook.
* In local development, email is simulated. The workflow can complete and Activity will show `delivery_status: simulated`, but no email leaves the system.
* Webhooks are attempted as real HTTP calls, including local development.
* Email or webhook delivery failures are retryable. Fix the recipient, endpoint, provider, or network issue, then retry from Activity.

**Open Screen**

Use Open screen when a live app interaction should navigate the current user to another app screen.

Builder fields:

* `Screen`: search by friendly screen name. The builder saves the `screen_id` and displays it as reference detail.
* `Record id path`: optional path to the record that the destination screen should open around. The default is `payload.record_id`.

Parameters this step reads:

* `screen_id`: destination screen id selected by the picker.
* `record_id`: optional dynamic path. Most workflows use `payload.record_id` or a record created by an earlier step, such as `context.step_create_task.record_id`.

Output available to later steps:

| Context path                                  | Meaning                                       |
| --------------------------------------------- | --------------------------------------------- |
| `context.<step_id>.ui_actions[0].type`        | `open_screen`.                                |
| `context.<step_id>.ui_actions[0].screen_id`   | Screen requested by the workflow.             |
| `context.<step_id>.ui_actions[0].record_id`   | Record id passed to the screen, when present. |
| `context.<step_id>.ui_action_delivery_status` | `returned_to_client` or `background_only`.    |

Example goal:

After a user clicks `Submit for review`, open the review detail screen for the current record.

Power-user view:

```json
{
  "screen_id": "screen_review_detail_001",
  "record_id": {
    "value_type": "dynamic",
    "path": "payload.record_id"
  }
}
```

Important notes:

* Put Open screen before Notify, Wait, Create record, or Update record when the user should navigate immediately during the same browser interaction.
* If this step runs later in the background worker, Activity records the UI action, but the user's current browser session is no longer available to update.

**Show or Hide Control**

Use Show or hide control when a workflow should reveal or hide a specific app control in the current user session.

Builder fields:

* `Control`: search by friendly control label. Suggestions show the control type and screen.
* `Visibility`: choose `Show control` or `Hide control`.
* `Screen`: optional screen picker. Leave blank to apply to the current screen.

Parameters this step reads:

* `control_id`: selected component/control id.
* `visible`: `true` to show the control, `false` to hide it.
* `screen_id`: optional screen scope.

Output available to later steps:

| Context path                                  | Meaning                                    |
| --------------------------------------------- | ------------------------------------------ |
| `context.<step_id>.ui_actions[0].type`        | `set_control_visibility`.                  |
| `context.<step_id>.ui_actions[0].control_id`  | Control affected by the workflow.          |
| `context.<step_id>.ui_actions[0].visible`     | Whether the control should be visible.     |
| `context.<step_id>.ui_action_delivery_status` | `returned_to_client` or `background_only`. |

Example goal:

When priority is `High`, reveal the `Reviewer notes` field.

Power-user view:

```json
{
  "control_id": "comp_reviewer_notes_001",
  "visible": true,
  "screen_id": "screen_review_detail_001"
}
```

Important notes:

* Use the optional Screen picker to narrow the Control list before searching.
* Like Open screen, this step must run in the inline part of the workflow to affect the current user immediately.

**Refresh Data**

Use Refresh data when a live interaction should reload app data after the workflow changes or checks something.

Builder fields:

* `Screen`: optional screen picker. Leave blank for the current screen.
* `Data source`: optional data source picker. Use it when only one data source needs refresh.

Parameters this step reads:

* `screen_id`: optional target screen.
* `sheet_id`: optional data source id.

Output available to later steps:

| Context path                                  | Meaning                                          |
| --------------------------------------------- | ------------------------------------------------ |
| `context.<step_id>.ui_actions[0].type`        | `refresh_data`.                                  |
| `context.<step_id>.ui_actions[0].screen_id`   | Screen requested for refresh, when present.      |
| `context.<step_id>.ui_actions[0].sheet_id`    | Data source requested for refresh, when present. |
| `context.<step_id>.ui_action_delivery_status` | `returned_to_client` or `background_only`.       |

Example goal:

After a user approves a request, refresh the request list.

Power-user view:

```json
{
  "screen_id": "screen_requests_001",
  "sheet_id": "64f000000000000000000202"
}
```

Important notes:

* Refresh data does not write anything by itself. It tells the live app to reload data it already knows how to display.
* Put it after the step that changes the data if both steps are part of the live response path. If the change happens in the background, the refresh action may only be recorded in Activity.

**Show Message**

Use Show message when the workflow should show a brief confirmation, warning, or error-like message to the current user.

Builder fields:

* `Message`: text shown to the user.
* `Tone`: `Info`, `Success`, `Warning`, or `Error`.

Parameters this step reads:

* `message`: fixed text or advanced dynamic value.
* `tone`: optional display tone.

Output available to later steps:

| Context path                                  | Meaning                                    |
| --------------------------------------------- | ------------------------------------------ |
| `context.<step_id>.ui_actions[0].type`        | `show_message`.                            |
| `context.<step_id>.ui_actions[0].message`     | Message requested by the workflow.         |
| `context.<step_id>.ui_actions[0].tone`        | Message tone, when present.                |
| `context.<step_id>.ui_action_delivery_status` | `returned_to_client` or `background_only`. |

Example goal:

After a user submits a review request, show a success message.

Power-user view:

```json
{
  "message": "This request was sent for review.",
  "tone": "success"
}
```

Important notes:

* Keep messages short. Long workflow explanations belong in app content or documentation.
* Put Show message before background-only steps when the message must appear immediately.

**Stop Action**

Use Stop action when the workflow should stop the app's default behavior after a live form or button interaction.

Builder fields:

* `Message`: optional text explaining why the default action stopped.

Parameters this step reads:

* `message`: optional fixed text or advanced dynamic value.

Output available to later steps:

| Context path                                  | Meaning                                          |
| --------------------------------------------- | ------------------------------------------------ |
| `context.<step_id>.ui_actions[0].type`        | `block_interaction`.                             |
| `context.<step_id>.ui_actions[0].message`     | Message requested by the workflow, when present. |
| `context.<step_id>.ui_action_delivery_status` | `returned_to_client` or `background_only`.       |

Example goal:

When a required priority is missing, stop the default button action and tell the user what to fix.

Power-user view:

```json
{
  "message": "Choose a priority before sending this request for review."
}
```

Important notes:

* For button clicks, Stop action prevents the normal button behavior from continuing.
* For form submissions, the record save has already completed. Stop action prevents default post-submit behavior such as redirecting or clearing after the workflow response is applied.
* Stop action only affects the current interaction when it is reached in the inline path.

**Condition**

Use Condition when the workflow should evaluate rules against event data or earlier step output.

Builder fields:

* `Rules`: each rule has a payload/context path, comparison operator, and optional compare value.

Parameters this step reads:

* `rules`: array of rules.
* Each rule's `field` path can read `payload.*` or `context.*`.
* Each rule's `value` is the value to compare against when the operator needs one.

Output available to later steps:

| Context path                | Meaning                        |
| --------------------------- | ------------------------------ |
| `context.<step_id>.matched` | `true` when all rules matched. |

Supported operators:

* `equals`
* `not_equals`
* `contains`
* `is_empty`
* `is_not_empty`
* `greater_than`
* `less_than`
* `before`
* `after`

Example goal:

Only treat requests with priority `High` as high-priority work.

Power-user view:

```json
{
  "rules": [
    {
      "field": "payload.priority",
      "operator": "equals",
      "value": "High"
    }
  ]
}
```

Example using earlier step output:

```json
{
  "rules": [
    {
      "field": "context.step_update_request.updated_count",
      "operator": "greater_than",
      "value": 0
    }
  ]
}
```

Important notes:

* Multiple rules must all match.
* A plain linear Condition step records `matched` and continues to the normal next step.
* Conditional routing requires branch configuration on the workflow step. When no branch matches, the executor uses the normal `next_step_id`.

**Wait**

Use Wait when the workflow should pause, save its current context, and continue later.

Builder fields:

* `Delay seconds`: relative wait duration. For example, `3600` means one hour.
* `Wait until`: optional absolute ISO date/time, such as `2026-07-01T14:00:00.000Z`.
* `Timer escalation step`: optional step to run if the timer expires before a builder rehydrates the run.

Parameters this step reads:

* `delay_seconds`: relative duration in seconds.
* `until`: absolute resume time.
* `escalation_step_id`: optional step id selected from the workflow.

Output available to later steps and Activity:

| Context path                           | Meaning                                                |
| -------------------------------------- | ------------------------------------------------------ |
| `context.<step_id>.wait_until`         | Date/time when the timer can wake the run.             |
| `context.<step_id>.dehydrated`         | `true` when the run saved state and entered waiting.   |
| `context.<step_id>.resume_step_id`     | Normal next step for manual/builder rehydrate.         |
| `context.<step_id>.escalation_step_id` | Escalation step used by timer rehydrate, when present. |
| `context.<step_id>.timer_behavior`     | `continue` or `escalate`.                              |

Delay example:

```json
{
  "delay_seconds": 86400
}
```

Specific-date example:

```json
{
  "until": "2026-07-01T14:00:00.000Z"
}
```

Escalation example:

```json
{
  "delay_seconds": 7200,
  "escalation_step_id": "step_notify_manager"
}
```

How dehydration works:

1. The worker reaches Wait.
2. The run stores the current `payload`, `context`, wait step id, normal next step, timer wake-up time, and optional escalation step.
3. The run moves to `waiting`.
4. Activity shows the run as waiting and enables `Rehydrate`.

How rehydration works:

* If a builder clicks `Rehydrate` before the timer expires, the run resumes the normal next step and does not use the escalation step.
* If the timer expires first and an escalation step is configured, the run resumes at the escalation step.
* If the timer expires first and no escalation step is configured, the run resumes the normal next step.

**End**

Use End to make the completion point explicit.

Builder fields:

* End has no required fields.

Parameters this step reads:

* None.

Output available to later steps:

* End does not add output.

Power-user view:

```json
{}
```

Important notes:

* End is useful for readability in the canvas and Activity timeline.
* A workflow can also complete when the last step has no next step, but an explicit End step makes the intended finish clearer for builders and support operators.

#### Validation

The builder shows validation in the right panel.

Validation checks include:

* Workflow name is present.
* Trigger is present.
* At least one step exists.
* Every step has a stable id.
* Every step has a plain-language name.
* Step types are supported.
* Step references point to existing steps.
* Cycles are rejected.
* A completion path exists.
* Required step config is present.

Some validation happens locally in the browser for fast feedback. Backend validation runs on publish and is authoritative.

If the workflow was created by Automation, also review Automation Route map before publishing. Workflow validation checks the selected workflow definition. Automation preview checks the larger route: recipe readiness, entitlement blockers, Messaging contract/subscriber state, generated object plan, and support-bundle context.

Common validation messages:

* `Workflow name is required.`
* `At least one step is required.`
* `Step name is required.`
* `Create record step needs sheet_id and fields.`
* `Update record step needs sheet_id and fields.`
* `Open screen step needs screen_id.`
* `Control visibility step needs control_id and visible.`
* `Show message step needs message.`
* `Condition step needs rules.`
* `Wait step needs delay_seconds or until.`
* `Workflow needs a defined completion path.`

#### Runs and Troubleshooting in the Builder

The builder Activity screen is the normal place a maker controls their own workflow executions. The admin console is only needed when support must look globally, inspect queue/worker health, or intervene beyond the app-scoped builder view.

**Activity Screen**

The Activity screen shows the operational state for the selected workflow.

It includes:

* Workflow state: draft, active, paused, disabled, or archived.
* Live run: the newest queued, running, waiting, retrying, or paused run when one exists.
* Recent run counts: total, completed, failed, and active.
* Published version: the version currently used by app events.
* Run history: recent executions for the selected workflow.
* Selected run details: status, current step, started time, finished time, retry count, and safe error summary.
* Step timeline: every recorded step attempt, status, timestamps, safe errors, and output snapshot when available.
* Actions: `Test workflow`, `Refresh`, `Pause`/`Resume`, `Disable`, `Retry`, `Rehydrate`, and `Cancel` where allowed.

**Starting a Test Run**

Use `Test workflow` when you want to confirm that the selected published workflow can create and process a run without waiting for a real user event.

Requirements:

* The app must have Workflow Foundation entitlement enabled.
* The selected workflow must be published and `active`.
* The workflow must have valid published steps.

What happens:

1. The builder creates a run for the selected workflow only.
2. The run receives a small builder-test payload.
3. The run appears in Activity with status `queued`.
4. The worker picks it up and moves it through `running`, `waiting`, `completed`, or `failed`depending on the workflow steps.
5. Refresh Activity to watch the state change.

This is different from sending a broad app interaction event. `Test workflow` targets the selected workflow directly so a test for one app-wide workflow does not accidentally create runs for every matching workflow in the app.

When the workflow came from an Automation recipe, complete the Automation Guided testing path as well:

1. Run Automation preview.
2. Fix route blockers.
3. Generate or confirm generated objects.
4. Test as the app user who should trigger the workflow.
5. Confirm the Workflow Activity run and any Messaging Activity delivery tied to it.

**Run Statuses**

Possible run statuses:

* `queued`: run has been created and is waiting for a worker.
* `running`: worker is executing a step.
* `waiting`: run is paused by a wait step and its context is saved so it can resume later.
* `retrying`: run is being retried after a retryable failure.
* `completed`: run finished successfully.
* `failed`: run failed.
* `cancelled`: run was cancelled.
* `paused`: run is paused by state transition.

**Rehydrating a Run in the Builder**

Use Rehydrate when:

* The selected run is in `waiting` status.
* The Wait step intentionally parked the run, but the work is ready to continue now.
* You want the run to resume from the saved context instead of waiting for the timer.

Rehydrate is available in the selected run header on the Activity screen. After it is clicked, the run moves back to `queued`, keeps the same run id, keeps the saved context, and resumes from the normal next step. If the Wait step had a timer escalation step, builder rehydrate does not use that escalation path because the timer did not expire.

If no builder rehydrates the run and the timer expires, the queue rehydrates the run automatically. When a timer escalation step is configured, the timer path resumes at the escalation step. When no timer escalation step is configured, the timer path resumes the normal next step.

**Retrying a Run in the Builder**

Use Retry when:

* The run failed.
* The underlying issue is likely temporary.
* You fixed the configuration or dependency that caused the failure.

The builder only enables retry for failed runs.

Retry is available in the selected run header on the Activity screen. After retry is clicked, the run is queued again and the timeline records the later attempt.

**Cancelling a Run in the Builder**

Use Cancel when:

* The run is still active.
* It should not continue.
* A wait step or queue delay means it would otherwise resume later.

Cancel is available for queued, running, waiting, retrying, or paused runs. Cancel is disabled for completed, failed, and already cancelled runs.

**Refreshing Runs**

Click `Refresh` in Activity to reload run history and selected run details.

Use it after:

* Publishing a workflow.
* Triggering a workflow event.
* Starting a test run.
* Retrying or cancelling a run.
* Retrying a failed run.
* Cancelling an active run.

#### Admin Operations Guide

**Opening Workflow Operations**

1. Open the admin console.
2. Go to `Workflow Operations`.
3. The tool loads summary metrics, runs, queue jobs, worker heartbeats, and entitlement controls.

The admin tool is intended for internal operators, not app makers. It provides global visibility and support intervention. It is not required for a builder to create, publish, pause, resume, enable, disable, delete, retry, or cancel workflows in their own app.

**Required Admin Permissions**

To view Workflow Operations, an admin needs:

* `admin.panel.view`
* `admin.workflows.view`

To retry runs, cancel runs, or change entitlement, an admin also needs:

* `admin.workflows.manage`

The workflow operations admin role bundle also includes:

* `admin.audit.view`

**Summary Metrics**

The top metrics show current system health:

* `Active workflows`: number of active workflow definitions.
* `Failed runs`: number of runs currently failed.
* `Queued jobs`: current queue depth.
* `Dead letters`: queue jobs that exhausted retry handling.
* `Unhealthy workers`: workers that are unhealthy or stale.

Use these metrics as the first triage view.

**Runs Panel**

The Runs panel lists recent workflow runs.

Controls:

* Text search field for workflow/app/account/event lookup where supported by the backend.
* Status dropdown.
* Search button.

Statuses:

* `all`
* `queued`
* `running`
* `waiting`
* `retrying`
* `completed`
* `failed`
* `cancelled`
* `paused`

Columns:

* `Status`: run status.
* `Workflow`: workflow name or workflow id.
* `Application`: application name, URI, or id.
* `Event`: trigger event id or trigger type.
* `Updated`: last update or creation timestamp.

Click a run row to load its detail.

**Run Detail Panel**

The Run Detail panel shows:

* Run status.
* Workflow name or id.
* Error summary.
* Internal action reason field.
* Retry action.
* Cancel action.
* Step-by-step execution detail.

The step list shows each step status and either the error message or step type.

Step statuses:

* `pending`
* `running`
* `succeeded`
* `failed`
* `skipped`
* `waiting`
* `retrying`

**Admin Retry**

Use admin Retry when a failed run should be requeued as part of a support intervention. Makers can retry their own failed workflow runs from the builder Activity screen.

Requirements:

* Admin has `admin.workflows.manage`.
* A run is selected.
* Run status is `failed`.
* Internal action reason has at least 8 characters.

Retry records an audit event:

```
admin.workflow_run.retry_requested
```

Retry also refreshes the admin summary, runs list, queue list, and containers.

**Admin Rehydrate**

Use admin Rehydrate when a waiting run should resume from saved context as part of a support intervention. Makers can rehydrate their own waiting workflow runs from the builder Activity screen.

Requirements:

* Admin has `admin.workflows.manage`.
* A run is selected.
* Run status is `waiting`.
* Internal action reason has at least 8 characters.

Rehydrate records an audit event:

```
admin.workflow_run.rehydrated
```

When admin Rehydrate runs:

* The run keeps the same run id.
* The saved context is marked as rehydrated by `admin`.
* The run moves back to `queued`.
* The queue job becomes available immediately.

**Admin Cancel**

Use admin Cancel when an active run should stop as part of a support intervention. Makers can cancel their own active or waiting workflow runs from the builder Activity screen.

Requirements:

* Admin has `admin.workflows.manage`.
* A run is selected.
* Run status is not `completed`, `failed`, or `cancelled`.
* Internal action reason has at least 8 characters.

Cancel records an audit event:

```
admin.workflow_run.cancelled
```

**Queue Panel**

The Queue panel shows queue jobs.

Controls:

* Status dropdown.

Statuses:

* `all`
* `queued`
* `running`
* `retrying`
* `completed`
* `failed`
* `dead_letter`
* `cancelled`

Columns:

* `Status`: queue job status.
* `Attempts`: attempts used out of max attempts.
* `Run`: workflow run id.
* `Available`: when the job is available for processing.
* `Error`: last safe error message.

Use this panel to distinguish between:

* A failed run with no queue job.
* A run waiting for retry.
* A queue backlog.
* A dead-lettered job.

**Containers Panel**

The Containers panel shows worker heartbeat records.

Each worker card shows:

* Worker id.
* Status or stale indicator.
* Container id.
* Queue depth.
* Heartbeat timestamp.

Worker statuses:

* `ready`: worker is available.
* `busy`: worker is processing.
* `draining`: worker is shutting down or draining work.
* `unhealthy`: worker reported unhealthy state.
* `stale`: heartbeat is older than the allowed heartbeat window.

Use `Refresh` in this panel to reload worker state.

**Entitlement Panel**

The Entitlement panel allows operators to configure Workflow Foundation access at three levels:

* Subscription plan policy: the default Workflow Foundation policy for each subscription tier.
* Account override: an account-level override that can enable, disable, and cap workflow usage for a customer account.
* Application override: an app-level control that can enable or disable Workflow Foundation for one application.

Entitlement precedence is application override, then account override, then subscription plan policy. Use an application override for one app-specific exception. Use an account override when the same decision or cap should apply to every app owned by the customer account. Use subscription plan policy for the default business rule for a billing tier.

The subscription plan policy and account entitlement forms include an `Entitlement period` selector.

Entitlement period options:

* `Billing period`: limits follow the account subscription billing cycle.
* `Monthly`: execution limits use a monthly window.
* `Annual`: execution limits use an annual window.

Use `Billing period` when Workflow Foundation usage should match the customer's paid subscription cadence. Use `Monthly` or `Annual` when the business policy should reset on a fixed Workflow Foundation entitlement window regardless of the subscription billing cadence.

The period is especially important for the execution cap. If a plan has an execution cap of `5,000` and the period is `Monthly`, the account is allowed up to 5,000 workflow runs in the monthly entitlement window. If the period is `Annual`, the same cap applies across the annual entitlement window.

The workflow cap is the number of non-deleted workflow definitions an account can own at one time. The entitlement period is still shown beside the workflow cap so operators can understand the full policy window that applies to the subscription or account, but the workflow cap itself is not a run counter.

To configure subscription plan policy:

1. Open the `Entitlements` screen in Workflow Operations.
2. Review each subscription tier. The friendly tier name appears in parentheses, such as `TIER2_05_2025 (Pro)`.
3. Choose whether Workflow Foundation is enabled by default for that plan.
4. Select the entitlement period.
5. Enter the workflow cap, or leave it blank for unlimited workflow definitions.
6. Enter the execution cap, or leave it blank for unlimited workflow runs during the selected period.
7. Click `Save subscription policy`.

To configure an account entitlement:

1. Search and select the account.
2. Choose whether the account should be enabled or disabled.
3. Select the account entitlement period.
4. Enter an account workflow cap if the account should override the subscription default.
5. Enter an account execution cap if the account should override the subscription default.
6. Enter an internal account entitlement reason with at least 8 characters.
7. Click `Enable account` or `Disable account`.

The account override form keeps `Entitlement period`, `Workflow cap`, and `Execution cap` aligned in one row when space allows, and wraps them into stacked fields on narrower screens. The period controls the reset window for the execution cap. The workflow cap is a maximum number of non-deleted workflow definitions owned at one time.

To enable application entitlement:

1. Search and select an application.
2. Enter an internal entitlement reason with at least 8 characters.
3. Click `Enable`.

To disable application entitlement:

1. Search and select an application.
2. Enter an internal entitlement reason with at least 8 characters.
3. Click `Disable`.

To review active override records:

1. Open the `Entitlements` screen in Workflow Operations.
2. Find `Active entitlement overrides`.
3. Review `Account overrides` to see account-level decisions, including account email/name, status, source, entitlement period, workflow cap, execution cap, and last update.
4. Review `Application overrides` to see app-specific decisions, including app name or URI, owning account, status, source, period, caps, and last update.
5. Click `Refresh overrides` after changing account or application entitlement.

These lists show explicit stored overrides, not every account that inherits access from a subscription plan policy. If an account receives Workflow Foundation only because its subscription plan is enabled, it appears through the plan policy and effective entitlement checks, not as an account override row.

Enabling records:

```
admin.workflow_entitlement.enabled
```

Disabling records:

```
admin.workflow_entitlement.removed
```

When entitlement is disabled by admin:

* Source is set to `admin`.
* Disabled admin email is recorded.
* Retention ends 90 days later.
* Removal policy is set to `pause_active_runs`.
* Internal note stores the reason.

#### Admin Permissions and Audit Trail

Workflow admin actions are permissioned and audited.

View actions require:

```
admin.workflows.view
```

Mutating actions require:

```
admin.workflows.manage
```

Mutating actions require a reason in the UI. The reason should explain why the action was taken and should be specific enough for later audit review.

Good reasons:

* `Customer requested workflow add-on for app launch.`
* `Retrying after temporary email provider outage.`
* `Cancelling stuck wait run after customer disabled the workflow.`
* `Disabling entitlement because subscription no longer includes Workflow Foundation.`

Weak reasons:

* `test`
* `needed`
* `fix`
* `retry`

Audit events include:

* Admin identity.
* Target account id.
* Target application id.
* Target object type.
* Target object id.
* Reason.
* Request IP.
* User agent.
* Before/after payloads for entitlement changes.

#### Operational Playbooks

**A Maker Cannot Save or Publish**

1. Check the builder entitlement panel.
2. If status is not enabled, ask the maker to request the add-on or enable it in admin.
3. In admin, open Workflow Operations.
4. Search for the application in Entitlement.
5. Enter a reason.
6. Click `Enable`.
7. Ask the maker to refresh the builder and save again.

**A Workflow Does Not Run After Publish**

1. Confirm workflow status is `active`.
2. Confirm entitlement is enabled.
3. Confirm the trigger type matches the event.
4. Confirm target type matches the event source.
5. Confirm target is blank for `application` or is selected from the picker for `screen`, `button`, or `data_source`. For `record` or other advanced sources, confirm the pasted id exactly matches the event source object.
6. Check the Activity screen in the builder.
7. If no run exists, check event ingestion and trigger attachment setup.
8. In admin, check Queue and Containers for worker health.

**A Run Failed**

1. Open the workflow in the builder.
2. Review the Activity screen error summary and selected run timeline.
3. If more detail is needed, open Admin Workflow Operations.
4. Select the run.
5. Review step statuses and step error messages.
6. Fix configuration or external dependency.
7. Retry only after the cause is understood.

**A Run Is Waiting Too Long**

1. Check whether the selected workflow includes a Wait step.
2. Review the wait config:
   * `delay_seconds`
   * `until`
3. In admin, check the Queue panel for the run id.
4. Confirm `available_at` is in the future for intentional waits.
5. If `available_at` is in the past and the job is queued, check Containers for stale or unhealthy workers.

**Queue Jobs Are Building Up**

1. Open Admin Workflow Operations.
2. Check `Queued jobs`.
3. Open Queue and filter to `queued`.
4. Open Containers.
5. Look for stale or unhealthy workers.
6. If workers are healthy, check whether queue jobs have future `available_at` values from Wait steps.
7. If workers are stale/unhealthy, escalate to infrastructure or restart the worker process.

**Dead Letters Are Increasing**

1. Open Queue and filter to `dead_letter`.
2. Inspect last error messages.
3. Group failures by workflow id or run id.
4. Open the corresponding run detail.
5. Identify whether failures are:
   * Bad workflow config.
   * Missing sheet.
   * Missing record id.
   * Notification delivery failure.
   * Worker/runtime failure.
6. Fix the underlying cause.
7. Retry only when the failure is retryable or the configuration has been corrected.

**Disable Workflow Foundation for an App**

1. Open Admin Workflow Operations.
2. Search and select the application in Entitlement.
3. Enter a clear reason.
4. Click `Disable`.
5. Confirm summary metrics and entitlement status after refresh.
6. Notify the maker that new workflow executions will stop.

#### JSON Examples

**Dynamic Field Mapping**

```json
{
  "sheet_id": "64f000000000000000000001",
  "fields": {
    "name_field_id": {
      "value_type": "dynamic",
      "path": "payload.name"
    },
    "priority_field_id": "High"
  }
}
```

**Status Condition**

```json
{
  "rules": [
    {
      "field": "payload.status",
      "operator": "equals",
      "value": "Needs review"
    }
  ]
}
```

**Non-Empty Check**

```json
{
  "rules": [
    {
      "field": "payload.email",
      "operator": "is_not_empty"
    }
  ]
}
```

**Date Comparison**

```json
{
  "rules": [
    {
      "field": "payload.due_date",
      "operator": "before",
      "value": "2026-07-01T00:00:00.000Z"
    }
  ]
}
```

**Notification with Dynamic Body**

```json
{
  "channel": "email",
  "recipients": ["reviewer@example.com"],
  "subject": "Workflow event received",
  "body": {
    "value_type": "dynamic",
    "path": "payload.summary"
  }
}
```

**Open Screen UI Action**

```json
{
  "screen_id": "screen_review_detail_001",
  "record_id": {
    "value_type": "dynamic",
    "path": "payload.record_id"
  }
}
```

**Show or Hide Control UI Action**

```json
{
  "control_id": "comp_reviewer_notes_001",
  "visible": true,
  "screen_id": "screen_review_detail_001"
}
```

**Refresh Data UI Action**

```json
{
  "screen_id": "screen_requests_001",
  "sheet_id": "64f000000000000000000202"
}
```

**Show Message UI Action**

```json
{
  "message": "This request was sent for review.",
  "tone": "success"
}
```

#### Best Practices

**Builder Best Practices**

* Use descriptive workflow names.
* Keep the trigger scope narrow when possible by choosing the correct target type and picker target.
* Use target type `screen` and choose the form-owning screen for form-submission workflows.
* Use target type `button` and choose the exact button for one specific button workflow.
* Add an explicit End step for readability.
* Configure one step at a time and save drafts frequently.
* Place Condition and UI response steps before background-only work when the app should react immediately.
* Use dynamic payload paths only when the event source reliably provides the data.
* Use the guided controls first; keep power-user JSON valid when you edit it.
* Publish only after validation is clean.
* Review runs after the first real event.

**Admin Best Practices**

* Always enter specific action reasons.
* Retry failed runs only after understanding the failure.
* Use Cancel for active runs that should not proceed.
* Watch dead letters before retrying broadly.
* Check worker heartbeats when queue depth rises.
* Disable entitlement only with a clear customer, billing, or operational reason.
* Prefer app-scoped investigation before cross-system action.

#### Glossary

`Power-user JSON`

Raw JSON for the selected step.

`Application`

The NotionApps app that owns workflows.

`Condition`

A step that evaluates rules against payload/context data.

`Dead letter`

A queue job that exhausted retry handling or could not continue safely.

`Entitlement`

The app-level right to use Workflow Foundation.

`Payload`

The event data that started a workflow run.

`Live UI action`

An immediate response returned to the app from a form or button workflow, such as opening a screen, showing a message, hiding a control, refreshing data, or blocking default behavior.

`Published version`

Immutable workflow snapshot used for execution.

`Queue job`

Worker-facing job that advances a workflow run.

`Run`

One execution of a published workflow.

`Step`

One action or control point inside a workflow.

`Target type`

The kind of object a trigger listens to, such as application, screen, button, data source, or record.

`Target id`

Optional saved id that narrows a trigger to one source object. In normal builder use, this is saved when the maker chooses a screen, button, data source, or field from a picker, and the builder shows it as reference detail. Advanced users can paste a custom id when the picker cannot discover the object.

`Trigger`

The event that starts a workflow.

`Worker heartbeat`

Operational record showing that a workflow worker is alive and what state it is in.
