# Adding blocks to a Workflow

Blocks (formerly called actions) are the building components of Workflows. Each block handles a specific task, and chaining them together lets you run a sequence of operations that can reference contextual data from your workspace.

Cortex offers a searchable library of blocks that can be added to your Workflows. See [How is a Workflow structured](/streamline/workflows.md#structured) for more information.

Blocks are organized into the following categories:

* **Core blocks**
  * Perform actions such as requiring a manual approval on a step within a Workflow.
* **Cortex blocks**
  * Perform Cortex-based actions, such as getting Scorecard scores for an entity.
* **Integration blocks**
  * Perform third-party integration actions such as creating a new GitHub repository or creating a new incident in ServiceNow.

## Prerequisites

1. You must have the `Edit Workflows` permission.
2. An existing Workflow. If you haven't yet created a Workflow, refer to [Creating a Workflow](/streamline/workflows/create.md) and [Configuring Workflow settings](/streamline/workflows/configuring-workflow-settings.md).

{% hint style="info" %}
Every block in a Workflow must have a unique slug.
{% endhint %}

## Configuring a Workflow block (basic)

1. Click the **+ icon**.\
   The **Search for blocks** window opens.
2. Search for and select the block you want to add to the Workflow.
3. In the right pane, configure the block. Note that configuration options differ depending on the block.
4. Click **Save**.
5. Repeat Steps 1 - 4 as necessary.

## Configuring a core block

Expand the tiles below for instructions on configuring each type of block.

<details>

<summary><strong>Branch</strong></summary>

A **Branch** allows you to set up to five conditional paths for a Workflow.

{% hint style="success" %}
**Workflow examples**: See an example demonstrating how to use a Branch block in [Referencing Workflow states in a block](/streamline/workflows/blocks/states.md#block-and-workflow-state-reference-example).
{% endhint %}

**Configure a branch**

To configure a branch:

1. Click **Branch** from the list of blocks.
2. On the right side of the page, enter a **Block name**.
   * The slug field will automatically pre-populate based on the name you enter.
3. Click **+Add Path**.\
   ![](/files/nJIuqFGWovhpioYwqWyg)
4. On the right side of the page, the "Conditional paths" section will expand. Enter a name, a slug, and a path expression.\
   ![](/files/XPzeaYjJg7YGltLByHte)
   * The path expression is compatible with [CEL syntax](https://cel.dev/). The path expression does not accept dashed values; if you reference a block's slug that contains a dash, wrap the slug in quotes and square brackets.
     * For example, if you want to reference a block with the slug `slug-example`, the expression would begin with `actions["slug-example"]`.
     * Note: Autocomplete will provide correctly formatted options based on the blocks defined in your Workflow.
5. Under the Path expression text box, click **Save**.
   * You will be redirected to the block editor page, showing your newly-added path in the Workflow visual.
6. Optionally, add additional paths and a fallback path.
   * Click **+** under a path to add the next type of block. You can add any type, including another branch.
7. When you are finished adding paths, click **Save** at the bottom of the block editor.
8. If you want to add additional blocks that occur after the paths within your branch, click **+** below the branch box in the Workflow editor.

**How paths work**

The paths defined run sequentially. The first path that returns `true` will execute, even if subsequent paths would also return `true`. The Workflow will then continue performing blocks in that path. You can also set a fallback path that will run if all other paths fail.

Primary and nested branches function the same way.

**Nested branches**

To nest a branch:

1. In the visual Workflow, click the **+** that is branched off your original branch.
2. On the right side of the page in the Workflow editor, select **Branch**.
3. Enter a name for your branch, then click **Save**.

There are no limits on how many branches you can nest.

</details>

<details>

<summary><strong>Data transformation</strong></summary>

A **Data transformation** performs data transformations using jq. Except for the block name and slug, the only field required is the **jq expression**.

{% hint style="success" %}
**Use cases**: Manipulate or format data between steps. For example, transform user input before sending it to an API or before using it in another Workflow block.\
\
**Workflow examples**: See an example demonstrating how to use a Data transformation block in [Referencing Workflow states in a block](/streamline/workflows/blocks/states.md#block-and-workflow-state-reference-example).
{% endhint %}

**Configure a data transformation**

To configure a data transformation:

1. Click **Data transformation** from the list of blocks.
2. Enter a name.
   * The slug field will automatically pre-populate based on the name you enter.
3. Enter a [jq](https://jqlang.github.io/jq/) expression. This field can pass any sort of jq expression, as long as the variables and context are referenced differently.
   * Although you would typically use `{}` to template the context of your Workflow, in this field you’ll need to reference such values as jq query values.
4. Click **Save**.

</details>

<details>

<summary><strong>HTTP request</strong></summary>

The HTTP request makes and records a request to a given URL, allowing you to integrate with external APIs or internal systems.

For use cases requiring asynchronous operations (e.g., provisioning cloud resources, CI/CD pipelines), use the [HTTP async action](#http-action-async).

{% hint style="success" %}
See an example demonstrating how to use an HTTP block in [Scaffolding a new service with custom data based on user input](/guides/production-readiness/standardize-new-service-creation.md).
{% endhint %}

**Configure an HTTP request**

To configure an HTTP request:

1. Click **HTTP request** from the list of blocks.
2. Enter a name.
   * The slug field will automatically pre-populate based on the name you enter.
3. Select an HTTP method. The options are `DELETE`, `GET`, `PATCH`, `POST`, or `PUT`.
4. Configure the fields:
   * **URL**: Enter a static URL or use a template to reference other blocks.
     * If you use `{{actions.url.outputs.result}}`, for example, you can set the URL to the output of a jq action. In this example:
       * `.actions` indicates a reference to a Workflow block
       * `.url` is the slug for the Workflow block we’re referencing
       * `.outputs` is the location of the actual output of the jq expression
       * `.result` is the result field where the output is stored
     * Because [Mustache](https://en.wikipedia.org/wiki/Mustache_\(template_system\)) performs HTML escaping by default, special characters referenced in a value with two curly braces (`{{}}`) will be converted to their associated HTML encoding. For example, `{{=}}` would become `&#61`. To reference a non-escaped value, use three curly braces (`{{{=}}}`).
   * **Headers**: Click one of the options provided, or enter your own.
     * When using a secret with a header, prefix the secret with `context.`.
   * **Payload**: This field appears if you are using an HTTP request that sends a payload. The payload that you supply can also be templated and can reference an entity that the Workflow is being run with. Some additional steps are required to properly template raw JSON in the payload field:
     * Single primitive values will work as expected. To add JSON objects or arrays, create a [Data Transformation block](#data-transformation) that accesses the relevant JSON and pipes it into the `tojson` built-in.
       * For example, `.context.initiatedBy | tojson` would enable a user to add the full `initiatedBy` object `()` into an HTTP request payload. When templating this value, three curly braces are needed in order to reference a non-escaped value. Continuing our earlier example, if the Data Transformation block we just created has the slug `transform-to-json`, then the payload would include `{{{actions.transform-to-json.outputs.result}}}`.
5. Click **Save**.

{% hint style="warning" %}
If using special characters when templating, make sure to include three curly braces to reference a non-HTML-escaped value.
{% endhint %}

</details>

<details>

<summary><strong>HTTP action (async)</strong></summary>

The HTTP async request makes and records a request to a given URL. This block will pause execution until a [callback API](/api/readme/workflows.md#post-api-v1-workflows-tagorid-callback-callbackid) is invoked or a timeout occurs, enabling long-running Workflows.

{% hint style="info" %}
You can pass the callback URL to the external service by using the template variable `{{callbackUrl}}`. This can be passed as part of the URL, in a header, or in the payload.

For example, when passing the variable in a URL, it would look like the following format: `https://example.com/?url={{callbackUrl}}`.
{% endhint %}

**Configure an HTTP async request**

1. Click **HTTP action (async)** from the list of blocks.
2. Enter a name.
   * The slug field will automatically pre-populate based on the name you enter.
3. Select an HTTP method. The options are `DELETE`, `GET`, `PATCH`, `POST`, or `PUT`.
4. Configure the fields:
   * **URL**: Enter a static URL or use a template to reference other blocks.
     * If you use `{{actions.url.outputs.result}}`, for example, you can set the URL to the output of a jq action. In this example:
       * `.actions` indicates a reference to a Workflow block
       * `.url` is the slug for the Workflow block we’re referencing
       * `.outputs` is the location of the actual output of the jq expression
       * `.result` is the result field where the output is stored
     * Because [Mustache](https://en.wikipedia.org/wiki/Mustache_\(template_system\)) performs HTML escaping by default, special characters referenced in a value with two curly braces (`{{}}`) will be converted to their associated HTML encoding. For example, `{{=}}` would become `&#61`. To reference a non-escaped value, use three curly braces (`{{{=}}}`).
   * **Headers**:
     * Include an Authorization header and use a[ personal access token](/configure/settings/api-keys/personal-tokens.md).
     * Optionally include additional headers: Click one of the provided headers, or enter your own.
     * When using a secret with a header, prefix the secret with `context.`.
   * **Payload**: This field appears if you are using an HTTP request that sends a payload. The payload that you supply can also be templated and can reference an entity that the Workflow is being run with. Some additional steps are required to properly template raw JSON in the payload field.
     * Single primitive values will work as expected, but to add JSON objects or arrays, follow these steps you first need to create a [Data Transformation action](#data-transformation) that accesses the relevant JSON and pipes it into the `tojson` built-in.
     * For example, `.context.initiatedBy | tojson` would enable a user to add the full `initiatedBy` object `()` into an HTTP request payload. When templating this value, three curly braces are needed in order to reference a non-escaped value. Continuing our earlier example, if the data transformation action we just created has the slug `transform-to-json`, then the payload would include `{{{actions.transform-to-json.outputs.result}}}`.
   * **Timeout**: Configure a timeout for this action. The maximum is 30 days and the minimum is 1 minute.
     * After a timeout, the block will fail with the status `timed_out`. If you have notifications enabled, you will receive a notification if you initiate a Workflow and it times out.
5. Click **Save**.

{% hint style="warning" %}
If using special characters when templating, make sure to include three curly braces to reference a non-HTML-escaped value.
{% endhint %}

**Handling the callback**

Once the HTTP Async Request block runs, Cortex sends the configured request and pauses the Workflow. To resume execution, the external system must call the callback URL provided by Cortex and follow the required schema.

The callback request must:

* Use the `POST` method
* Include a valid Cortex API key in the `Authorization` header (`Bearer <token>`)
* Match the expected request body shape. Below is an example:

```
{
  "message": "Provisioning complete – sandbox environment created.",
  "response": {
    "env_id": "sandbox-abc123"
  },
  "status": "SUCCESS"
}
```

See the full [Cortex API reference](https://docs.cortex.io/api/rest/workflows#post-api-v1-workflows-tagorid-callback-callbackid) for callback details and status options (`SUCCESS`, `FAILURE`, `CANCELLED`).

{% hint style="warning" %}
If the callback is missing required fields, improperly formatted, or lacks authentication, Cortex will not accept it, and the Workflow will remain paused or fail.
{% endhint %}

</details>

<details>

<summary><strong>JavaScript</strong></summary>

**Configure a JavaScript block**

Use a JavaScript block to insert custom code or add looping and other logic to your Workflows.

The JavaScript runtime supports the [ES2020](https://tc39.es/ecma262/) specification and has an implementation of [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch), allowing you to make HTTP requests directly in the script rather than needing to add an additional HTTP request block to your Workflow.

{% hint style="success" %}
See an example demonstrating how to use a JavaScript block: [Looping in a JavaScript block and returning a specified output](/guides/operational-readiness/javascript-looping.md)
{% endhint %}

To test your block's code locally, you can use [Cortex's JavaScript harness](https://github.com/cortexapps/js-action-harness).

1. Click **JavaScript** from the list of blocks.
2. On the right side of the page, configure the fields:
   * **Block name**: Enter a descriptive name for your block.
   * **Slug**: The slug field will automatically pre-populate based on the name you enter.
   * **JavaScript**: Enter the script you want to run. The script must end with a `return` statement. The value from the `return` statement is exposed via `outputs.result`.
     * For example, in the script `return {"a": 1, "b": 2}`, the result can be referenced from subsequent blocks as `actions.<SLUG>.outputs.a`.
     * You can reference previous blocks and run context by accessing `actions` and `context`. For example, `actions["jq"].outputs.result.`
       * Learn more about [referencing blocks and Workflow states here](/streamline/workflows/blocks/states.md).
     * If you want the block to fail, you can use the `throw` statement. For example:

       ```
       let previous = actions.previous.outputs.result;
       if (previous == null) {
         throw "Some error";
       }
       ```
3. Click **Save**.

</details>

<details>

<summary><strong>Manual approval</strong></summary>

A **Manual approval** pauses the Workflow to get approval from a member of a given Team. Like with user inputs, the Workflow will proceed to the next block once it has been approved.

**Configure a manual approval**

To configure a manual approval:

1. Click **Manual approval** from the list of blocks.
2. Enter a name.
   * The slug field will automatically pre-populate based on the name you enter.
3. Under **Teams allowed to approve**, select one or more teams who are allowed to approve the request from this block. Any member of a given team can approve the block.
4. Click **Save**.

You can have multiple manual approvals within a given Workflow. If you have two blocks with two different sets of teams set as approvers, each team will only be able to approve the block they are defined under.

**Pending approval**

When a manual approval block is triggered, users that belong to teams designated as approvers will see **Pending approvals** at the top of their Workflows page.

<img src="/files/xptzHvRq0dCaPppd3i0g" alt="workflows 23" data-size="original">

This section displays any blocks that are pending your approval. If manual approval actions exist within a Workflow, but do not require your approval, they will not appear here, even if you are designated to approve a different block in the same Workflow.

You can open any Workflow in the pending approval list to **Approve** or **Reject** the block.

Once all of your approval requests have been approved or rejected, this tab will disappear from the Workflows page.

</details>

<details>

<summary><strong>Run Workflow</strong></summary>

The **Run workflow** block calls another Workflow from inside the current one, letting you chain Workflows together.

{% hint style="info" %}
The embedded Workflow and the parent Workflow have a strict parent‑child relationship to prevent accidental Workflow looping.
{% endhint %}

**To configure a Run Workflow block**:

1. Click **Run workflow** from the list of blocks.
2. Under **Block name**, enter a name. The slug field auto‑populates based on the name.
3. From the **Workflow** drop‑down menu, select the Workflow to run.
4. Optionally, from the **Entity** drop‑down menu, select an entity to run the target Workflow against. If the target Workflow is entity‑scoped and no entity is provided, it pauses for input at runtime.
5. Click **Save**.

</details>

<details>

<summary><strong>Scaffolder</strong></summary>

The **Scaffolder** uses a Cortex Scaffolder template to perform a given function. You must have the `Execute Scaffolder` permission to configure a Scaffolder block.

See the docs to learn about [registering a Scaffolder template](/streamline/workflows/scaffolder.md).

{% hint style="success" %}
**Use cases**: Standardize and bootstrap service creation

**Workflow example**: See an example demonstrating how to use a Scaffolder block in [Scaffolding a new service with custom data based on user input](/guides/production-readiness/standardize-new-service-creation.md).
{% endhint %}

To configure a Scaffolder:

1. Click **Scaffolder** from the list of blocks.
2. Enter a name.
   * The slug field will automatically pre-populate based on the name you enter.
3. Under **Scaffolder template**, select a template from the dropdown.
   * This dropdown pulls in all templates available from the Scaffolder page.
4. Configure the remaining fields. The fields differ depending on the template's specifications and available Git providers. The option to create a repo also may or may not be visible, depending on whether the template requires a pull request.
5. Click **Save**.

{% hint style="warning" %}
If using the Scaffolder to create a new repo and the desired repo already exists, Cortex will surface an error and prevent the flow from continuing.
{% endhint %}

**Define Scaffolder template overrides**

You can also define **Scaffolder template overrides** for a block — these will override template fields with output variables from a previous Workflow step, or from the context of the Workflow.

To add an override:

1. In the bottom of the block configuration, click **Add variable**.
2. In the override variable modal, click the **Variable** dropdown to select the Scaffolder template fields to override. Note that the options in this dropdown will be pulled from fields in the Scaffolder template you selected in the first step.\
   ![workflows 12](/files/78SohOExxXj51Tsv7nDc)
3. Under **Path**, enter the path to the actual value we want in the Workflow.
   * For example, if you wanted to override the **Project name** variable for a Scaffolder with the tag of the entity you’re running, the path would be `context.entity.tag` — that will obtain and supply the value.
4. If you want to override the options that are available to a user running the Workflow, toggle on **Is value override**.
   * For example, if you wanted to restrict the project name to some set of values based on a particular HTTP fetch, you would toggle this setting on.
   * When toggled **on**, the value being grabbed in lieu of `project_name` is the value of the variable. When toggled **off**, the value grabbed would be the option provided for that variable, i.e. the project name.

**Running a workflow with a Scaffolder step**

When you run a workflow with a Scaffolder block, the Scaffolder will prompt you for user input. Some fields, such as **Commit message** and **Pull request title**, only appear if your Scaffolder step creates a Pull Request rather than a repository.

After the inputs are provided, the Scaffolder will run. When the run is complete, you will see a link to the newly-created repository and the entity in Cortex.

{% hint style="warning" %}
**Note:** For GitLab, Azure DevOps, and Bitbucket, the branch name entered when running this block must match the default branch of the target repository in your Git provider.
{% endhint %}

</details>

<details>

<summary><strong>User input</strong></summary>

The **User input** block pauses the Workflow and prompts the user for specific inputs. Once user inputs are entered, the Workflow will proceed to the next block.

{% hint style="success" %}
**Use cases**: Collect new developer details (name, email, GitHub username) during onboarding, or gather IAM policy requirements before creating a policy in AWS.

**Workflow example**: Onboard a new developer > Collect user information in User input block > Subsequent actions use this data to create accounts and send notifications.\
\
See examples demonstrating how to use a User Input block in [Looping in a JavaScript block and returning specified output](/guides/operational-readiness/javascript-looping.md) and [Scaffolding a new service with custom data based on user input](/guides/production-readiness/standardize-new-service-creation.md).
{% endhint %}

{% hint style="warning" %}
Note that users with the `Edit Workflows` permission are inherently able to obtain secret values using complex data transformation on secrets or echoing services.
{% endhint %}

To configure a user input block:

1. Click **User input** from the list of actions.
2. Enter a name.
   * The slug field will automatically pre-populate based on the name you enter.
3. Click **Add user input**.\ <img src="/files/xWGZd95TXNMYIObfYfkB" alt="" data-size="original">
4. Configure the "Create input field" form:
   * **Name**: Enter a name for the input field.
   * **Key**: Enter a value to be used when templating. This must be unique across fields in a given user input block.
   * **Description**: Enter a description of the input field.
     * It is possible to use templating to reference previous block outputs in the description.
       * For example, if a previous step creates a Pull Request and outputs the URL of the PR, you might want to reference it in the description of a subsequent User Input step using a template: `Confirm that you have merged the Pull Request created here: {{ actions.<block-slug>.outputs.response.gitURL }}`
   * **Type**: Select from the following:
     * `Date`: Date in YYYY-MM-DD format.
     * `Number`: A numerical value.
       * If you select this type, you can then choose `Integer` or `Decimal` for the number format, and select a minimum and maximum value.
     * `Paragraph`: Multi-line, freeform text.
     * `Secret`: Capture a secret value.
     * `Select`: Manually configured or predefined data selection.
       * Toggle on **Allow multiple** to enable multiple selections for a given input field.
     * `Text`: Short, freeform text.
     * `Toggle`: Boolean value.
     * `Nested form`: Users can enter data multiple times for the inputs you configure.
       * Additional configuration is required for this type. See the additional steps for the `Nested form` type below.
   * **Placeholder**: Enter text to display when a field is empty.
   * **Default value**: Enter a value that will automatically populate the field.
   * **Validation regex**: Set validation options for the input field.
     * If you chose the `Secret` type, enter the secret value that a user will need to input to run this action.
   * **Path to override value**: Optionally, enter the previous block output path to override the value of a given input.
     * For example, if the key is `name`, then entering `actions.name-action.outputs.name` in the previous block output path field will use the output from a previous step as the name.
     * **Is override value editable**: Enable this option if you want to allow users to edit the override value before continuing to execute the Workflow.\
       ![](/files/7P2mx8K6IbY3p9u1sw3f)
5. To add validation logic, enable the toggle next to **Validation logic**.
   * See "Add valiation logic" below for more information.
6. Additional configuration is required for the `Select` type. See the [additional steps for the `Select` type](#additional-steps-for-the-select-type) below.
7. Click **Add input** at the bottom of the "Edit input field" modal.
8. Click **Save**.

**Additional steps for the `Select` type**

If you chose the type `Select` while configuring the user input block, additional fields must be configured depending on which **Data source** you select:

* **Manual** data source: You can manually define each option for the input. You can select any of these defined options as the default value.
  * When adding options you can define a label for it. If the label is not defined, the value will be used as the label.
* **Cortex entity** data source: You can filter the entities that will be available for user selection. If you don't set filters, the input will apply to all entities.
  * If you want the user running the Workflow to only see their owned entities as options during this User Input step, enable the toggle next to **Limit options to runner user's scope**.
    * To only show the user teams they belong to, enable this toggle *and* select `team` under the **Entity type** filtering option.
* **Cortex user** data source: You can filter by teams and users to determine the options available to users. If you don't set filters, the input will apply to all Cortex users and Teams.
* **Slack channels** data source: You can choose to include or exclude one or more Slack channels from the available options. The default values will include all Slack channels registered in Cortex.

**Additional steps for the `Nested form` type**

A nested form allows users to provide an arbitrary number of responses to a form. For example, you may have a data warehouse form built into your Workflow, requiring users to enter a name and size for their database instance. If they create multiple instances, they can enter multiple responses in the form.

You will be able to nest up to 5 layers of forms using the `Nested form` input by adding additional nested form input layers.

There are additional configuration options while adding a `Nested form`:

* **Element count**: You can set a minimum and maximum number of elements that users can enter.
* **Path to override value**: You can override the input itself with an array of objects. It must meet the allowed element count limits.

**Add validation logic**

You can define custom JavaScript-based validations on Workflow input fields, ensuring that users are correctly inputting required fields and adhering to standards. For example, you might want to configure validation to ensure users are adhering to predefined naming conventions for new repositories or you may want to validate that the chosen repository name is unique.

To add validation:

1. While configuring the user input block, click the toggle to enable **Validation logic**.
2. Enter a JavaScript expression.
   * You can call `validator.addInputViolation` to display an error on a specific input, and `validator.addGlobalViolation` to display an error at the top of the form.
     * If you call `validator.addInputViolation` with an invalid input key, the error will display at the top of the form.
   * For example, the following expression adds validation to ensure that a role value has at least three characters and the selected date must be in the future. It is configured to display input-specific errors for the `User role` and `Target date` inputs, and a global error if any field is invalid:

```javascript
let currentOutputs = actions['user-input'].outputs;
let isAnyFieldInvalid = false;

if(currentOutputs['user-role'].length < 3) {
    validator.addInputViolation('user-role', "Role must have at least 3 characters")
    isAnyFieldInvalid = true;
}

let selectedDate = Date.parse(currentOutputs['target-date'])
let currentDate = Date.now()
if(selectedDate < currentDate) {
    validator.addInputViolation('target-date', "Selected date must be in the future")
    isAnyFieldInvalid = true;
}

if(isAnyFieldInvalid) {
    validator.addGlobalViolation("Not all fields are valid, please fix before continuing");
}
```

When you run the Workflow and enter a response to the user input, the validation logic runs. If there are any issues, they are flagged at that time. Based on the example above, errors will appear if you do not enter at least three characters for the `user role` field value, and if you do not select a date in the future for the `target date` field.\
![Errors appear based on the JavaScript validation expression.](/files/pMYFa4CGfHIiIZT3d1s0)

</details>

<details>

<summary><strong>Set variable(s)</strong></summary>

This block allows you to set or update specific variables during a Workflow. The variables must be declared in the [Workflow's basic settings](/streamline/workflows/create.md#step-2-configure-your-workflow-settings).

To configure a Set variable(s) block:

1. Click **Set variable(s)** from the list of blocks.
2. Enter a slug for the block.
   * The slug field will automatically pre-populate based on the name you enter.
3. In the **Variable** dropdown, select the variable you want to set/update.
4. Define how you want to set the variable's value. You can use a direct reference or use JavaScript.
5. Optionally, set additional variables.
6. Click **Save**.

</details>

## Configuring an integration block

**Prerequisites**

1. Ensure the integration is installed in your Cortex workspace.
2. Ensure the integration is configured with the correct permissions. Refer to [Integrations](/ingesting-data-into-cortex/integrations.md#third-party-integrations) for more information.

{% hint style="info" %}
If an integration supports multiple configurations, you'll be prompted to select the **configuration alias** to use with the block. The block authenticates using the selected configuration, so ensure that you select the configuration with the appropriate permissions.
{% endhint %}

Cortex provides prebuilt blocks to perform a variety of actions for the following integrations. Expand an integration below to view available blocks.

<details>

<summary><strong>AWS</strong></summary>

* Attach role policy
* Create EC2 security group
* Create IAM group
* Create IAM role
* Create S3 bucket
* Describe EC2 instances
* List buckets
* Put role policy
* Run EC2 instances

</details>

<details>

<summary><strong>Azure DevOps</strong></summary>

* Create a branch
* Create branch policies
* Create file
* Create repository
* Delete a branch
* Delete branch policy
* Delete file
* Delete repository
* Fetch latest commit ID
* Get a branch
* Get all branches
* Get branch policy
* Get file
* Get pipeline
* Get pipeline run details
* Get repository
* List branch policies
* List pipeline runs
* List pipelines
* List repositories
* Rename a branch
* Run pipeline
* Update branch policies
* Update file

</details>

<details>

<summary><strong>Bitbucket</strong></summary>

* Create repository
* Get file
* Update branch protection

</details>

<details>

<summary><strong>GitHub</strong></summary>

* Add label to pull request
* Add user to org
* Add user to team
* Create a branch
* Create deployment
* Create or update custom property values
* Create or update a file
* Create a pull request
* Create a pull request comment
* Create reference (or branch)
* Create release
* Create repository
* Create team
* Delete a branch
* Delete branch protection rules
* Delete file
* Delete team
* Find files
* Get a branch
* Get branch protection rules
* Get commit
* Get deployment
* Get file
* Get release by tag
* Get team
* Get team membership
* List branches
* List commits
* List deployments
* List organization members
* List releases
* List repositories
* List team members
* List teams
* Merge a branch
* Remove user from organization
* Remove user from team
* Rename a branch
* Trigger workflow
* Update branch protection rules
* Update repository

</details>

<details>

<summary><strong>GitLab</strong></summary>

* Archive project
* Create approval rule
* Create branch protection
* Create file
* Create pipeline schedule
* Create project
* Create project access token
* Create project variable
* Create push rule
* Delete approval rule
* Delete branch protection
* Delete file
* Delete pipeline schedule
* Delete project
* Delete project variable
* Delete push rule
* Get approval configuration
* Get approval rule
* Get file
* Get pipeline schedule
* Get project
* Get project variable Get protected branch
* Get push rule
* List approval rules
* List pipeline schedules
* List project access tokens
* List project variables
* List protected branches
* Revoke project access token
* Rotate project access token
* Run pipeline
* Unarchive project
* Update approval configuration
* Update approval rule
* Update branch protection
* Update file
* Update pipeline schedule
* Update project
* Update project variable

</details>

<details>

<summary><strong>Google Cloud</strong></summary>

* Create project
* Delete project
* Get project
* List projects
* Update project

</details>

<details>

<summary><strong>Jenkins</strong></summary>

* Run a build
* Run a build with parameters

</details>

<details>

<summary><strong>LaunchDarkly</strong></summary>

* Create a feature flag
* Delete a feature flag
* Get feature flag
* List feature flags
* List projects
* Toggle feature flags
* Update a feature flag

</details>

<details>

<summary><strong>Microsoft Teams</strong></summary>

* Send message

</details>

<details>

<summary><strong>PagerDuty</strong></summary>

* Create escalation policy
* Create incident
* Create schedule
* Create service
* Create team
* Delete escalation policy
* Delete schedule
* Delete service
* Delete team
* Get escalation policy
* Get schedule
* Get service
* Get team
* List escalation policies
* List incidents
* List schedules
* List services
* List teams
* List users
* Schedule override
* Update escalation policy
* Update schedule
* Update service
* Update team

</details>

<details>

<summary><strong>ServiceNow</strong></summary>

* Create incident
* Create record
* Delete incident
* Delete record
* Get incident
* Get record
* Get user by email
* Get user information
* List groups
* List incident categories
* List incident subcategories
* List incidents
* List records
* List users
* Update record

</details>

<details>

<summary><strong>Slack</strong></summary>

* Get channel info
* Get user by email
* List channels
* List members in channel
* List users
* Send message

When using a Slack block:

1. Ensure the [Cortex AI Assistant](/ingesting-data-into-cortex/integrations/slack.md) is added to the appropriate Slack channel.
   * If the AI Assistant isn't in the channel, you'll receive the following error: `Cannot send message to Slack channel without invitation`. To resolve the error, do one of the following:
     * Invite the AI Assistant to the specific channel OR
     * Reinstall the Slack integration to get the latest scopes, which allows posting to public channels without the AI Assistant needing to be a member
2. Ensure the Slack Bot has the correct permission(s) scoped:
   * If the channel is public and the install is up to date (has `chat:write.public`), the bot can post without being a member.
   * If the channel is private, the bot needs `chat:write` and must be invited to the channel.

</details>

**To configure an integration block**:

1. Click the **+ icon**.\
   The **Search for blocks** window opens.
2. Search for the block you want to add to the Workflow.
3. Select a block to view its details, including any permissions required for it to run correctly.
4. Click **Configure**.\
   The block is inserted into your Workflow, and a configuration form appears in the side panel.
5. In the side panel, configure the block metadata:

   * **Block name** - Optionally, change the name of the block. The name auto-populates based on the block name.
   * **Slug** - Optionally, change the slug. The slug auto-populates based on the block name and is made up of letters, digits, and hyphens.

   Metadata differs depending on the block. Any of these inputs can accept dynamic values using Mustache syntax (`{{ ... }}`). For fields that aren't text-based, click the **path icon** on the right of the input to switch into templating mode.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/JbMtENbqxnPU7WcR1dob" alt="Mustache templating displayed when configuring a Workflow block." width="374"><figcaption></figcaption></figure></div>
6. Click **Save**.

## Duplicating a block

There may be an instance where you want to repeat a task within your Workflow. Follow the steps below to duplicate a block.

1. Locate the block you want to duplicate.
2. Click the **Overflow icon** on the right side of the block.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/sbOkztQzdVMsxApTJ62Y" alt="The &#x27;Overflow menu&#x27; icon on a block." width="229"><figcaption></figcaption></figure></div>
3. Click **Duplicate block**. A copy of the block is placed in the Workflow.
4. Optionally, hover over the block and use the **grip icon** to drag it to a new position in the Workflow.

## Using request signing with Workflow blocks

Refer to the documentation for [using request signing with Workflow blocks](/streamline/workflows/blocks/using-request-signing-with-workflow-blocks.md).

## Referencing a Workflow state in a block

Refer to the documentation for [referencing a Workflow state in a block](/streamline/workflows/blocks/states.md).

[Next step: Running a Workflow](/streamline/workflows/run.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.cortex.io/streamline/workflows/blocks.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
