> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cortex.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Workflow block configuration reference

> Fields, types, and examples for each Workflow block as it appears in the Workflows API and in Workflow YAML

This page lists the configuration fields for each Workflow block as they appear in a Workflow definition. Use it when you create or update Workflows with the [Workflows API](/api/rest/workflows) or manage them as YAML with [Workflows as code](/streamline/workflows/workflows-as-code). The API and YAML use the same structure, so every example on this page works in both. In JSON, use the same keys.

For instructions on configuring blocks in the Workflow editor, see [Adding blocks to a Workflow](/streamline/workflows/blocks).

<Info>
  The fastest way to get a correct definition is to build the Workflow in the UI first, then click **Export Workflow YAML** (see [Workflows as code](/streamline/workflows/workflows-as-code#step-2-creating-a-yaml-file-for-the-workflow)). The export shows the exact values Cortex expects, including IDs that are specific to your workspace.
</Info>

## How a block appears in a Workflow definition

In a definition, blocks are listed under `actions`. Each entry has the same outer fields, and the block-specific configuration sits under `schema`. The `schema.type` value sets which other fields the block takes.

| Field | Type | Required | Description |
| - | - | - | - |
| `name` | string | Yes | The display name of the block. |
| `slug` | string | Yes | A unique identifier for the block within the Workflow. Use lowercase letters, digits, and hyphens, 2 to 255 characters, not starting or ending with a hyphen. |
| `isRootAction` | boolean | Yes | Whether this is the first block in the Workflow. A Workflow has exactly one root block. |
| `outgoingActions` | array of strings | Yes | The slugs of the blocks that run after this one. Use `[]` for the last block. For a Branch block, list the `outgoingAction` of every path, including the fallback path. |
| `schema` | object | Yes | The block's configuration. Always includes `type`. See the sections below. |

```yaml theme={null}
actions:
- name: Get user email
  slug: get-user-email
  isRootAction: true
  outgoingActions:
  - notify-team
  schema:
    type: JQ
    expression: .context.initiatedBy.email
- name: Notify team
  slug: notify-team
  isRootAction: false
  outgoingActions: []
  schema:
    type: SLACK
    channel: platform-team
    message: "Workflow started by {{actions.get-user-email.outputs.result}}"
```

### Referencing run data in block fields

Blocks can read the Workflow run state through three top-level keys: `context`, `actions`, and `variables`. Each block writes its result to `actions.<slug>.outputs`. How you reference a value depends on the field:

* **Text fields** (URLs, headers, payloads, messages, descriptions) - Use Mustache templates, such as `{{variables.app-name}}` or `{{actions.get-user-email.outputs.result}}`. Use three curly braces to avoid HTML escaping.
* **JQ expressions** - Start with a dot, such as `.variables.app-name`.
* **CEL expressions, JavaScript, and path fields** - Use dot paths without a leading dot, such as `variables.app-name`.
* **Slugs that contain a hyphen** - In CEL, JavaScript, and JQ, quote them: `actions["get-user-email"]` (or `.actions["get-user-email"]` in JQ).

For the full state object, see [Referencing a Workflow state in a block](/streamline/workflows/blocks/states).

## Core blocks

### Branch (`CONDITIONAL_BRANCH`)

Cortex evaluates the paths in order and takes the first one whose expression returns `true`. If none do, it takes the fallback path. See [Branch](/streamline/workflows/blocks#branch) for how paths work.

| Field | Type | Required | Description |
| - | - | - | - |
| `branches` | array of objects | Yes | The conditional paths, evaluated in order. See the path fields below. |
| `fallbackBranch` | object | No | The path to take if no other path returns `true`. |
| `joiningAction` | string | No | The slug of the block where the paths join again. Leave it out if the paths don't join. When set, the slug must also be in this block's `outgoingActions`. |

Each path in `branches` takes the following fields. `fallbackBranch` takes the same fields except `expression`, and its `type` is `FALLBACK`.

| Field | Type | Required | Description |
| - | - | - | - |
| `type` | string | Yes | `CONDITIONAL` for paths in `branches`, `FALLBACK` for `fallbackBranch`. |
| `name` | string | Yes | The display name of the path. |
| `slug` | string | Yes | The path's identifier. It must be unique within the block. |
| `expression` | string | Yes (`CONDITIONAL` only) | A [CEL](https://cel.dev/) expression that can read `context`, `actions`, and `variables`, such as `variables.count > 0`. |
| `outgoingAction` | string | No | The slug of the first block in this path. |

**Outputs:** `actions.<slug>.outputs.conditions.<path-slug>.result`

```yaml theme={null}
- name: Check environment
  slug: check-environment
  isRootAction: false
  outgoingActions:
  - deploy-production
  - deploy-staging
  schema:
    type: CONDITIONAL_BRANCH
    branches:
    - type: CONDITIONAL
      name: Production
      slug: production
      expression: actions["user-input"].outputs.environment == "prod"
      outgoingAction: deploy-production
    fallbackBranch:
      type: FALLBACK
      name: Everything else
      slug: everything-else
      outgoingAction: deploy-staging
```

### Data transformation (`JQ`)

| Field | Type | Required | Description |
| - | - | - | - |
| `expression` | string | Yes | A [jq](https://jqlang.github.io/jq/) expression. Its input has the keys `context`, `actions`, and `variables`, such as `.context.initiatedBy.email`. |

**Outputs:** `actions.<slug>.outputs.result`

```yaml theme={null}
schema:
  type: JQ
  expression: .context.initiatedBy | tojson
```

### HTTP request (`HTTP_REQUEST`)

| Field | Type | Required | Description |
| - | - | - | - |
| `httpMethod` | string | Yes | One of `GET`, `POST`, `PUT`, `PATCH`, or `DELETE`. |
| `url` | string | Yes | The request URL. Supports templates. When `integration` is set, enter a path relative to the integration's base URL. |
| `headers` | object | Yes | A map of header names to values. Use `{}` for no headers. Supports templates. |
| `payload` | string | No | The request body. Supports templates. |
| `integration` | string | No | A configured integration to authenticate the request with, such as `GitHub`, `Jira`, or `Cortex`. See [Authenticating HTTP requests with an integration](/streamline/workflows/blocks#authenticating-http-requests-with-an-integration). |
| `integrationAlias` | string | No | The integration configuration to use when the integration has more than one. |
| `targetHost` | string | No | Only for the `Google` integration: the `*.googleapis.com` host to call. Defaults to `cloudresourcemanager.googleapis.com`. Cortex rejects this field with any other integration. |

**Outputs:** `actions.<slug>.outputs.status`, `actions.<slug>.outputs.headers`, `actions.<slug>.outputs.body`

```yaml theme={null}
schema:
  type: HTTP_REQUEST
  httpMethod: POST
  url: https://api.example.com/v1/environments
  headers:
    Content-Type: application/json
    Authorization: "Bearer {{context.secrets.example-token}}"
  payload: '{"name": "{{actions.user-input.outputs.env-name}}"}'
```

### Asynchronous HTTP request (`HTTP_REQUEST_ASYNC`)

This block takes all of the [HTTP request](#http-request-http_request) fields, plus a timeout. The Workflow pauses until the external system calls the callback URL (available as `{{callbackUrl}}`) or the timeout expires. See [Asynchronous HTTP request](/streamline/workflows/blocks#http-action-async) for the callback format.

| Field | Type | Required | Description |
| - | - | - | - |
| `timeoutInSeconds` | integer | No | How long to wait for the callback, in seconds. |

```yaml theme={null}
schema:
  type: HTTP_REQUEST_ASYNC
  httpMethod: POST
  url: https://ci.example.com/pipelines/provision
  headers:
    Content-Type: application/json
  payload: '{"callback": "{{callbackUrl}}"}'
  timeoutInSeconds: 3600
```

### JavaScript (`JAVASCRIPT`)

| Field | Type | Required | Description |
| - | - | - | - |
| `script` | string | Yes | The script to run. It runs as the body of `run(actions, context, variables)` and must end with a `return` statement. |

**Outputs:** `actions.<slug>.outputs.result`, plus any top-level keys of the returned object.

```yaml theme={null}
schema:
  type: JAVASCRIPT
  script: |
    const email = context.initiatedBy.email;
    return { username: email.split("@")[0] };
```

### Manual approval (`MANUAL_APPROVAL`)

| Field | Type | Required | Description |
| - | - | - | - |
| `approvingTeamIds` | array of strings | Yes | The Cortex IDs (CIDs) of the teams whose members can approve, not team tags. Can be `[]` when `approvingTeamIdsOverride` is set. |
| `approvingTeamIdsOverride` | string | No | A dot path that resolves the approving teams at run time, such as `variables.approvers` or `actions.user-input.outputs.team`. The value at the path must be an array of team Cortex IDs or team tags. Don't wrap it in template braces. |
| `approverDescription` | string | No | A message shown to approvers. Supports templates. |

```yaml theme={null}
schema:
  type: MANUAL_APPROVAL
  approvingTeamIds: []
  approvingTeamIdsOverride: variables.approvers
  approverDescription: "Approve the new environment for {{actions.user-input.outputs.env-name}}"
```

### Run Workflow (`RUN_WORKFLOW`)

| Field | Type | Required | Description |
| - | - | - | - |
| `workflowId` | string | Yes | The child Workflow to run. |
| `entityId` | string | No | The entity to run the child Workflow against. |
| `inputs` | object | Yes | Values for the child Workflow's variables, keyed by variable slug. The child reads each value as `{{variables.<slug>}}`. Values keep the variable's type and can use templates. Use `{}` if there are no inputs. |
| `waitForCompletion` | boolean | Yes | Whether to wait for the child run to finish before continuing. Cortex uses `false` if you leave it out. |
| `timeoutInSeconds` | integer | No | How long to wait for the child run, in seconds. When it expires, Cortex cancels the child run. Only used with `waitForCompletion`. |

**Outputs:** `actions.<slug>.outputs.runId`. With `waitForCompletion: true`, also `status`, `runResponse`, and `variables`. See [Run Workflow](/streamline/workflows/blocks#run-workflow).

```yaml theme={null}
schema:
  type: RUN_WORKFLOW
  workflowId: approval-workflow
  waitForCompletion: true
  timeoutInSeconds: 86400
  inputs:
    app-id: "{{actions.form.outputs.appId}}"
    count: 5
```

### Scaffolder (`SCAFFOLDER`)

| Field | Type | Required | Description |
| - | - | - | - |
| `scaffolderTemplateTag` | string | One of these two | The tag of the Scaffolder template. If both fields are set, Cortex uses this one, which keeps definitions portable across workspaces. |
| `scaffolderTemplateId` | string | One of these two | The template's tag or Cortex ID. In responses, this is always the Cortex ID, or `null` if the template was deleted. |
| `createNewRepository` | boolean | No | Whether to create a new repository. Defaults to `true`. Set it to `false` to open a pull request against an existing repository. |
| `createService` | boolean | No | Whether to create the entity in Cortex. |
| `inputOverrides` | array of objects | Yes | Values that override template fields. See [Input overrides](#input-overrides). Use `[]` for none. |

```yaml theme={null}
schema:
  type: SCAFFOLDER
  scaffolderTemplateTag: java-service
  createNewRepository: true
  createService: true
  inputOverrides:
  - type: VALUE
    inputKey: project_name
    outputVariable: context.entity.tag
    editable: false
```

### Set variable(s) (`SET_VARIABLES`)

The variables must be declared in the Workflow's `variables` list (see [Configuring Workflow settings](/streamline/workflows/configuring-workflow-settings)).

| Field | Type | Required | Description |
| - | - | - | - |
| `variables` | array of objects | Yes | The variables to set. Each item has a `slug` (the variable's slug) and a `source`. |
| `variables[].source.type` | string | Yes | `REFERENCE` to read a value from a path, or `JAVASCRIPT` to compute it with a script. |
| `variables[].source.path` | string | For `REFERENCE` | A dot path into the run data, such as `actions.fetch.outputs.body`. |
| `variables[].source.script` | string | For `JAVASCRIPT` | A script that returns the value. It runs as the body of `run(actions, context, variables)`. |

```yaml theme={null}
schema:
  type: SET_VARIABLES
  variables:
  - slug: approved
    source:
      type: REFERENCE
      path: actions.run-approval.outputs.variables.approved
  - slug: retry-count
    source:
      type: JAVASCRIPT
      script: return (variables["retry-count"] ?? 0) + 1;
```

### User input (`USER_INPUT`)

| Field | Type | Required | Description |
| - | - | - | - |
| `inputs` | array of objects | Yes | The fields to show the user. See [User input field types](#user-input-field-types). |
| `inputOverrides` | array of objects | Yes | Values that override or prefill fields. See [Input overrides](#input-overrides). Use `[]` for none. |
| `jsValidatorScript` | string | No | JavaScript that validates the response. See [Adding validation logic](/streamline/workflows/blocks#user-input). |

**Outputs:** `actions.<slug>.outputs.<key>` for each field.

```yaml theme={null}
schema:
  type: USER_INPUT
  inputs:
  - type: INPUT_FIELD
    name: Service name
    key: service-name
    required: true
    validationRegex: ^[a-z][a-z0-9-]+$
  - type: SELECT_FIELD
    name: Environment
    key: environment
    required: true
    options: [dev, staging, prod]
    optionsLabels: [Development, Staging, Production]
    allowAdditionalOptions: false
  inputOverrides: []
  jsValidatorScript: ""
```

#### User input field types

Every field takes these common keys:

| Field | Type | Required | Description |
| - | - | - | - |
| `type` | string | Yes | The field type. See the table below. |
| `name` | string | Yes | The label shown to the user. |
| `key` | string | Yes | The output key. It must be unique within the block. |
| `required` | boolean | Yes | Whether the user must provide a value. |
| `description` | string | No | Help text shown with the field. Supports templates. |

Each type also takes the keys below. Keys in **bold** are required.

| UI type | `type` | Additional keys |
| - | - | - |
| Text | `INPUT_FIELD` | `defaultValue` (string), `placeholder`, `validationRegex` |
| Paragraph | `TEXTAREA_FIELD` | `defaultValue` (string), `placeholder`, `validationRegex` |
| Secret | `SECRET_FIELD` | **`disabled`**, `placeholder`, `validationRegex` |
| Toggle | `TOGGLE_FIELD` | `defaultValue` (boolean) |
| Number | `NUMBER_FIELD` | **`format`** (`INTEGER` or `DECIMAL`), **`disabled`**, `min`, `max`, `defaultValue` (number), `placeholder` |
| Date | `DATE_FIELD` | **`format`** (`DATE` or `DATETIME`), **`disabled`**, `defaultValue` (string), `placeholder` |
| Select, manual options | `SELECT_FIELD` | **`options`** (array of strings), **`allowAdditionalOptions`**, `optionsLabels`, `defaultValue` (string), `placeholder` |
| Select, manual options with **Allow multiple** | `MULTISELECT_FIELD` | **`options`** (array of strings), **`allowAdditionalOptions`**, `optionsLabels`, `defaultValue` (array of strings), `placeholder` |
| Select, Cortex entity | `CORTEX_ENTITY_FIELD` | **`entityFilter`**, **`allowMultiple`**, **`limitEntitiesToRunnerUserScope`**, **`shouldDisplayOptionsAsHierarchy`**, `defaultValue` (array of strings), `placeholder` |
| Select, Cortex user | `CORTEX_USER_FIELD` | **`filter`**, **`allowMultiple`**, `defaultValue` (array of `{name, email}` objects), `placeholder` |
| Select, Slack channels | `SLACK_FIELD` | **`filter`** (object with `channels`), **`allowMultiple`**, `defaultValue` (array of strings), `placeholder` |
| Nested form | `NESTED_FORM_FIELD` | See [Nested form fields](#nested-form-fields). |

Notes on these keys:

* If you leave out a required boolean (`disabled`, `allowMultiple`, `allowAdditionalOptions`, `limitEntitiesToRunnerUserScope`, or `shouldDisplayOptionsAsHierarchy`), Cortex uses `false`. If you leave out `format`, Cortex uses `DECIMAL` for numbers and `DATE` for dates.
* `optionsLabels` sets display labels in the same order as `options`. If you leave it out, Cortex shows the option values.
* `entityFilter` accepts `typeFilter` (`{types: [service, team]}`), `groupTags`, `excludedGroupTags`, `teamIds`, `domainIds`, and `emailOwners`. Use `{}` to allow all entities.
* For `CORTEX_USER_FIELD`, `filter` accepts `teamCids` and `userEmails`. Use `{}` to allow all users.

```yaml theme={null}
- type: CORTEX_ENTITY_FIELD
  name: Service
  key: service
  required: true
  allowMultiple: false
  limitEntitiesToRunnerUserScope: true
  shouldDisplayOptionsAsHierarchy: false
  entityFilter:
    typeFilter:
      types: [service]
```

#### Nested form fields

A `NESTED_FORM_FIELD` lets the user enter a list of items. It takes the common keys, plus:

| Field | Type | Required | Description |
| - | - | - | - |
| `itemType` | string | No | `OBJECT` (the default) for items with several sub-fields, or `STRING`, `INTEGER`, `DECIMAL`, or `BOOLEAN` for single values. For single values, Cortex derives this from `element`. |
| `inputs` | array of objects | For `OBJECT` | The sub-fields for each item. Uses the same field types as `inputs` on the block, up to five levels of nesting. |
| `inputOverrides` | array of objects | For `OBJECT` | Overrides for the sub-fields. Use `[]` for none. |
| `element` | object | For single values | One field definition that describes every item. Its `type` must be `INPUT_FIELD`, `TEXTAREA_FIELD`, `DATE_FIELD`, `NUMBER_FIELD`, or `TOGGLE_FIELD`. |
| `min` | number | No | The minimum number of items. It also sets how many items appear by default. Defaults to 1. |
| `max` | number | No | The maximum number of items. |
| `disabled` | boolean | No | Whether the field is disabled. |

**Outputs:** an array of objects for `OBJECT` (for example, `[{"name": "db-1", "size": 100}]`), or a flat array for single values (for example, `[8080, 8443]`).

```yaml theme={null}
- type: NESTED_FORM_FIELD
  name: Databases
  key: databases
  required: true
  itemType: OBJECT
  min: 1
  max: 5
  inputs:
  - type: INPUT_FIELD
    name: Name
    key: name
    required: true
  - type: NUMBER_FIELD
    name: Size (GB)
    key: size
    required: true
    format: INTEGER
    disabled: false
  inputOverrides: []
```

For a single-value example, see [Workflows as code](/streamline/workflows/workflows-as-code#example-workflow-yaml).

#### Input overrides

`inputOverrides` on User input and Scaffolder blocks fill a field from a value earlier in the run.

| Field | Type | Required | Description |
| - | - | - | - |
| `type` | string | Yes | `VALUE` sets the field's value. `OPTION` sets the options the user can choose from. |
| `inputKey` | string | Yes | The key of the field to override. |
| `outputVariable` | string | Yes | A dot path to the value, such as `actions.lookup.outputs.result` or `variables.team-tags`. |
| `editable` | boolean | Yes (`VALUE` only) | Whether the user can edit the value before continuing. When `true`, the Workflow pauses for the user. Cortex uses `false` if you leave it out. |

## Integration blocks

Most prebuilt integration blocks use the `ADVANCED_HTTP_REQUEST` type and identify the action with `actionIdentifier`. Each action has its own set of `inputs`, so the easiest way to get the identifier and input keys is to add the block in the UI and export the Workflow YAML.

| `type` | Fields |
| - | - |
| `ADVANCED_HTTP_REQUEST` | `actionIdentifier` (string, required, such as `googleCloud.getProject`), `inputs` (object, required, keyed by input), `integrationAlias` (required when the integration has more than one configuration) |
| `AWS` | `actionIdentifier` (string, required, such as `aws.ec2.describeInstances`), `inputs` (object, required), `accountId` (string, required, supports templates), `region` (string, required, such as `us-east-1`, supports templates) |
| `SLACK` | `channel` (required, the channel name without `#`), `message` (required) |
| `MS_TEAMS_SEND_MESSAGE` | `teamId`, `channelId`, `message` (all required) |
| `PAGERDUTY_CREATE_INCIDENT` | `serviceId`, `title`, `body`, `fromEmail`, `urgency` (`HIGH` or `LOW`), all required; `incidentTypeName` |
| `GITHUB_CREATE_OR_UPDATE_FILE` | `alias`, `repositoryName`, `path`, `content` (not base64-encoded), `commitMessage`, all required; `branch` (defaults to the default branch), `committer` and `author` (each `{name, email}`) |
| `JIRA_CREATE_ISSUE` | `alias`, `projectKey`, `issueSummary`, `issueType`, `description`, `labels`, `components`, and `fields`, all required (use `[]` or `{}` for none); `assignee`, `reporter`, `priority` |

```yaml theme={null}
schema:
  type: ADVANCED_HTTP_REQUEST
  actionIdentifier: googleCloud.getProject
  integrationAlias: production
  inputs:
    projectId: "{{actions.user-input.outputs.project-id}}"
```

## Validating a definition

Before you save, you can check a definition with the [Validates YAML descriptor](/api/rest/workflows/validates-yaml-descriptor) endpoint. It reports missing required fields, slugs that aren't unique, and broken references between blocks.


## Related topics

- [Adding blocks to a Workflow](/streamline/workflows/blocks.md)
- [Workflows as code](/streamline/workflows/workflows-as-code.md)
- [Referencing a Workflow state in a block](/streamline/workflows/blocks/states.md)
