---
title: "Built-in Steps"
description: "The steps and triggers MindCloud runs itself (Loop, If/Else, Code, HTTP request, Schedule, Webhook and more): each one's settings, their types and examples, and what it outputs."
---

{/* Generated by projects/publicApi (npm run docs:website:generate) from the built-in step and trigger definitions. Do not edit by hand: docs:check fails when this page differs from the code. */}

Set a built-in step up with [Update Workflow Step Configuration](/docs/api/rest/actions/update-workflow-step-configuration): its settings go in `arguments` and the ones marked option in `options`. [Get Workflow Step Schema](/docs/api/rest/actions/get-workflow-step-schema) answers the same for a step you have added. A template is text that may hold references ([Workflow References](/docs/api/rest/introduction/workflow-references)); a condition is an If/Else condition tree.

## Steps

### Loop

Add it with `"app": "iterate"` in [Add Workflow Step](/docs/api/rest/actions/add-workflow-step).

| Setting | Type | Required | Default | Choices | Example | What it is |
| --- | --- | --- | --- | --- | --- | --- |
| `source` | template | yes |  |  | `"{{ steps.<stepId>.output }}"` | What to loop through: "\{\{ steps.&lt;stepId>.output \}\}" (every record) or "\{\{ steps.&lt;stepId>.output[0].&lt;field> \}\}" (an array in the first record). |
| `delayMs` | integer | no | `100` |  | `500` | A pause after each item, in milliseconds: 1 or more. Left out, 100. |

Options: `parallel` (Run loop items in parallel: \{ adaptive, window, maxWindow \}. Example: `{"window":5}`).

**Output.** The list it loops through. Inside the loop, each pass sees the Loop's output as a one-item list holding the current item, so steps in its body read \{\{ steps.&lt;loopStepId>.output[0].&lt;field> \}\}. A Loop is not tested on its own: give the step it loops over a sample (Test Workflow Step or Update Workflow Step Output) and the Loop's sample is that sample's first record.

### If/Else

Add it with `"app": "ifElse"` in [Add Workflow Step](/docs/api/rest/actions/add-workflow-step).

| Setting | Type | Required | Default | Choices | Example | What it is |
| --- | --- | --- | --- | --- | --- | --- |
| `condition` | condition | yes |  |  | `{"conjunction":"and","where":[{"field":"{{ steps.<loopStepId>.output[0].realName }}","operator":"startsWith","value":"D","type":"string"},{"field":"{{ steps.<loopStepId>.output[0].isBot }}","operator":"eq","value":"false","type":"boolean"}]}` | A condition tree: one condition \{ field, operator, value, type \} or a group \{ conjunction, where \}. Sending one in place of the other replaces it whole. It is stored as a group, so reads always answer \{ conjunction, where \}: a single condition reads back as a group of one. |

**Output.** One record: which lane ran and each condition as it was evaluated. The then lane runs when the condition holds, the else lane otherwise.

| Field | Type | Holds |
| --- | --- | --- |
| `conclusion` | string | then or else: the lane that ran. |
| `conditions` | object | The condition tree as evaluated: \{ conjunction, filterSet \}, where filterSet lists each condition as \{ field, operator, value, conclusion, disabled \} with its field and value resolved and conclusion true or false, and each nested group as \{ type: "nested", conjunction, filterSet, conclusion \}. An If still on the older single condition answers field, operator and value on the record itself instead. |

### Transform

Add it with `"app": "transform"` in [Add Workflow Step](/docs/api/rest/actions/add-workflow-step).

| Setting | Type | Required | Default | Choices | Example | What it is |
| --- | --- | --- | --- | --- | --- | --- |
| `source` | template | yes |  |  | `"{{ steps.<stepId>.output }}"` | The output to transform: "\{\{ steps.&lt;stepId>.output \}\}". |

Options: `postProcess` (Filter, sort and slice the output: \{ filter, sort: [\{ field, direction \}], slice: \{ from, to \} \} (from 0, to excluded). Example: `{"slice":{"from":0,"to":10}}`).

**Output.** Transform filters, sorts or slices one earlier output without code (to reshape records with JavaScript, use Map). It answers the source's records after the postProcess option's filter, sort and slice.

### Wait

Add it with `"app": "wait"` in [Add Workflow Step](/docs/api/rest/actions/add-workflow-step).

| Setting | Type | Required | Default | Choices | Example | What it is |
| --- | --- | --- | --- | --- | --- | --- |
| `delayMs` | integer | no | `1000` |  | `5000` | How long to wait, in milliseconds: 1 or more. Left out, 1000. |

**Output.** One record with the pause it took.

| Field | Type | Holds |
| --- | --- | --- |
| `delay` | integer | The pause, in milliseconds. |

### Continue or Break

Add it with `"app": "continue"` or `"app": "break"` in [Add Workflow Step](/docs/api/rest/actions/add-workflow-step).

No settings.

**Output.** No output: Continue moves a loop to its next item, Break ends the loop.

### Map

Add it with `"app": "map"` in [Add Workflow Step](/docs/api/rest/actions/add-workflow-step).

| Setting | Type | Required | Default | Choices | Example | What it is |
| --- | --- | --- | --- | --- | --- | --- |
| `code` | string | yes |  |  | `"return input['<key>'].map((user) => ({ name: 'Mr. ' + user.realName }));"` | The JavaScript, a function body that returns the output: input['&lt;key>'] is each input's output, always a list. Required before the step can run, not to save it: a Map step added without code is kept and shows as not set up yet, which is how one that reads a step created in the same Set Workflow Definition call is added before its key is known. |
| `inputs` | array | yes |  |  | `[{"stepId":"<stepId>","grouped":false}]` | The steps whose outputs the code reads: [\{ stepId, grouped \}]. grouped (for a step inside a loop) collects that step's records from every pass of the loop instead of the current pass's. Each input answers its key, the name the code reads it by (input['&lt;key>']): for an app step it is the app's slug, then the action's slug with a capital first letter, then Group when grouped, then the last four characters of the step id in capitals (slackListUsers7K2Q); for a built-in step it is the built-in's slug, then Group when grouped, then those four characters (iterateFVNN). It cannot be set. |
| `allowLargeOutput` | boolean | no |  |  | `false` | Allow an output row over 500 KB. |

Options: `batching` (Run the code once per batch of an input: \{ size, inputKey \}. Example: `{"size":100,"inputKey":"<key>"}`).

**Output.** Map runs your JavaScript over earlier steps' outputs (to filter, sort or slice one output without code, use Transform). It answers the records the code returns: return an array for several records. The code is the body of a JavaScript function that gets one argument, input, whose keys are the inputs' keys (each input's key is answered with it, before and after a save). Each input['&lt;key>'] is always a list: a step's records, the current item of a loop as a one-item list, or with grouped every pass's records of a step inside a loop. It runs in MindCloud's code runner.

### Group results

Add it with `"app": "groupResults"` in [Add Workflow Step](/docs/api/rest/actions/add-workflow-step).

| Setting | Type | Required | Default | Choices | Example | What it is |
| --- | --- | --- | --- | --- | --- | --- |
| `inputs` | array | yes |  |  | `["<stepId>","<stepId>"]` | The steps whose outputs are grouped, in order. |
| `flatten` | boolean | no |  |  | `true` | Flatten nested lists into one. |
| `hideEmpty` | boolean | no |  |  | `true` | Leave out empty results of steps inside an If. |

**Output.** The records of its inputs collected into one output, in input order; a step inside a loop contributes its records from every pass. flatten merges them into one list of records.

### Memory

Add it with `"app": "memory"` in [Add Workflow Step](/docs/api/rest/actions/add-workflow-step).

No settings.

Options: `memory` (Values to remember after the step runs: [\{ key, value, scope, saveOn, expiresAfterMs \}]. Example: `[{"key":"lastSync","value":"{{ system.now }}","scope":"workflow","saveOn":"success"}]`).

**Output.** One record per value its memory option saved.

| Field | Type | Holds |
| --- | --- | --- |
| `key` | string | The name the value is saved under. |
| `value` | dynamic | The value saved. |
| `scope` | string | Where it is kept: workflow, allWorkflows, environment or installation. |

### Flow control

Add it with `"app": "flowControl"` in [Add Workflow Step](/docs/api/rest/actions/add-workflow-step).

| Setting | Type | Required | Default | Choices | Example | What it is |
| --- | --- | --- | --- | --- | --- | --- |
| `action` | string | no |  |  | `"endAsSuccess"` | doNothing, continue or break (in a loop), endAsSuccess, or endAsFailure. |
| `log` | object | no |  |  | `{"level":"info","message":"Synced {{ steps.<stepId>.output[0].id }}"}` | Write to the run log: \{ level: info \| warn \| error, message \}. |
| `email` | object | no |  |  | `{"to":"ops@example.com","subject":"Order failed","body":"Order {{ steps.<stepId>.output[0].id }} failed."}` | Send an e-mail: \{ to (comma-separated), subject, body, html, toEndUser \}. |
| `slack` | object | no |  |  | `{"channel":"C0123456789","message":"Order {{ steps.<stepId>.output[0].id }} failed."}` | Send a Slack message: \{ channel (a channel id), message \}. |

**Output.** One record: the action taken and what each notice did.

| Field | Type | Holds |
| --- | --- | --- |
| `action` | string | The action it took. |
| `log` | object | sent: whether it wrote to the run log. |
| `email` | object | sent, sentTo and any recipients skipped for rate limits. |
| `slack` | object | sent, and Slack's answer. |

### HTTP request

Add it with `"app": "httpRequest"` in [Add Workflow Step](/docs/api/rest/actions/add-workflow-step).

| Setting | Type | Required | Default | Choices | Example | What it is |
| --- | --- | --- | --- | --- | --- | --- |
| `url` | template | yes |  |  | `"https://api.example.com/orders/{{ steps.<stepId>.output[0].id }}"` | The URL, which may hold templates. |
| `method` | string | no |  |  | `"POST"` | GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS. Left out, GET. |
| `query` | array | no |  |  | `[{"name":"status","value":"open","type":"string"}]` | Query parameters: [\{ name, value, type \}]. |
| `headers` | array | no |  |  | `[{"name":"Accept","value":"application/json","type":"string"}]` | Headers: [\{ name, value, type \}]. |
| `auth` | object | no |  |  | `{"type":"bearer","token":"{{ workflow.inputs.apiToken }}"}` | Authentication: \{ type: basic, username, password \}, \{ type: bearer, token \}, or \{ type: apiKey, name, value, in: header (the default) or query \}; null for none. |
| `body` | object | no |  |  | `{"format":"json","fields":[{"name":"orderId","value":"{{ steps.<stepId>.output[0].id }}","type":"string"}]}` | The body: \{ format: json \| formData \| urlencoded, fields: [\{ name, value, type \}] \} or \{ format: raw, content, contentType \}; null for none. |
| `followRedirects` | boolean | no |  |  | `false` | Follow redirects (up to 10). Left out, true. |
| `acceptEncoding` | string | no |  |  | `"gzip"` | The Accept-Encoding to ask for: gzip, deflate, gzip, deflate, br. |
| `connectionPooling` | boolean | no |  |  | `true` | Reuse connections. Left out, true. |
| `retries` (option) | object | no |  |  | `{"count":3,"delayMs":1000,"multiplier":2,"onStatusCodes":[429,503]}` | Retries, as on every step: \{ count, delayMs, multiplier, onStatusCodes, onAnyError \}. |

Options: `onFailure` (What to do when the step fails: \{ action, logLevel \}. Example: `{"action":"continue","logLevel":"warn"}`); `onNoResults` (What to do when it finds nothing: \{ action, logLevel \}. Example: `{"action":"break"}`); `onSuccess` (What to do when it succeeds: \{ action: stop \}. Example: `{"action":"stop"}`).

**Output.** The response body as records: an array body gives one record per item, anything else one record. The response's status and headers are in the step's meta.response.

### Run workflow

Add it with `"app": "runWorkflow"` in [Add Workflow Step](/docs/api/rest/actions/add-workflow-step).

| Setting | Type | Required | Default | Choices | Example | What it is |
| --- | --- | --- | --- | --- | --- | --- |
| `workflowId` | string | yes |  |  | `"Wq3kZ8pLx2Nb"` | The workflow to run, from List Workflows. |
| `version` | string | no |  |  | `"published"` | published (the default once it has one) or draft. |
| `inputs` | object | no |  |  | `{"orderId":"{{ steps.<stepId>.output[0].id }}"}` | Values for the workflow's variables, by key; they may be templates. |
| `environments` | array | no |  |  | `["Ev8kT3nW5qLz"]` | Environment ids to run it in, one run each; left out, one run in the default environment. |

**Output.** One record per run it queued, with the message the queue answered; a run that could not be queued adds a record with its error.

| Field | Type | Holds |
| --- | --- | --- |
| `message` | string | What the queue answered. |
| `error` | string | Why a run could not be queued. |

## Triggers

### Schedule

Add it with `"app": "schedule"` in [Add Workflow Trigger](/docs/api/rest/actions/add-workflow-trigger).

| Setting | Type | Required | Default | Choices | Example | What it is |
| --- | --- | --- | --- | --- | --- | --- |
| `type` | string | no | `"interval"` | interval, fixed | `"fixed"` | interval: every everyMinutes; fixed: at each of times, in timeZone. |
| `everyMinutes` | integer | no | `60` | 10, 15, 30, 60, 180, 360, 720, 1440, 2880, 4320, 10080, 20160 | `60` | Interval schedules: how often it runs, in minutes, one of the choices. Days are read in the company time zone. |
| `days` | array | no | `[0,1,2,3,4,5,6]` | 0, 1, 2, 3, 4, 5, 6 | `[1,2,3,4,5]` | Weekdays it runs on, 0 (Sunday) to 6. Left out, every day; an empty list never runs. |
| `times` | array | no |  |  | `["09:00","17:00"]` | Fixed schedules: the times it runs at, HH:MM in 24-hour time, at least one, each at least 10 minutes from the next (across midnight too). Stored once each, in order. |
| `timeZone` | string | no |  |  | `"America/New_York"` | Fixed schedules: the IANA time zone of times and days ("America/New_York"). |
| `environments` | array | no |  |  | `["Ev8kT3nW5qLz"]` | Environment ids to run in, one run each; left out, the default environment. Not for Embedded workflows. |

**Output.** It starts a run at each scheduled time; steps read the time as \{\{ system.now \}\}.

### Webhook

Add it with `"app": "webhook"` in [Add Workflow Trigger](/docs/api/rest/actions/add-workflow-trigger).

| Setting | Type | Required | Default | Choices | Example | What it is |
| --- | --- | --- | --- | --- | --- | --- |
| `url` | string | no |  |  | `"https://webhook.mindcloud.co/v1/webhook/<id>"` | The URL that starts the workflow, made by MindCloud. Read-only. Add Workflow Trigger answers it as webhookUrl too. |
| `waitForCompletion` | boolean | no | `false` |  | `false` | true: a call waits for the workflow to finish (the answer comes from a Respond to webhook step, if any); false: the call is queued and answered at once, with the custom response when one is set and otherwise \{ success, message, requestId, runId \}, where runId is the run it started (Get a Run; null when processInOrder is on, since that run starts later). A new Webhook trigger starts false (queued), as in the editor; adding a Respond to webhook step turns it true. Settings apply after publish. |
| `processInOrder` | boolean | no |  |  | `true` | Queued calls only: run one at a time, in the order they came. Each run starts when its turn comes, so the answer has no runId. |
| `forwardHeaders` | boolean | no |  |  | `false` | Queued calls only: answer with the call's own request headers. |
| `customUrl` | string | no |  |  | `"orders/:orderId"` | A path of your own after https://webhook.mindcloud.co/v1/webhook/&lt;company slug>/, such as "orders/:orderId" (":name" captures a part). Applies at once, published or not; unique in the company. null turns it off. |
| `response` | object | no |  | `{"status":["200","201","202","204","301","304","400","401","403","404","418","429","500","502","503","504"]}` | `{"status":"202","body":{"received":"true"}}` | Queued calls only: the answer, \{ status, headers, body, redirectUrl \}. status is one of the choices (default "200"); headers are names and values; body is fields and values, or one text value; templates may read only this trigger's call, \{\{ trigger.&lt;triggerId>.output[0].body.&lt;field> \}\}. null answers the default. |
| `environments` | array | no |  |  | `["Ev8kT3nW5qLz"]` | Queued calls only: environment ids to run in, one run each; left out, the default environment. Not for Embedded workflows. |

**Output.** One record per call, read as \{\{ trigger.&lt;triggerId>.output[0].&lt;part>.&lt;field> \}\}. Listen Workflow Trigger saves a real call as the sample.

| Field | Type | Holds |
| --- | --- | --- |
| `body` | object | The call's body. |
| `query` | object | The call's query parameters. |
| `headers` | object | The call's headers. |

### When called

Add it with `"app": "runWorkflow"` in [Add Workflow Trigger](/docs/api/rest/actions/add-workflow-trigger).

| Setting | Type | Required | Default | Choices | Example | What it is |
| --- | --- | --- | --- | --- | --- | --- |
| `allowConcurrentRuns` (option) | boolean | no |  |  | `true` | Start a run for every call, even while another run of this workflow is going. Left out, a call made during a run is skipped. |

**Output.** It starts a run when another workflow's Run workflow step calls this one; the values that step sends set this workflow's variables, read as \{\{ workflow.inputs.&lt;key> \}\}.
