---
title: "Create a flow definition"
slug: "create-a-flow-definition"
abstract: "Describes how to create a flow definition using the Sitecore Personalize Flow definition REST API."
---
# Create a flow definition

`POST /v3/flowDefinitions`

Creates a flow definition in Sitecore Personalize.

You can use this endpoint to create web, interactive API, or triggered experiments and experiences.

A flow definition specifies the experiment or experience configuration, including its type, subtype, variants, traffic allocation, schedule, and business process.

For experiments, you can configure multiple variants and specify how traffic is distributed between them. Use audience conditions in `filters` to determine which guests are eligible for the flow.

## Request body

Provide the following attributes in the request body:

| Attribute | Type | Required | Description | Example |
| --- | --- | --- | --- | --- |
| `name` | string | Yes | The name of the flow definition. | `"Alert bar"` |
| `friendlyId` | string | Yes | The unique ID of the flow definition. Use lowercase alphanumeric characters and underscores. | `"alert_bar_1"` |
| `type` | string enum | Yes | The flow type: `INTERACTIVE_WEB_FLOW`, `INTERACTIVE_API_FLOW`, or `TRIGGERED_V3`. | `"INTERACTIVE_API_FLOW"` |
| `subtype` | string enum | Yes | Whether the flow is an `EXPERIMENT` or an `EXPERIENCE`. | `"EXPERIMENT"` |
| `status` | string enum | Yes | Set to `DRAFT` when creating a flow. | `"DRAFT"` |
| `channels` | array of strings | Yes | The touchpoints where guests interact with your brand. | `["WEB"]` |
| `businessProcess` | string | Yes | Set to `interactive_v1` for interactive flows or `triggered_v1` for triggered flows. | `"interactive_v1"` |
| `filters` | object | No | Sets the conditions that must pass before the experiment or experience can run. | [Filters and example](https://doc.sitecore.com/personalize/en/developers/api/rest-apis/flow-definition-rest-api/create-a-flow-definition.html#the-filters-object) |
| `variants` | array of objects | Yes | Versions of the experiment or experience. Set this value to an empty array (`[]`) when the flow has no variants yet. Otherwise, include one object for each variant. | [Variants and example](https://doc.sitecore.com/personalize/en/developers/api/rest-apis/flow-definition-rest-api/create-a-flow-definition.html#the-variants-array) |
| `traffic` | object | Yes | Defines traffic allocation and distribution between variants. | [Traffic and examples](https://doc.sitecore.com/personalize/en/developers/api/rest-apis/flow-definition-rest-api/create-a-flow-definition.html#the-traffic-object) |
| `schedule` | object | Yes | Defines when the experiment or experience can run. | [Schedule and example](https://doc.sitecore.com/personalize/en/developers/api/rest-apis/flow-definition-rest-api/create-a-flow-definition.html#the-schedule-object) |
| `sampleSizeConfig` | object | Yes | Defines the sample size parameters. The create request fails when this object is null. | [Sample size configuration and example](https://doc.sitecore.com/personalize/en/developers/api/rest-apis/flow-definition-rest-api/create-a-flow-definition.html#the-samplesizeconfig-object) |

For a complete payload, see [Example: Create an experiment with audience filters](https://doc.sitecore.com/personalize/en/developers/api/rest-apis/flow-definition-rest-api/create-a-flow-definition.html#example-create-an-experiment-with-audience-filters).

## The `traffic` object

The `traffic` object defines traffic allocation and distribution between variants.

| Attribute | Type | Description | Example |
| --- | --- | --- | --- |
| `type` | string enum | The traffic allocation type. Set this to `simpleTraffic` or `advancedTraffic`. | `"simpleTraffic"` |
| `weightingAlgorithm` | string enum | The algorithm used to determine variant weights. | `"USER_DEFINED"` |
| `coupled` | boolean | Whether the experiment is coupled to other experiments. | `false` |
| `allocation` | integer | The percentage of guests exposed to the experiment. Minimum `0`, maximum `100`. For an experience, set this to `100`. | `100` |
| `splits` | array of objects | Defines traffic distribution between variants. For `simpleTraffic`, each object specifies a variant reference and percentage. For `advancedTraffic`, each object specifies a variant reference and bucket range. | See below |

### Example: Simple traffic allocation

This example uses `simpleTraffic` to expose 60 percent of guests to one variant and 40 percent to another:

```json
{
  "traffic": {
    "type": "simpleTraffic",
    "weightingAlgorithm": "USER_DEFINED",
    "splits": [
      {
        "ref": "71206a12-b1b0-4baa-93ea-a0752a2762b0",
        "split": 60
      },
      {
        "ref": "ffe19d2a-b531-468d-a155-fedf757208e5",
        "split": 40
      }
    ]
  }
}
```

### Example: Advanced traffic allocation

This example uses `advancedTraffic` for an experiment. Guests in buckets 1 to 11 will not be exposed to the experiment. Guests in buckets 12 to 55 will be exposed to one variant, while guests in buckets 56 to 120 will be exposed to another variant.

```json
{
  "traffic": {
    "type": "advancedTraffic",
    "weightingAlgorithm": "USER_DEFINED",
    "modifiedAt": "2026-07-21T16:09:54.583Z",
    "allocationLow": 12,
    "allocationHigh": 120,
    "splits": [
      {
        "ref": "3e0c4419-5679-47e8-9d95-7f34b074af4b",
        "lowSplit": 12,
        "highSplit": 55
      },
      {
        "ref": "61705a82-a5d2-4a0f-920f-2c0990897b39",
        "lowSplit": 56,
        "highSplit": 120
      }
    ]
  }
}
```

## The `filters` object

The optional `filters` object sets the conditions that must pass before an experiment or experience can run. It can contain condition groups and a saved audience in `targetGroup`.

| Attribute | Type | Description | Example(s) |
| --- | --- | --- | --- |
| `conditionGroups` optional | array of objects | Groups of filter conditions evaluated together before the experiment or experience can run. | See the following example. |
| `targetGroup` optional | object | The saved audience that the guest must belong to. | See the following example. |

Personalize sets `renderedExpression` when it publishes the experience. Leave this attribute out of the create request.

Each object in `conditionGroups`:

| Attribute | Type | Description | Example(s) |
| --- | --- | --- | --- |
| `conditions` | array of objects | The conditions in this group. | See the following example. |
| `unionType` optional | string enum | How this group combines with the other groups. | `"AND"` or `"OR"` |

Each object in `conditions`:

| Attribute | Type | Description | Example(s) |
| --- | --- | --- | --- |
| `templateFriendlyId` | string | The friendly ID of the audience template that defines the condition. | `"country"` |
| `templateRevision` | integer | The revision of the audience template that defines the condition. | `5` |
| `params` | object | Parameter values passed to the audience template. Each value is a string. | `{ "is": "is", "country(s)": "DK" }` |
| `source` optional | string | The data source to evaluate. | `"CDP"` |
| `field` optional | string | The field in the data source to evaluate. | `"email"` |
| `operator` optional | string | The comparison to apply to the field. | `"NOT_NULL"` |
| `value` optional | string, number, boolean, array, or null | The value to compare with the field. | `"gold"` |
| `mapKey` optional | string | The key to read when the field is a map. | `"utm_source"` |
| `unit` optional | string | The time unit for a time-based operator. | `"DAYS"` |
| `scope` optional | string | The count scope for a nested array. | `"total"` or `"session"` |
| `unionType` optional | string enum | How this condition combines with the other conditions in the group. | `"AND"` or `"OR"` |

The `targetGroup` object:

| Attribute | Type | Description | Example(s) |
| --- | --- | --- | --- |
| `ref` | string (UUID) | The reference of the saved audience. | `"b7e3f1d0-9a2c-4f8e-b5d1-3c6e7a0d2f4b"` |
| `generatedCode` optional | string | JavaScript that evaluates the audience. Personalize generates this value. Leave it out of the create request. | `"function () { return true; }"` |

### Example: Country and operating system filters

To target guests in Denmark who use Windows, add two condition groups to `filters.conditionGroups`. Set `unionType` to `"AND"` on the second group so that both conditions must match:

- For the `country` template, set `is` to `"is"` and `country(s)` to `"DK"`.
- For the `operating_system` template, set `is` to `"is"` and `operating system(s)` to `"Windows"`.

Windows is an operating system, not a device type.

Each condition requires both `templateFriendlyId` and `templateRevision`. This example uses country template revision `5` and operating system template revision `9`. Use the template revisions available in your environment.

Include the following fragment in the create request alongside the other required flow definition attributes:

```json
{
  "filters": {
    "conditionGroups": [
      {
        "conditions": [
          {
            "templateFriendlyId": "country",
            "templateRevision": 5,
            "params": {
              "is": "is",
              "country(s)": "DK"
            }
          }
        ]
      },
      {
        "unionType": "AND",
        "conditions": [
          {
            "templateFriendlyId": "operating_system",
            "templateRevision": 9,
            "params": {
              "is": "is",
              "operating system(s)": "Windows"
            }
          }
        ]
      }
    ]
  }
}
```

These filters apply to the entire experiment or experience, not to an individual variant. For an experiment, use `traffic.splits` to configure the traffic distribution between variants separately. For example, a 50/50 split distributes eligible traffic between the control and the other variant.

When you retrieve the flow definition, each condition can include `templateFriendlyId`, `templateRevision`, and `expression`. In the Denmark and Windows example, the country expression checks `request.params.geo.country`, falling back to geolocation data in open web sessions when the request country is unavailable. The operating system expression checks the request's `User-Agent` header. The `transpiledVariants` array contains the combined condition expression in a `conditionsTask` for each variant.

For template-based filters such as these, provide `templateFriendlyId`, `templateRevision`, and `params` in the create request. You do not need to copy the condition's `expression` or the `transpiledVariants` array from a retrieved flow. Personalize resolves the template expressions and generates the transpiled variants.

## The `variants` array

The `variants` array contains one object for each version of the experiment or experience. When the array contains variants, include at least one control variant and set its `isControl` property to `true`. Each variant requires a `name` and `tasks`.

| Attribute | Type | Description | Example(s) |
| --- | --- | --- | --- |
| `name` | string | The name of the variant. | `"Control"` |
| `tasks` | array of objects | The actions to run when this variant is served. | See below |
| `ref` optional | string (UUID) | The reference of the variant. Use the same value in the matching traffic split's `ref`. | `"71206a12-b1b0-4baa-93ea-a0752a2762b0"` |
| `isControl` optional | boolean | Whether this is the control variant. Set this to `true` for one variant in the array. | `true` |
| `previewUrl` optional | string | The URL used to preview the variant. | `"https://www.example.com/preview"` |
| `assets` optional | object | The CSS, HTML, and JavaScript for the variant. | See below |
| `templateVariables` optional | object | String values that override template variables for this variant. | `{ "headline": "Welcome" }` |
| `description` optional | string | A description of the variant. | `"Control variant"` |
| `templateRef` optional | string (UUID) | The reference of the template used to render the variant. | `"a1b2c3d4-e5f6-7890-abcd-ef1234567890"` |
| `render` optional | boolean | Whether to render the variant on the server when it is served. | `true` |

Each attribute in the `assets` object is optional:

| Attribute | Type | Description | Example(s) |
| --- | --- | --- | --- |
| `css` optional | string | The CSS for the variant. | `".alert { color: #000; }"` |
| `html` optional | string | The HTML for the variant. | `"<div class=\"alert\">Hello</div>"` |
| `js` optional | string | The JavaScript for the variant. | `"insertHTMLAfter('body');"` |

Each object in `tasks`:

| Attribute | Type | Description | Example(s) |
| --- | --- | --- | --- |
| `implementation` | string | The task to run. | `"templateRenderTask"` or `"conditionsTask"` |
| `input` | object | The task parameters. Set `inputType` to the matching input type. | See below |

For `inputType: "templateRenderTaskInput"`, use the following attributes:

| Attribute | Type | Description | Example(s) |
| --- | --- | --- | --- |
| `inputType` | string | The input type for the task. Set this to `"templateRenderTaskInput"`. | `"templateRenderTaskInput"` |
| `type` | string | The content type of the template. | `"application/json"` |
| `template` | string | The template to render. | `"{ \"message\": \"Hello\" }"` |

For `inputType: "conditionsTaskInput"`, use the following attribute:

| Attribute | Type | Description | Example(s) |
| --- | --- | --- | --- |
| `rules` | array of objects | The rules that determine whether the variant runs. | See below |

Each object in `rules`:

| Attribute | Type | Description | Example(s) |
| --- | --- | --- | --- |
| `id` | string | The identifier of the rule. | `"scriptCondition"` |
| `ruleData` | object | The data used to evaluate the rule. | See below |
| `friendlyId` optional | string | The friendly ID of the rule. Use lowercase letters, digits, and underscores. | `"guest_has_email"` |
| `name` optional | string | The display name of the rule. | `"Guest has email"` |
| `description` optional | string | A description of the rule. | `"Matches guests who have an email address."` |

The `ruleData` object:

| Attribute | Type | Description | Example(s) |
| --- | --- | --- | --- |
| `expression` | string | The expression or value to evaluate. | `"guest.email"` |
| `field` optional | string | The guest profile field to evaluate. | `"orders.totalValue"` |
| `operator` optional | string | The comparison between the field and the expression. | `"GREATER_THAN"` |

For `inputType: "webhookTaskInput"`, set `connectionRef` to the UUID of the connection. Personalize resolves the `connection` object when it publishes the experience, so leave `connection` out of the create request.

### Example: A control variant

This fragment defines the control variant used in the full experiment example. Use the same `ref` in the corresponding `traffic.splits` object.

```json
{
  "variants": [
    {
      "ref": "e8c92a61-740f-4d35-a19b-3f062b85c947",
      "name": "Control",
      "isControl": true,
      "tasks": [
        {
          "implementation": "templateRenderTask",
          "input": {
            "inputType": "templateRenderTaskInput",
            "type": "application/json",
            "template": "{ \"message\": \"Hello\" }"
          }
        }
      ]
    }
  ]
}
```

## The `schedule` object

The `schedule` object defines when the experiment or experience can run.

| Attribute | Type | Description | Example(s) |
| --- | --- | --- | --- |
| `type` | string enum | The type of the flow schedule.<br><br>Set this value to `"simpleSchedule"`. | `"simpleSchedule"` |
| `startDate` | string ([ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)) | The earliest possible time the flow can run. | `2026-07-04T11:46:41.810Z` |
| `endDate`<br><br>optional | string ([ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)) | The last possible time the flow can run. | `2026-07-22T12:00:00.810Z` |

### Example: A start date

This fragment sets the earliest time the experiment can run:

```json
{
  "schedule": {
    "type": "simpleSchedule",
    "startDate": "2026-10-29T00:00:00.000Z"
  }
}
```

## The `sampleSizeConfig` object

The `sampleSizeConfig` object defines the sample size parameters for the experiment.

| Attribute | Type | Description | Example(s) |
| --- | --- | --- | --- |
| `baseValue` | number | The anticipated conversion goal value of the primary goal.<br><br>The default is `0.02`. | `0.02` |
| `minimumDetectableDifference` | number | The minimum conversion goal difference to detect relative to the base value.<br><br>The default is `0.2`. | `0.2` |
| `confidenceLevel` | number | The required confidence level before the test is considered complete.<br><br>This value represents the confidence your organization has that if the null hypothesis is true, the measured difference is not due to random fluctuations.<br><br>The default is `0.95`. | `0.95` |

### Example: Sample size configuration

This fragment uses the default sample size parameters:

```json
{
  "sampleSizeConfig": {
    "baseValue": 0.02,
    "minimumDetectableDifference": 0.2,
    "confidenceLevel": 0.95
  }
}
```

## Example: Create an experiment with audience filters

The following request creates a draft web experiment for guests in Denmark who use Windows. Eligible traffic is split equally between the control and Variant B.

In the response, the `ref` key contains the flow definition reference. Use it to [retrieve](https://doc.sitecore.com/personalize/en/developers/api/rest-apis/flow-definition-rest-api/retrieve-a-flow-definition.html "Retrieve a flow definition") or [update](https://doc.sitecore.com/personalize/en/developers/api/rest-apis/flow-definition-rest-api/update-a-flow-definition.html "Update a flow definition") the flow definition.

```curl
curl -X POST '<baseURL>/v3/flowDefinitions' \
-H 'Authorization: Bearer <accessToken>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
--data-raw '
{
  "name": "Denmark Windows variant test 2",
  "friendlyId": "denmark_windows_variant_test_2",
  "type": "INTERACTIVE_WEB_FLOW",
  "subtype": "EXPERIMENT",
  "status": "DRAFT",
  "channels": [
    "WEB"
  ],
  "businessProcess": "interactive_v1",
  "filters": {
    "conditionGroups": [
      {
        "conditions": [
          {
            "templateFriendlyId": "country",
            "templateRevision": 5,
            "params": {
              "is": "is",
              "country(s)": "DK"
            }
          }
        ]
      },
      {
        "unionType": "AND",
        "conditions": [
          {
            "templateFriendlyId": "operating_system",
            "templateRevision": 9,
            "params": {
              "is": "is",
              "operating system(s)": "Windows"
            }
          }
        ]
      }
    ]
  },
  "variants": [
    {
      "ref": "e8c92a61-740f-4d35-a19b-3f062b85c947",
      "name": "Control",
      "isControl": true,
      "tasks": [
        {
          "implementation": "templateRenderTask",
          "input": {
            "inputType": "templateRenderTaskInput",
            "type": "application/json",
            "template": "{ \"message\": \"Hello\" }"
          }
        }
      ]
    },
    {
      "ref": "72b1d0f9-c583-46ae-8d24-f917ac603be5",
      "name": "Variant B",
      "isControl": false,
      "tasks": [
        {
          "implementation": "templateRenderTask",
          "input": {
            "inputType": "templateRenderTaskInput",
            "type": "application/json",
            "template": "{ \"message\": \"Hej\" }"
          }
        }
      ]
    }
  ],
  "traffic": {
    "type": "simpleTraffic",
    "weightingAlgorithm": "USER_DEFINED",
    "coupled": false,
    "allocation": 100,
    "splits": [
      {
        "ref": "e8c92a61-740f-4d35-a19b-3f062b85c947",
        "split": 50
      },
      {
        "ref": "72b1d0f9-c583-46ae-8d24-f917ac603be5",
        "split": 50
      }
    ]
  },
  "schedule": {
    "type": "simpleSchedule",
    "startDate": "2026-10-29T00:00:00.000Z"
  },
  "sampleSizeConfig": {
    "baseValue": 0.02,
    "minimumDetectableDifference": 0.2,
    "confidenceLevel": 0.95
  }
}'
```
