---
title: Setting Up a Flow Action | Shopware Community Hub
description: >-
  Learn how to define a custom Flow Action that sends order data from Shopware
  to your App Server.
canonical_url: 'https://hub.shopware.com/learn/unit/set-up-flow-action'
---

# Setting Up a Flow Action

<LearningObjectives>

- **Understand** the **difference** between **Flow Actions and Webhooks**.
- **Define a custom Flow Action** in the `flow.xml` file.
- **Pass order data** (headers and parameters) from Shopware to the App Server.
- **Understand ACL (Access Control List) permissions** and why they are critical for **App security**.
- **Configure the required permissions** in the `manifest.xml` file.
- **Use the Flow Builder** in the Shopware administration to **configure and test your custom Flow Action**.

</LearningObjectives>

# Setting Up a Flow Action

You have now learned how to set up an App Server and how to define webhooks. You learned that Shopware can notify your App Server **when events occur**. In this learning unit, you will learn about **Flow Actions** — another way for Shopware to communicate with your App Server.

## Understanding Flow Actions vs. Webhooks

Both **Flow Actions** and **Webhooks** allow your App Server to react to events in Shopware, but they serve different purposes:

| Aspect                    | Webhooks                                        | Flow Actions                                                         |
|---------------------------|-------------------------------------------------|----------------------------------------------------------------------|
| **Who configures it?**    | Developer (in `manifest.xml`)                   | Merchant (in Flow Builder UI)                                        |
| **When does it trigger?** | Automatically when an event occurs              | Only when used in a merchant-configured flow                         |
| **Flexibility**           | Fixed logic for all shops                       | Merchants can combine with conditions, delays, and other actions     |
| **Use case**              | Background tasks, logging, external system sync | Merchant-customizable workflows (e.g., conditional order processing) |

**Example:**

- A **Webhook** (`order.placed`) always fires when an order is placed—no matter what. Your App Server receives the notification automatically.
- A **Flow Action** (`Issue Dispatch Note`) only runs when a merchant adds it to a flow in the Flow Builder. The merchant decides the trigger (e.g., "order is paid") and can add conditions (e.g., "only for orders over €100").

**In short:** Webhooks are for developers to automate tasks. Flow Actions are for merchants to build custom workflows.

## What You Will Build

The [Flow Builder](https://www.shopware.com/en/products/ecommerce-automation/flow-builder/) is a core capability in Shopware that allows merchants to automate business logic without writing code. In this learning unit, you will create a **custom Flow Action** that merchants can use in their flows.

By the end, your action will:

- Be selectable in the Flow Builder UI
- Call an HTTP endpoint on your App Server when triggered
- Pass order data to your App Server for processing

## Code-Along

<Callout title="Switch Over to Shopware for This Part" type="info">

In this section we will be working with the `ShopwareStoreTracker` App, so make sure you switch over to the Shopware workspace in your IDE.

</Callout>

To follow along, use the following command in the terminal:

```bash
git checkout tags/setup_flow_action--start
```

## Coding Requirements

Imagine the following scenario: Our client **BigSpace** wants to notify their warehouse automatically once an order is fully paid. The business requirement can be described in [Gherkin](https://cucumber.io/docs/gherkin/reference/) notation:

```txt
WHEN the customer places an order in the Shopware Shop
AND the order has been fully paid for
THEN extract relevant data from the order
AND construct a note for the warehouse to dispatch relevant items
```

Here is an illustration of the process we will be carrying out at a high level:

![Illustration of logical process for flow builder action](assets/flow-order-process.png)

<Callout title="Typical Workflow for Warehouse Notification" type="info">

The use-case of automatically sending documents via the Flow-Builder is [already covered in Shopware documentation](https://docs.shopware.com/en/shopware-6-en/tutorials-and-faq/flow-builder-example-flows#notification). In this learning unit, we extend that idea: instead of just sending a document, we will create new entries in a newly defined `DispatchNote` entity on the App Server.

</Callout>

## Declaring a Flow-Action

To react to the Flow Builder events with your App Server, Shopware needs to know which endpoint to call. This is done by defining a [**Flow Action**](https://developer.shopware.com/docs/concepts/framework/flow-concept.html#action) in the Shopware App.

All Flow Action and Flow Trigger definitions are declared in the [flow.xml file](https://github.com/shopware/shopware/blob/trunk/src/Core/Framework/App/Flow/Schema/flow-1.0.xsd) located at `[app_root]/Resources/flow.xml`.

<Callout title="Looking Ahead" type="info">

Later you will implement a Symfony Controller on the App Server to handle these requests.

</Callout>

### Declaring an Action

#### 1. Define Root Elements

First, create the `flow.xml` file in your App directory at `[app_root]/Resources/flow.xml`. Add the following root elements to set up the schema and the `flow-actions` container:

```xml
<flow-extensions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/shopware/shopware/trunk/src/Core/Framework/App/Flow/Schema/flow-1.0.xsd">
    <flow-actions>
    </flow-actions>
</flow-extensions>
```

This establishes the basic structure for defining Flow Actions in your App.

#### 2. Add a New Flow Action Entry

Inside the `flow-actions` section, add a `flow-action` element. This defines the action and its metadata:

```xml
<flow-action>
  <meta>
    <name>senddispatchnote</name>
    <label>Issue Dispatch Note</label>
    <description>Sends a notification to the ERP system to dispatch an order</description>
    <requirements>orderAware</requirements>
    <url>http://localhost:8001/dispatch-note</url>
  </meta>
  <!-- further configuration will go here... -->
</flow-action>
```

The `meta` section contains core details about our Flow Action, such as:

- **Name**: The internal identifier, in this case `senddispatchnote`.
- **Label**: Display name in the Flow Builder, in this case 'Issue Dispatch Note'.
- **Description**: Explains the action's purpose, in this case 'Sends a notification to the ERP system to dispatch an order.'
- **Requirements**:Dependencies on other Shopware entities, in this case `orderAware`.
- **URL**: The endpoint which Shopware will call (crucial for App-Server communication).

<Callout title="Endpoint Options" type="info">

The endpoint URL in `meta` section doesn't have to point to your App Server. You can also integrate third-party APIs such as [Slack API](https://docs.slack.dev/) or [HubSpot API](https://developers.hubspot.com/docs/api-reference/search/guide) to trigger follow-up actions.

</Callout>

#### 3. Specify Headers and Parameters

Next, define the headers and parameters that Shopware will send to your App Server. Inside the `flow-action` section, use `headers` and `parameters` to specify the request headers and parameters respectively.

```xml
<flow-action>
    <meta>
        <!-- meta-data goes here -->
    </meta>
    <!-- the request headers sent to the endpoint -->
    <headers>
        <parameter type="string" name="Accept-Encoding" value="application/json"/>
    </headers>
    <!-- 
        Request URL parameters. These will end up as individual arguments to our Controller method (defined in the next module)
    -->
    <parameters>
        <parameter type="string" name="orderId" value="{{ order.id }}"/>
        <parameter type="string" name="shopwareOrderNumber" value="{{ order.orderNumber }}" />
        <parameter type="string" name="customerDelivery_1" value='{{ order.addresses[0].street }}'/>
        <parameter type="string" name="customerDelivery_2" value='{{ order.addresses[0].additionalAddressLine1 }}'/>
        <parameter type="string" name="customerDelivery_3" value='{{ order.addresses[0].additionalAddressLine2 }}'/>
        <parameter type="string" name="customerDelivery_4" value='{{ order.addresses[0].city }}'/>
        <parameter type="string" name="customerDelivery_5" value='{{ order.addresses[0].zipcode }}'/>
        <parameter type="string" name="customerEmail" value="{{ order.orderCustomer.email }}"/>
    </parameters>
    <config>
        <!-- config values here -->
    </config>
</flow-action>
```

As you can see, we have used a [Twig-like](https://twig.symfony.com) syntax to extract order data provided by the [OrderAware](https://developer.shopware.com/docs/guides/plugins/plugins/framework/flow/add-flow-builder-trigger.html#event-interfaces-and-classes) interface:

- The `order.id`, the internal order reference.
- The `order.orderCustomer.email`, the customer's email address.
- The `order.addresses[0]...`, the first delivery address, split into multiple string-type parameters.

<Callout title="Limitations of Object Notation" type="info">

The `parameters` section only supports primitive types (`string`, `int`, `float`, `bool`). You cannot pass complex objects directly, so addresses are split into indexed parameters (`customerDelivery_1`, `customerDelivery_2`, and so on).  

</Callout>

#### 4. Add a "Dummy" Configuration Option

The [`flow.xml` document schema](https://github.com/shopware/shopware/blob/trunk/src/Core/Framework/App/Flow/Schema/flow-1.0.xsd) requires that every Flow Action contains a `config` section with at least one `input-field`.

In our case, we don't need any real configuration yet, so we add a simple _'dummy' entry_ inside the `config` section. This ensures the Flow Action can be used in the Admin panel.

```xml
    <flow-action>
        <meta>
        </meta>
        <headers>
        </headers>
        <parameters>
        </parameters>
        <config>
        <input-field>
            <name>urgentDispatch</name>
            <label>Does the order need to be dispatched urgently?</label>
            <defaultValue>False</defaultValue>
            <helpText>Gives warehouse awareness if the order dispatch is urgent or not</helpText>
            <required>false</required>
            <options>
            <option value="true">
                <label>True</label>
            </option>
            <option value="false">
                <label>False</label>
            </option>
            </options>
        </input-field>
        </config>
    </flow-action>
```

When this Flow Action is selected in the Admin panel, a configuration modal will appear with this field, even though in this example it has no functional effect.

## Understanding ACL Permissions

Before your Flow Action can work, you need to configure **ACL (Access Control List) permissions**. This is a critical security feature of the Shopware App System.

### What is ACL?

ACL (Access Control List) defines **what your App is allowed to do** in Shopware. It works like the permission system in Android or iOS apps: merchants can see exactly what data your App accesses before installing it.

In Shopware Apps, ACL is enforced via the `permissions` section of the `manifest.xml` file. You must explicitly list:

- Which **entities** your App can access (e.g., `order`, `product`, `customer`)
- Which **CRUD operations** you need (`create`, `read`, `update`, `delete`)

**Anything not listed will be denied.** This ensures Apps cannot access data they don't need.

### Why ACL Matters

ACL is not just a technical requirement—it's a **trust mechanism**:

- **For merchants**: They can review permissions before installing your App.
- **For compliance**: GDPR and other regulations require explicit data access control.
- **For security**: Apps are isolated from each other and from the core system.

<Callout title="Real-World Example" type="warning">

If your App only needs to **read** product data for a catalog sync, but you request **delete** permissions, merchants may refuse to install it. Always request the **minimum permissions** required.

</Callout>

### Configuring Permissions for Flow Actions

In our case, the Flow Action will update the Shopware `Order` entity to add an internal comment (success or failure). For this to work, the App needs explicit permissions.

Open your `manifest.xml` and add the following lines to the `permissions` section:

```xml
<permissions>
  <read>ce_physical_shop</read>
  <create>ce_physical_shop</create>
  <update>ce_physical_shop</update>
  <delete>ce_physical_shop</delete>
  
  <!-- Permissions for Flow Action -->
  <read>order</read> 
  <update>order</update>
</permissions>
```

This grants your App:

- **Read access** to orders (so it can verify the order exists)
- **Update access** to orders (so it can add an internal comment)

<Callout title="Best Practice: Principle of Least Privilege" type="info">

Always grant the **minimum permissions** required for your App to function. This improves security and builds trust with merchants.

</Callout>

### Applying Your Changes

Changes to the `flow.xml` file or permissions only take effect after an App update. Increment your App's version in the `manifest.xml` and run:

```bash
bin/console app:update
```

If you need a detailed reminder on updating Apps, revisit [Learning Unit 01](/learn/unit/app-setting-up-shopware-apps#updatinganapp).

#### Troubleshooting: Schema Validation Errors

You may receive an error message similar to this during the `app:refresh` process:

![Schema error for Flow XML file](assets/flow-file-schema-error.png)

If so, then check your `flow.xml` file for **typos**, **missing tags** or **invalid syntax** (e.g., red squiggly lines).

![VSCode editor pane using red squiggly line to highlight XML syntax mistake](assets/flow-file-typo-highlight.png)

<Callout title="XML Syntax Highlighting" type="info">

Make sure you are using an IDE with XML syntax support. For VSCode the XML syntax support is available via [plugins](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-xml).

</Callout>

## Defining a Flow Sequence in the Shopware Admin

Now that our flow is successfully defined, the next step is to use it in a Flow Builder sequence in the Shopware Admin panel.

### 1. Access Flow Builder Settings

In the Shopware Admin panel, click **Settings** in the side menu:

![Admin settings button](assets/flow-admin-dash.png)

In the main settings menu, select **Flow Builder** under the **Automation** group.

![Flow Builder menu option](assets/flow-settings-menu.png)

### 2. Select a Flow Trigger From Pre-Defined Templates

The Flow Builder interface has two tabs **My flows**, and **Flow templates**. Because Flow Templates do a bit of the work for us already, navigate to this tab and find the entry **Payment enters status paid** in the list. This template already uses the trigger we need: The `state_enter.order_transaction.state.paid`.

![A list of flow templates](assets/flow-template-paid.png)

Click **Create new flow from template**.

### 3. Configure General Settings

In the Flow editor, the **General** tab appears first. Here you can add a name and a description in the flow.

For our purposes, activate the flow by switching the **Active** toggle on. Optionally, raise the **Priority** of the flow in case other flows use the same trigger.

![Screenshot of the general section of a new flow sequence](assets/flow-template-general-view.png)

### 4. Adjust the Flow Execution

Open the **Flow** tab. The template includes a default section **Send mail**. Since we want to notify the warehouse through the App Server, delete the email action and add you custom Flow Action instead.

![Flow Builder delete pre-configured 'email send' action](assets/flow-configuration-delete-sendEmail.png)

![Flow Builder select custom action](assets/flow-configuration-add-thenAction.png)

![Flow Builder select custom action](assets/flow-configuration-selectAction.png)

### 5. Confirm the Custom Flow-Action Setting

When you select the custom Flow Action, a configuration modal appears. In our case, this is just the dummy option we added earlier (`urgentDispatch`). Choose any value and click **Save Action**.

![Custom Flow Action configuration](assets/flow-configuration-customSelect.png)

Finally, click the blue **Save** button in the top right corner to persist the new Flow Sequence.

![Flow Builder save button](assets/flow-configuration-save.png)

## Code-Along (end)

To see what the final result of this learning unit should look like, run the following command:

```bash
git checkout tags/setup_flow_action--end
```

<Callout title="Removing Working Changes" type="warning">

If you have local changes, you will need to run `git reset --hard HEAD` in the App directory. Be mindful that this command will destroy any local changes!

</Callout>

## Summary

In this learning unit, you learned how to create custom Flow Actions that merchants can use in the Shopware Flow Builder. You now understand:

- **Flow Actions vs Webhooks**: Flow Actions are merchant-configurable, Webhooks are developer-defined
- **How to define a Flow Action**: Using the `flow.xml` file with metadata, headers, parameters, and configuration
- **ACL permissions**: What they are, why they matter for security and compliance, and how to configure them
- **Flow Builder integration**: How merchants can select and configure your Flow Action in the Admin panel

These concepts form the foundation for building merchant-friendly, customizable workflows. In the next learning unit, you will implement the **App Server controller** that processes Flow Action requests and interacts with Shopware's Admin API.
